use kish::{Board, Square, Team};
#[test]
fn white_pawn_promotes_on_row_8() {
let board = Board::from_squares(Team::White, &[Square::D7], &[Square::H8], &[]);
let actions = board.actions();
let promotion_action = actions
.iter()
.find(|a| a.delta.pieces[Team::White.to_usize()] & Square::D8.to_mask() != 0);
assert!(promotion_action.is_some(), "Should be able to move to D8");
let action = promotion_action.unwrap();
assert_ne!(
action.delta.kings & Square::D8.to_mask(),
0,
"Pawn should promote to king at D8"
);
}
#[test]
fn black_pawn_promotes_on_row_1() {
let board = Board::from_squares(Team::Black, &[Square::A8], &[Square::D2], &[]);
let actions = board.actions();
let promotion_action = actions
.iter()
.find(|a| a.delta.pieces[Team::Black.to_usize()] & Square::D1.to_mask() != 0);
assert!(promotion_action.is_some(), "Should be able to move to D1");
let action = promotion_action.unwrap();
assert_ne!(
action.delta.kings & Square::D1.to_mask(),
0,
"Black pawn should promote to king at D1"
);
}
#[test]
fn promotion_works_for_all_columns() {
for (src, dest) in [
(Square::A7, Square::A8),
(Square::D7, Square::D8),
(Square::H7, Square::H8),
] {
let board = Board::from_squares(Team::White, &[src], &[Square::A1], &[]);
let actions = board.actions();
let promotion = actions
.iter()
.find(|a| a.delta.pieces[Team::White.to_usize()] & dest.to_mask() != 0);
assert!(promotion.is_some(), "Should promote at {dest:?}");
assert_ne!(
promotion.unwrap().delta.kings & dest.to_mask(),
0,
"Should become king at {dest:?}"
);
}
}
#[test]
fn promoted_piece_has_king_movement() {
let board = Board::from_squares(
Team::White,
&[Square::D4],
&[Square::H8],
&[Square::D4], );
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() || dest == Square::D2.to_mask() || dest == Square::D1.to_mask()
});
assert!(backward_move, "King should be able to move backward");
}
#[test]
fn pawn_promotes_after_capture_on_promotion_row() {
let board = Board::from_squares(Team::White, &[Square::B6], &[Square::B7], &[]);
let actions = board.actions();
assert_eq!(actions.len(), 1);
let action = &actions[0];
assert_eq!(
action.delta.pieces[Team::Black.to_usize()],
Square::B7.to_mask()
);
assert_ne!(
action.delta.kings & Square::B8.to_mask(),
0,
"Pawn should promote at B8 after capture"
);
}
#[test]
fn pawn_continues_as_pawn_during_capture_sequence() {
let board = Board::from_squares(Team::White, &[Square::D6], &[Square::D7, Square::C8], &[]);
let actions = board.actions();
assert_eq!(actions.len(), 1, "Should have one 2-capture action");
let action = &actions[0];
assert_eq!(
action.delta.pieces[Team::Black.to_usize()],
Square::D7.to_mask() | Square::C8.to_mask(),
"Should capture both pieces"
);
let final_pos = action.delta.pieces[Team::White.to_usize()] & !Square::D6.to_mask();
assert_eq!(final_pos, Square::B8.to_mask(), "Should end on B8");
assert_ne!(
action.delta.kings & Square::B8.to_mask(),
0,
"Should promote at B8"
);
}
#[test]
fn sideways_capture_from_promotion_row_as_pawn() {
let board = Board::from_squares(Team::White, &[Square::D6], &[Square::D7, Square::E8], &[]);
let actions = board.actions();
let max_captures = actions
.iter()
.map(|a| a.delta.pieces[Team::Black.to_usize()].count_ones())
.max()
.unwrap_or(0);
assert_eq!(max_captures, 2, "Should capture both in sequence");
}
#[test]
fn promotion_only_at_turn_end() {
let board = Board::from_squares(Team::White, &[Square::D6], &[Square::D7, Square::C8], &[]);
let actions = board.actions();
let action = &actions[0];
assert_eq!(
action.delta.kings,
Square::B8.to_mask(),
"Promotion only at final position B8"
);
}
#[test]
fn black_pawn_promotes_during_capture() {
let board = Board::from_squares(
Team::Black,
&[Square::D2], &[Square::D3], &[],
);
let actions = board.actions();
assert_eq!(actions.len(), 1);
let action = &actions[0];
assert_eq!(
action.delta.pieces[Team::White.to_usize()],
Square::D2.to_mask(),
"Should capture D2"
);
assert_ne!(
action.delta.kings & Square::D1.to_mask(),
0,
"Black should promote at D1"
);
}