Hard
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.
'C'
(Cat),'M'
(Mouse).'.'
and can be walked on.'#'
and cannot be walked on.'F'
and can be walked on.'C'
, 'M'
, and 'F'
in grid
.Mouse and Cat play according to the following rules:
grid
.catJump, mouseJump
are the maximum lengths Cat and Mouse can jump at a time, respectively. Cat and Mouse can jump less than the maximum length.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
Constraints:
rows == grid.length
cols = grid[i].length
1 <= rows, cols <= 8
grid[i][j]
consist only of characters 'C'
, 'M'
, 'F'
, '.'
, and '#'
.'C'
, 'M'
, and 'F'
in grid
.1 <= catJump, mouseJump <= 8
@Suppress("NAME_SHADOWING")
class Solution {
private val graphs: Array<Array<List<Int>>> = arrayOf(arrayOf(), arrayOf())
private var foodPos = 0
private lateinit var memo: Array<Array<IntArray>>
fun canMouseWin(grid: Array<String>, catJump: Int, mouseJump: Int): Boolean {
val m = grid.size
val n = grid[0].length
var mousePos = 0
var catPos = 0
for (i in 0 until m) {
for (j in 0 until n) {
val c = grid[i][j]
if (c == 'F') {
foodPos = i * n + j
} else if (c == 'C') {
catPos = i * n + j
} else if (c == 'M') {
mousePos = i * n + j
}
}
}
graphs[0] = buildGraph(mouseJump, grid)
graphs[1] = buildGraph(catJump, grid)
memo = Array(m * n) { Array(m * n) { IntArray(2) } }
for (i in 0 until m) {
for (j in 0 until n) {
val c = grid[i][j]
if (c == '#' || c == 'F') {
continue
}
val catTurn = 1
dfs(i * n + j, foodPos, catTurn)
}
}
return memo[mousePos][catPos][MOUSE_TURN] < 0
}
private fun buildGraph(jump: Int, grid: Array<String>): Array<List<Int>> {
val dirs = arrayOf(intArrayOf(-1, 0), intArrayOf(1, 0), intArrayOf(0, 1), intArrayOf(0, -1))
val m = grid.size
val n = grid[0].length
val graph: Array<List<Int>> = Array(m * n) { mutableListOf() }
for (i in 0 until m) {
for (j in 0 until n) {
val list: MutableList<Int> = ArrayList()
graph[i * n + j] = list
if (grid[i][j] == '#') {
continue
}
list.add(i * n + j)
for (dir in dirs) {
for (step in 1..jump) {
val x = i + dir[0] * step
val y = j + dir[1] * step
if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '#') {
break
}
list.add(x * n + y)
}
}
}
}
return graph
}
private fun dfs(p1: Int, p2: Int, turn: Int) {
var turn = turn
if (p1 == p2) {
return
}
if ((if (turn == 0) p2 else p1) == foodPos) {
return
}
if (memo[p1][p2][turn] < 0) {
return
}
memo[p1][p2][turn] = -1
turn = turn xor 1
for (w in graphs[turn][p2]) {
if (turn == MOUSE_TURN || ++memo[w][p1][turn] == graphs[turn][w].size) {
dfs(w, p1, turn)
}
}
}
companion object {
private const val MOUSE_TURN = 0
}
}