#2056
Hard Algorithms Number of valid move combinations on chessboard
Array String Backtracking Simulation
48.8% acceptance
Feb 25, 2026
75
297
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.
A rook can only travel horizontally or vertically from (r, c) to the direction of (r+1, c), (r-1, c), (r, c+1), or (r, c-1).
A queen can only travel horizontally, vertically, or diagonally from (r, c) to the direction of (r+1, c), (r-1, c), (r, c+1), (r, c-1), (r+1, c+1), (r+1, c-1), (r-1, c+1), (r-1, c-1).
A bishop can only travel diagonally from (r, c) to the direction of (r+1, c+1), (r+1, c-1), (r-1, c+1), (r-1, c-1).
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.
Solution
Rust
Time O(n³)
Space O(n)
impl Solution {
pub fn count_combinations(pieces: Vec<String>, positions: Vec<Vec<i32>>) -> i32 {
let n = pieces.len();
fn dirs(piece: &str) -> Vec<(i32, i32)> {
let rook = vec![(0, 1), (0, -1), (1, 0), (-1, 0)];
let bishop = vec![(1, 1), (1, -1), (-1, 1), (-1, -1)];
match piece {
"rook" => rook,
"bishop" => bishop,
_ => rook.into_iter().chain(bishop).collect(),
}
}
// Each move: (dr, dc, max_steps) where 0,0,0 = stay
let all_moves: Vec<Vec<(i32, i32, i32)>> = (0..n).map(|i| {
let r = positions[i][0];
let c = positions[i][1];
let mut moves = vec![(0i32, 0i32, 0i32)];
for (dr, dc) in dirs(&pieces[i]) {
let mut steps = 0i32;
let (mut nr, mut nc) = (r + dr, c + dc);
while nr >= 1 && nr <= 8 && nc >= 1 && nc <= 8 {
steps += 1;
moves.push((dr, dc, steps));
nr += dr;
nc += dc;
}
}
moves
}).collect();
let is_valid = |combo: &[(i32, i32, i32)]| -> bool {
for t in 0i32..=7 {
let mut pos_t: Vec<(i32, i32)> = vec![];
for (idx, &(dr, dc, steps)) in combo.iter().enumerate() {
let r = positions[idx][0];
let c = positions[idx][1];
let ts = t.min(steps);
pos_t.push((r + ts * dr, c + ts * dc));
}
for a in 0..pos_t.len() {
for b in a + 1..pos_t.len() {
if pos_t[a] == pos_t[b] {
return false;
}
}
}
}
true
};
let sizes: Vec<usize> = all_moves.iter().map(|v| v.len()).collect();
let total: usize = sizes.iter().product();
let mut count = 0;
for idx in 0..total {
let mut combo = vec![];
let mut tmp = idx;
for i in 0..n {
combo.push(all_moves[i][tmp % sizes[i]]);
tmp /= sizes[i];
}
if is_valid(&combo) {
count += 1;
}
}
count
}
}