LeetCode in Kotlin

2056. Number of Valid Move Combinations On Chessboard

Hard

There is an 8 x 8 chessboard containing n pieces (rooks, queens, or bishops). You are given a string array pieces of length n, where pieces[i] describes the type (rook, queen, or bishop) of the ith piece. In addition, you are given a 2D integer array positions also of length n, where positions[i] = [ri, ci] indicates that the ith piece is currently at the 1-based coordinate (ri, ci) on the chessboard.

When making a move for a piece, you choose a destination square that the piece will travel toward and stop on.

You must make a move for every piece on the board simultaneously. A move combination consists of all the moves performed on all the given pieces. Every second, each piece will instantaneously travel one square towards their destination if they are not already at it. All pieces start traveling at the 0th second. A move combination is invalid if, at a given time, two or more pieces occupy the same square.

Return the number of valid move combinations.

Notes:

Example 1:

Input: pieces = [“rook”], positions = [[1,1]]

Output: 15

Explanation: The image above shows the possible squares the piece can move to.

Example 2:

Input: pieces = [“queen”], positions = [[1,1]]

Output: 22

Explanation: The image above shows the possible squares the piece can move to.

Example 3:

Input: pieces = [“bishop”], positions = [[4,3]]

Output: 12

Explanation: The image above shows the possible squares the piece can move to.

Constraints:

Solution

class Solution {
    // 0: rook, queen, bishop
    private val dirs = arrayOf(
        arrayOf(intArrayOf(-1, 0), intArrayOf(1, 0), intArrayOf(0, -1), intArrayOf(0, 1)),
        arrayOf(
            intArrayOf(-1, 0),
            intArrayOf(1, 0),
            intArrayOf(0, -1),
            intArrayOf(0, 1),
            intArrayOf(1, 1),
            intArrayOf(-1, -1),
            intArrayOf(-1, 1),
            intArrayOf(1, -1),
        ),
        arrayOf(intArrayOf(1, 1), intArrayOf(-1, -1), intArrayOf(-1, 1), intArrayOf(1, -1)),
    )

    fun countCombinations(pieces: Array<String?>, positions: Array<IntArray>): Int {
        val endPosition: Array<ArrayList<IntArray>?> = arrayOfNulls(pieces.size)
        for (i in pieces.indices) {
            endPosition[i] = ArrayList()
        }
        for (i in pieces.indices) {
            positions[i][0]--
            positions[i][1]--
            endPosition[i]!!.add(positions[i])
            var dirIndex = 0
            when (pieces[i]) {
                "rook" -> dirIndex = 0
                "queen" -> dirIndex = 1
                "bishop" -> dirIndex = 2
            }
            for (d in dirs[dirIndex]) {
                var r = positions[i][0]
                var c = positions[i][1]
                while (true) {
                    r += d[0]
                    c += d[1]
                    if (r < 0 || r >= 8 || c < 0 || c >= 8) {
                        break
                    }
                    endPosition[i]!!.add(intArrayOf(r, c))
                }
            }
        }
        return dfs(positions, endPosition, IntArray(pieces.size), 0)
    }

    private fun dfs(positions: Array<IntArray>, stop: Array<ArrayList<IntArray>?>, stopIndex: IntArray, cur: Int): Int {
        if (cur == stopIndex.size) {
            val p = Array(positions.size) { IntArray(2) }
            for (i in p.indices) {
                p[i] = intArrayOf(positions[i][0], positions[i][1])
            }
            return check(p, stop, stopIndex)
        }
        var res = 0
        for (i in stop[cur]!!.indices) {
            stopIndex[cur] = i
            res += dfs(positions, stop, stopIndex, cur + 1)
        }
        return res
    }

    private fun check(positions: Array<IntArray>, stop: Array<ArrayList<IntArray>?>, stopIndex: IntArray): Int {
        var keepGoing = true
        while (keepGoing) {
            keepGoing = false
            for (i in positions.indices) {
                var diff = stop[i]!![stopIndex[i]][0] - positions[i][0]
                if (diff > 0) {
                    keepGoing = true
                    positions[i][0]++
                } else if (diff < 0) {
                    keepGoing = true
                    positions[i][0]--
                }
                diff = stop[i]!![stopIndex[i]][1] - positions[i][1]
                if (diff > 0) {
                    keepGoing = true
                    positions[i][1]++
                } else if (diff < 0) {
                    keepGoing = true
                    positions[i][1]--
                }
            }
            val seen: MutableSet<Int> = HashSet()
            for (position in positions) {
                val key = position[0] * 100 + position[1]
                if (seen.contains(key)) {
                    return 0
                }
                seen.add(key)
            }
        }
        return 1
    }
}