Make code more readable with some abstraction
Approach\nAn ordinary BFS problem, but we can hide all those redundancy for dealing with state transition logic from the main routine.\n\n# Code\n\nnamespace de
# Approach\nAn ordinary BFS problem, but we can hide all those redundancy for dealing with state transition logic from the main routine.\n\n# Code\n```\nnamespace details {\n\n    struct Pos {\n        int x {};\n        int y {};\n        constexpr bool operator==(Pos rhs) const {\n            return x == rhs.x && y == rhs.y;\n        }\n    };\n\n    /*\n        class invariant: head is adjacent to tail\n    */\n    struct Snake {\n        Pos head {.x = 0, .y = 1};\n        Pos tail {.x = 0, .y = 0};\n        // note: all snake actions are unchecked for validity\n        Snake& move_right() {\n            ++head.y, ++tail.y;\n            return *this;\n        }\n        Snake& move_down() {\n            ++head.x, ++tail.x;\n            return *this;\n        }\n        Snake& rotate_clockwise() {\n            head.x = tail.x + 1, head.y = tail.y;\n            return *this;\n        }\n        Snake& rotate_anticloswise() {\n            head.x = tail.x, head.y = tail.y + 1;\n            return *this;\n        }\n        constexpr bool operator==(Snake const& rhs) const {\n            return head == rhs.head && tail == rhs.tail;\n        }\n    };\n}\n\ntemplate<>\nstruct std::hash<details::Snake> {\n    std::size_t operator()(details::Snake const& s) const {\n        return std::hash<int>{}(\n            (s.head.x ^ s.head.y) \n            | ((s.tail.x ^ s.tail.y) << 7)\n        );\n    }\n};\n\nclass Solution {\npublic:\n    int minimumMoves(vector<vector<int>>& grid) {\n        using namespace details;\n        std::queue<Snake> q;\n        q.emplace();\n        std::unordered_set<Snake> met {Snake{}};\n        \n        using snake_action = Snake& (Snake::*)();\n        constexpr snake_action actions[4] {\n            &Snake::move_down, &Snake::move_right, \n            &Snake::rotate_clockwise, &Snake::rotate_anticloswise\n        };\n\n        int n = grid.size();\n        auto valid_pos = [&](Pos p) {\n            return !(p.x < 0 || p.y < 0 || p.x >= n || p.y >= n) \n                && grid[p.x][p.y] == 0;\n        };\n        auto valid_move = [&](Snake s, snake_action f)->bool {\n            Snake t {s};\n            (t.*f)();\n            if (!valid_pos(t.head) || !valid_pos(t.tail)) return false;\n            if (f == &Snake::rotate_clockwise) {\n                Pos below_head {s.head.x+1, s.head.y}, \n                    below_tail {s.tail.x+1, s.tail.y};\n                return valid_pos(below_head) && valid_pos(below_tail);\n            } else if (f == &Snake::rotate_anticloswise) {\n                Pos right_head {s.head.x, s.head.y+1},\n                    right_tail {s.tail.x, s.tail.y+1};\n                return valid_pos(right_head) && valid_pos(right_tail);\n            }\n            return true;\n        };\n\n        Snake end {{n-1, n-1}, {n-1, n-2}};\n        for (int lv {}; !q.empty(); ++lv) {\n            int qsize = q.size();\n            while (qsize--) {\n                Snake curr = q.front(); q.pop();\n                for (snake_action act: actions) {\n                    if (!valid_move(curr, act)) continue;\n                    Snake next {curr};\n                    (next.*act)();\n                    if (next == end) return lv + 1;\n                    if (met.count(next)) continue;\n                    met.insert(next);\n                    q.push(next);\n                }\n            }\n        }\n        return -1;\n    }\n};\n```
['C++']