use kish::{Board, Square, Team};
const MASK_COL_H: u64 = 0x8080_8080_8080_8080;
#[test]
fn pawn_cannot_move_diagonally() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let diagonal_squares = [Square::C3, Square::C5, Square::E3, Square::E5];
for sq in &diagonal_squares {
let diag_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(!diag_move, "Pawn should NOT move diagonally to {sq:?}");
}
}
#[test]
fn king_cannot_move_diagonally() {
let board = Board::from_squares(
Team::White,
&[Square::D4],
&[Square::H8],
&[Square::D4], );
let actions = board.actions();
let diagonal_squares = [
Square::A1,
Square::B2,
Square::C3,
Square::E5,
Square::F6,
Square::G7,
Square::A7,
Square::B6,
Square::C5,
Square::E3,
Square::F2,
Square::G1,
];
for sq in &diagonal_squares {
let diag_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(!diag_move, "King should NOT move diagonally to {sq:?}");
}
}
#[test]
fn white_pawn_moves_forward() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let forward_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == Square::D5.to_mask()
});
assert!(
forward_move,
"White pawn should be able to move forward to D5"
);
}
#[test]
fn white_pawn_moves_left() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let left_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == Square::C4.to_mask()
});
assert!(left_move, "White pawn should be able to move left to C4");
}
#[test]
fn white_pawn_moves_right() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let right_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == Square::E4.to_mask()
});
assert!(right_move, "White pawn should be able to move right to E4");
}
#[test]
fn white_pawn_cannot_move_backward() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let backward_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == Square::D3.to_mask()
});
assert!(!backward_move, "White pawn should NOT move backward to D3");
}
#[test]
fn black_pawn_moves_forward() {
let board = Board::from_squares(Team::Black, &[Square::A1], &[Square::D5], &[]);
let actions = board.actions();
let forward_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::Black.to_usize()] & !Square::D5.to_mask();
dest == Square::D4.to_mask()
});
assert!(
forward_move,
"Black pawn should be able to move forward to D4"
);
}
#[test]
fn black_pawn_moves_left() {
let board = Board::from_squares(Team::Black, &[Square::A1], &[Square::D5], &[]);
let actions = board.actions();
let left_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::Black.to_usize()] & !Square::D5.to_mask();
dest == Square::C5.to_mask()
});
assert!(left_move, "Black pawn should be able to move left to C5");
}
#[test]
fn black_pawn_moves_right() {
let board = Board::from_squares(Team::Black, &[Square::A1], &[Square::D5], &[]);
let actions = board.actions();
let right_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::Black.to_usize()] & !Square::D5.to_mask();
dest == Square::E5.to_mask()
});
assert!(right_move, "Black pawn should be able to move right to E5");
}
#[test]
fn black_pawn_cannot_move_backward() {
let board = Board::from_squares(Team::Black, &[Square::A1], &[Square::D5], &[]);
let actions = board.actions();
let backward_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::Black.to_usize()] & !Square::D5.to_mask();
dest == Square::D6.to_mask()
});
assert!(!backward_move, "Black pawn should NOT move backward to D6");
}
#[test]
fn pawn_moves_exactly_one_square() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[]);
let actions = board.actions();
let two_square_moves = [Square::D6, Square::B4, Square::F4];
for sq in &two_square_moves {
let found = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(!found, "Pawn should NOT move 2 squares to {sq:?}");
}
}
#[test]
fn pawn_on_left_edge_limited_moves() {
let board = Board::from_squares(Team::White, &[Square::A4], &[Square::H8], &[]);
let actions = board.actions();
assert_eq!(actions.len(), 2, "Edge pawn should have 2 moves");
let left_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::A4.to_mask();
dest & MASK_COL_H != 0 });
assert!(!left_move, "Pawn should NOT move off the left edge");
}
#[test]
fn pawn_on_right_edge_limited_moves() {
let board = Board::from_squares(Team::White, &[Square::H4], &[Square::A8], &[]);
let actions = board.actions();
assert_eq!(actions.len(), 2, "Edge pawn should have 2 moves");
}
#[test]
fn king_moves_multiple_squares_in_one_direction() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
let far_move = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == Square::D8.to_mask()
});
assert!(far_move, "King should be able to move far to D8");
}
#[test]
fn king_moves_forward() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
for i in 5..=8 {
let sq = Square::try_from_u8(3 + (i - 1) * 8).unwrap(); let found = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(found, "King should reach {sq:?}");
}
}
#[test]
fn king_moves_backward() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
for i in 1..=3 {
let sq = Square::try_from_u8(3 + (i - 1) * 8).unwrap(); let found = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(found, "King should reach {sq:?}");
}
}
#[test]
fn king_moves_left() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
let left_squares = [Square::A4, Square::B4, Square::C4];
for sq in &left_squares {
let found = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(found, "King should reach {sq:?}");
}
}
#[test]
fn king_moves_right() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
let right_squares = [Square::E4, Square::F4, Square::G4, Square::H4];
for sq in &right_squares {
let found = actions.iter().any(|a| {
let dest = a.delta.pieces[Team::White.to_usize()] & !Square::D4.to_mask();
dest == sq.to_mask()
});
assert!(found, "King should reach {sq:?}");
}
}
#[test]
fn king_at_center_has_14_moves() {
let board = Board::from_squares(Team::White, &[Square::D4], &[Square::H8], &[Square::D4]);
let actions = board.actions();
assert_eq!(actions.len(), 14, "King at center should have 14 moves");
}
#[test]
fn king_blocked_by_friendly_piece() {
let board = Board::from_squares(
Team::White,
&[Square::D4, Square::D6],
&[Square::H8],
&[Square::D4],
);
let actions = board.actions();
let past_block = actions.iter().any(|a| {
let delta = a.delta.pieces[Team::White.to_usize()];
if delta & Square::D4.to_mask() != 0 {
let dest = delta & !Square::D4.to_mask();
dest == Square::D7.to_mask() || dest == Square::D8.to_mask()
} else {
false
}
});
assert!(!past_block, "King should NOT pass through friendly piece");
}
#[test]
fn king_blocked_by_hostile_for_moves() {
let _board = Board::from_squares(Team::White, &[Square::D4], &[Square::D6], &[Square::D4]);
}
#[test]
fn king_cannot_jump_without_capturing() {
let board = Board::from_squares(
Team::White,
&[Square::A4, Square::C4],
&[Square::H8],
&[Square::A4],
);
let actions = board.actions();
let past_friendly = actions.iter().any(|a| {
let delta = a.delta.pieces[Team::White.to_usize()];
if delta & Square::A4.to_mask() != 0 {
let dest = delta & !Square::A4.to_mask() & !Square::C4.to_mask();
dest & (Square::D4.to_mask()
| Square::E4.to_mask()
| Square::F4.to_mask()
| Square::G4.to_mask()
| Square::H4.to_mask())
!= 0
} else {
false
}
});
assert!(!past_friendly, "King should NOT jump over friendly piece");
}
#[test]
fn king_at_corner_has_14_moves() {
let board = Board::from_squares(Team::White, &[Square::A1], &[Square::H8], &[Square::A1]);
let actions = board.actions();
assert_eq!(actions.len(), 14, "Corner king should have 14 moves");
}
#[test]
fn black_king_moves_backward() {
let board = Board::from_squares(
Team::Black,
&[Square::A1], &[Square::D4],
&[Square::D4], );
let actions = board.actions();
let backward_moves: Vec<_> = actions
.iter()
.filter(|a| {
let dest = a.delta.pieces[Team::Black.to_usize()] & !Square::D4.to_mask();
dest == Square::D5.to_mask()
|| dest == Square::D6.to_mask()
|| dest == Square::D7.to_mask()
|| dest == Square::D8.to_mask()
})
.collect();
assert_eq!(
backward_moves.len(),
4,
"Black king should have 4 backward (up) moves"
);
}
#[test]
fn black_pawn_at_row_8_has_limited_moves() {
let board = Board::from_squares(Team::Black, &[Square::A1], &[Square::D8], &[]);
let actions = board.actions();
assert_eq!(actions.len(), 3, "Black pawn at D8 should have 3 moves");
}