> ## Documentation Index
> Fetch the complete documentation index at: https://leetcode-py.wisl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> leetcode-py is a Python LeetCode practice environment generator with one CLI: lcpy. It is not a service or platform.
> Each problem is a directory under leetcode/ with README.md, solution.py, test_solution.py, helpers.py, and playground.ipynb. lcpy gen creates them from JSON templates bundled with the package.
> Examples are backed by tests; copy them verbatim.

# Cat and Mouse Python Solution with Tests

> Tested Python solution for LeetCode 913 with 22 pytest cases. Generate a practice environment with lcpy.

LeetCode 913, [Hard](/catalog/hard). Topics: [Math](/catalog/topics/math), [Dynamic Programming](/catalog/topics/dynamic-programming), [Graph Theory](/catalog/topics/graph-theory), [Topological Sort](/catalog/topics/topological-sort), [Memoization](/catalog/topics/memoization), Minimax, [Game Theory](/catalog/topics/game-theory), Zero-Sum Game. [View on LeetCode](https://leetcode.com/problems/cat-and-mouse/description/).

Generate this problem as a practice environment: tested reference solution, 22 [parametrized pytest cases](/practice/testing), and a playground notebook:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
lcpy gen -n 913   # by problem number
lcpy gen -s cat_and_mouse   # by problem name
```

## Problem

A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns.

The graph is given as follows: `graph[a]` is a list of all nodes `b` such that `ab` is an edge of the graph.

The mouse starts at node `1` and goes first, the cat starts at node `2` and goes second, and there is a hole at node `0`.

During each player's turn, they must travel along one edge of the graph that meets where they are. For example, if the Mouse is at node 1, it must travel to any node in `graph[1]`.

Additionally, it is not allowed for the Cat to travel to the Hole (node `0`).

Then, the game can end in three ways:

* If ever the Cat occupies the same node as the Mouse, the Cat wins.
* If ever the Mouse reaches the Hole, the Mouse wins.
* If ever a position is repeated (i.e., the players are in the same position as a previous turn, and it is the same player's turn to move), the game is a draw.

Given a `graph`, and assuming both players play optimally, return

* `1` if the mouse wins the game,
* `2` if the cat wins the game, or
* `0` if the game is a draw.

### Examples

![Example 1](https://assets.leetcode.com/uploads/2020/11/17/cat1.jpg)

```
Input: graph = [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
Output: 0
```

![Example 2](https://assets.leetcode.com/uploads/2020/11/17/cat2.jpg)

```
Input: graph = [[1,3],[0],[3],[0,2]]
Output: 1
```

### Constraints

* 3 \<= graph.length \<= 50
* 1 \<= graph\[i].length \< graph.length
* 0 \<= graph\[i]\[j] \< graph.length
* graph\[i]\[j] != i
* graph\[i] is unique.
* The mouse and the cat can always move.

## Solution

Reference implementation from [solution.py on GitHub](https://github.com/wislertt/leetcode-py/blob/main/leetcode/cat_and_mouse/solution.py), full suite in [test\_solution.py](https://github.com/wislertt/leetcode-py/blob/main/leetcode/cat_and_mouse/test_solution.py):

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from collections import deque


class Solution:
    # Time: O(n^3)
    # Space: O(n^2)
    def cat_mouse_game(self, graph: list[list[int]]) -> int:
        n = len(graph)
        draw, mouse_win, cat_win = 0, 1, 2
        # color[m][c][t]: result of the state with the mouse on m, the cat on c and
        # t picking the mover (0 mouse, 1 cat). Unresolved states stay draw.
        color = [[[draw] * 2 for _ in range(n)] for _ in range(n)]
        # degree[m][c][t]: how many of the mover's options are still undecided.
        degree = [[[0] * 2 for _ in range(n)] for _ in range(n)]
        for m in range(n):
            for c in range(n):
                degree[m][c][0] = len(graph[m])
                degree[m][c][1] = len(graph[c]) - (0 in graph[c])

        queue: deque[tuple[int, int, int]] = deque()
        for node in range(n):
            for turn in (0, 1):
                if node and color[node][node][turn] == draw:
                    color[node][node][turn] = cat_win
                    queue.append((node, node, turn))
                if color[0][node][turn] == draw:
                    color[0][node][turn] = mouse_win
                    queue.append((0, node, turn))

        while queue:
            m, c, turn = queue.popleft()
            outcome = color[m][c][turn]
            if turn == 0:
                # A resolved mouse-to-move state was reached by the cat moving.
                parents = [(m, prev_c, 1) for prev_c in graph[c] if prev_c != 0]
            else:
                # A resolved cat-to-move state was reached by the mouse moving.
                parents = [(prev_m, c, 0) for prev_m in graph[m]]
            for prev_m, prev_c, prev_turn in parents:
                if color[prev_m][prev_c][prev_turn] != draw:
                    continue
                if outcome == prev_turn + mouse_win:
                    # The mover can step into a state it already wins.
                    color[prev_m][prev_c][prev_turn] = outcome
                    queue.append((prev_m, prev_c, prev_turn))
                else:
                    degree[prev_m][prev_c][prev_turn] -= 1
                    if degree[prev_m][prev_c][prev_turn] == 0:
                        # Every option loses, so the state is lost for the mover.
                        color[prev_m][prev_c][prev_turn] = outcome
                        queue.append((prev_m, prev_c, prev_turn))
        return color[1][2][0]
```

## Complexity

| Time | Space |
| - | - |
| O(n^3) | O(n^2) |

## Tags


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.