Cat and Mouse II

A game is played by a cat and a mouse named Cat and Mouse.

The environment is represented by a grid of size rows x cols, where each element is a wall, floor, player (Cat, Mouse), or food.

Mouse and Cat play according to the following rules:

The game can end in 4 ways:

Given a rows x cols matrix grid and two integers catJump and mouseJump, return true if Mouse can win the game if both Cat and Mouse play optimally, otherwise return false.

 

Example 1:

Input: grid = ["####F","#C...","M...."], catJump = 1, mouseJump = 2
Output: true
Explanation: Cat cannot catch Mouse on its turn nor can it get the food before Mouse.

Example 2:

Input: grid = ["M.C...F"], catJump = 1, mouseJump = 4
Output: true

Example 3:

Input: grid = ["M.C...F"], catJump = 1, mouseJump = 3
Output: false

Example 4:

Input: grid = ["C...#","...#F","....#","M...."], catJump = 2, mouseJump = 5
Output: false

Example 5:

Input: grid = [".M...","..#..","#..#.","C#.#.","...#F"], catJump = 3, mouseJump = 1
Output: true

 

Constraints:


Solution:

bfs does not work because we can't guarantee optimized moves

DFS:

class Solution {
    int m, n;
    char[][] grid;
    int mJump, cJump;
    private final int[][] dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    
    public boolean canMouseWin(String[] gridString, int catJump, int mouseJump) {
        m = gridString.length;
        n = gridString[0].length();
        mJump = mouseJump;
        cJump = catJump;
        int ci = 0, cj = 0, mi = 0, mj = 0;

        grid = new char[m][n];
        
        for (int i = 0; i < m; i ++) {
            grid[i] = gridString[i].toCharArray();
            for (int j = 0; j < n; j ++) {
                char c = grid[i][j];
                if (c == 'M') {
                    mi = i;
                    mj = j;
                } else if (c == 'C') {
                    ci = i;
                    cj = j;
                }
            }
        }
        
        return dfs(0, mi, mj, ci, cj, new Boolean[71][m][n][m][n]);
    }
    
    private boolean dfs(int turn, int mi, int mj, int ci, int cj, Boolean[][][][][] dp) {
        if (mi == ci && mj == cj) return false;
        if (turn >= 70) return false;

        if (grid[mi][mj] == 'F') return true;
        if (grid[ci][cj] == 'F') return false;

        if (dp[turn][mi][mj][ci][cj] != null) return dp[turn][mi][mj][ci][cj];
        
        boolean win = false;
        if (turn % 2 == 0) {
            // mouse
            List<int[]> next = move(mi, mj, mJump);

            for(int[] n : next) {
                if (dfs(turn + 1, n[0], n[1], ci, cj, dp)) {
                    win = true;
                    break;
                }
            }
        } else {
            win = true;
            // cat
            List<int[]> next = move(ci, cj, cJump);

            for(int[] n : next) {
                if (!dfs(turn + 1, mi, mj, n[0], n[1], dp)) {
                    win = false;
                    break;
                }
            }
        }
        
        dp[turn][mi][mj][ci][cj] = win;
        return win;
    }
    
    private List<int[]> move(int i, int j, int jump) {
        List<int[]> res = new ArrayList<>();
        res.add(new int[]{i, j});
        for(int[] d : dirs) {
            for(int s = 1; s <= jump; s ++) {
                int ni = i + s * d[0];
                int nj = j + s * d[1];
                
                if (ni < 0 || ni >= m || nj < 0 || nj >= n) break;

                // cannot jump #
                if (grid[ni][nj] == '#') break;
                
                res.add(new int[]{ni, nj});
            }
        }
        
        return res;
    }
}