Python BFS - extended, with comments
Approach\n1) use a named tuple Part to keep track of tail and head\n2) use a named tuple Snake to keep track of the whole body\n3) calculate finish snake state\
**Approach**\n1) use a named tuple Part to keep track of tail and head\n2) use a named tuple Snake to keep track of the whole body\n3) calculate finish snake state\n4) enqueue initial snake state\n5) use BFS to traverse the board and get to the end in as few steps as possible\n\n**Complexity analysis**\ntime: O(V + E)\nspace: O(V + E)\n\n```python\nPart = collections.namedtuple(\'Part\', \'ri ci\')\nSnake = collections.namedtuple(\'Snake\', \'tail head\')\n\nclass Solution:\n    def minimumMoves(self, grid: List[List[int]]) -> int:\n        def moves(tail, head):\n            ok = 0 # it\'s unblocked\n            is_horiz = tail.ri == head.ri\n            \n            # currently horizontal\n            if is_horiz and head.ci < N-1 and grid[head.ri][head.ci+1] == ok:\n\t\t\t  # move right\n                yield Snake(Part(tail.ri, tail.ci+1), Part(head.ri, head.ci+1))\n                \n            #  currently horizontal, can move two ways\n            if is_horiz and head.ri + 1 < N and grid[head.ri+1][head.ci] == ok and grid[tail.ri+1][tail.ci] == ok:\n                # move down\n                yield Snake(Part(tail.ri+1, tail.ci), Part(head.ri+1, head.ci)) \n                # rotate clockwise\n                yield Snake(tail, Part(tail.ri+1, tail.ci))\n\n            # currently vertical, can move two ways\n            if not is_horiz and tail.ci + 1 < N and grid[tail.ri][tail.ci+1] == ok and grid[head.ri][head.ci+1] == ok:\n                # move right\n                yield Snake(Part(tail.ri, tail.ci+1), Part(head.ri, head.ci+1))\n                # rotate counter-clockwise\n                yield Snake(tail, Part(tail.ri, tail.ci+1))\n                \n            # currently vertical\n            if not is_horiz and head.ri+1 < N and grid[head.ri+1][head.ci] == ok:\n\t\t\t\t# move down\n                yield Snake(Part(tail.ri+1, tail.ci), Part(head.ri+1, head.ci))\n                    \n            \n            \n        N = len(grid)\n        visited = set()\n        finish = Snake(Part(N-1, N-2), Part(N-1, N-1))\n        snake = Snake(Part(0, 0), Part(0, 1))\n        item = (snake, 0) # keep track of snake position and number of moves so far\n        q = collections.deque([item])\n        \n        while q:\n            snake, count = q.popleft()\n            \n            for snake2 in moves(*snake):\n\t\t\t\t# early exit\n                if snake2 == finish:\n                    return count + 1\n                \n                if snake2 not in visited:\n                    visited.add(snake2)\n                    item = (snake2, count+1)\n                    q.append(item)\n                    \n        return -1\n```
[]