rules: fix castling issue

This commit is contained in:
dece 2020-06-06 01:27:19 +02:00
parent 659094b269
commit 25b1164644

View file

@ -39,8 +39,7 @@ pub const CASTLING_BL_MASK: u8 = 0b00001100;
pub const CASTLING_K_MASK: u8 = 0b00000101; pub const CASTLING_K_MASK: u8 = 0b00000101;
pub const CASTLING_Q_MASK: u8 = 0b00001010; pub const CASTLING_Q_MASK: u8 = 0b00001010;
pub const CASTLING_MASK: u8 = 0b00001111; pub const CASTLING_MASK: u8 = 0b00001111;
pub const CASTLING_SIDES: [(std::ops::RangeInclusive<i8>, u8); 2] = pub const CASTLING_SIDES: [(i8, u8); 2] = [(5i8, CASTLING_K_MASK), (3i8, CASTLING_Q_MASK)];
[(5..=6, CASTLING_K_MASK), (2..=3, CASTLING_Q_MASK)];
pub const START_WH_K_POS: Pos = pos("e1"); pub const START_WH_K_POS: Pos = pos("e1");
pub const START_BL_K_POS: Pos = pos("e8"); pub const START_BL_K_POS: Pos = pos("e8");
@ -404,27 +403,19 @@ fn get_king_moves(
(7, CASTLING_BL_MASK) (7, CASTLING_BL_MASK)
}; };
// Check for castling if the king is on its castling rank (R1) and is not in check (R4). // Check for castling if the king is on its castling rank (R1)
// and is not in check (R4)
if if
*r == castling_rank && // Part of R1 for the king. *r == castling_rank &&
!is_attacked(board, game_state, at) // R4 !is_attacked(board, game_state, at)
{ {
// Check for both castling sides. // Check for both castling sides.
for (path, castling_side_mask) in CASTLING_SIDES.iter() { for (through_f, castling_side_mask) in CASTLING_SIDES.iter() {
// Check for castling availability for this color and side. // Check for castling availability for this color and side.
if ((game_state.castling & castling_color_mask) | castling_side_mask) != 0 { if (game_state.castling & castling_color_mask & castling_side_mask) != 0 {
// R3, R5, R6: check that files on the way are empty and not attacked. // R3, R5, R6: check that files on the way are empty and not attacked.
let mut clear_path = true; let p = (*through_f, castling_rank);
for through_f in path.to_owned() { if is_empty(board, &p) && !is_illegal(board, game_state, &(*at, p, None)) {
let p = (through_f, castling_rank);
if !is_empty(board, &p) || is_illegal(board, game_state, &(*at, p, None)) {
clear_path = false;
break;
}
}
// If the path is clear, the castling can be done.
if clear_path {
let castle = CASTLING_K_MASK & castling_color_mask; let castle = CASTLING_K_MASK & castling_color_mask;
let m = get_castle_move(castle); let m = get_castle_move(castle);
if can_register(commit, board, game_state, &m) { if can_register(commit, board, game_state, &m) {
@ -512,10 +503,10 @@ mod tests {
#[test] #[test]
fn test_get_castle() { fn test_get_castle() {
assert_eq!(get_castle(&parse_move("e1a1")), Some(CASTLING_WH_Q)); assert_eq!(get_castle(&parse_move("e1c1")), Some(CASTLING_WH_Q));
assert_eq!(get_castle(&parse_move("e1h1")), Some(CASTLING_WH_K)); assert_eq!(get_castle(&parse_move("e1g1")), Some(CASTLING_WH_K));
assert_eq!(get_castle(&parse_move("e8a8")), Some(CASTLING_BL_Q)); assert_eq!(get_castle(&parse_move("e8c8")), Some(CASTLING_BL_Q));
assert_eq!(get_castle(&parse_move("e8h8")), Some(CASTLING_BL_K)); assert_eq!(get_castle(&parse_move("e8g8")), Some(CASTLING_BL_K));
assert_eq!(get_castle(&parse_move("d2d4")), None); assert_eq!(get_castle(&parse_move("d2d4")), None);
} }
@ -555,14 +546,14 @@ mod tests {
clear_square(&mut b, &pos("f8")); clear_square(&mut b, &pos("f8"));
clear_square(&mut b, &pos("g8")); clear_square(&mut b, &pos("g8"));
// White queen-side castling. // White queen-side castling.
apply_move_to(&mut b, &mut gs, &parse_move("e1a1")); apply_move_to(&mut b, &mut gs, &parse_move("e1c1"));
assert!(is_piece(get_square(&b, &pos("c1")), SQ_WH_K)); assert!(is_piece(get_square(&b, &pos("c1")), SQ_WH_K));
assert!(is_piece(get_square(&b, &pos("d1")), SQ_WH_R)); assert!(is_piece(get_square(&b, &pos("d1")), SQ_WH_R));
assert!(is_empty(&b, &pos("a1"))); assert!(is_empty(&b, &pos("a1")));
assert!(is_empty(&b, &pos("e1"))); assert!(is_empty(&b, &pos("e1")));
assert_eq!(gs.castling, CASTLING_BL_MASK); assert_eq!(gs.castling, CASTLING_BL_MASK);
// Black king-side castling. // Black king-side castling.
apply_move_to(&mut b, &mut gs, &parse_move("e8h8")); apply_move_to(&mut b, &mut gs, &parse_move("e8g8"));
assert!(is_piece(get_square(&b, &pos("g8")), SQ_BL_K)); assert!(is_piece(get_square(&b, &pos("g8")), SQ_BL_K));
assert!(is_piece(get_square(&b, &pos("f8")), SQ_BL_R)); assert!(is_piece(get_square(&b, &pos("f8")), SQ_BL_R));
assert!(is_empty(&b, &pos("h8"))); assert!(is_empty(&b, &pos("h8")));
@ -713,7 +704,6 @@ mod tests {
#[test] #[test]
fn test_get_king_moves() { fn test_get_king_moves() {
let mut gs = GameState::new(); let mut gs = GameState::new();
return; // FIXME
// King can move 1 square in any direction. // King can move 1 square in any direction.
let mut b = new_empty(); let mut b = new_empty();
@ -740,14 +730,17 @@ mod tests {
#[test] #[test]
fn test_filter_illegal_moves() { fn test_filter_illegal_moves() {
let mut b = new_empty(); let mut b = new_empty();
let gs = GameState::new(); let mut gs = GameState::new();
// Place white's king on first rank. // Place white's king on first rank.
set_square(&mut b, &pos("e1"), SQ_WH_K); set_square(&mut b, &pos("e1"), SQ_WH_K);
// Place black rook in second rank: king can only move left or right. // Place black rook in second rank: king can only move left or right.
set_square(&mut b, &pos("h2"), SQ_BL_R); set_square(&mut b, &pos("h2"), SQ_BL_R);
// No castling available.
gs.castling = 0;
// 5 moves in absolute but only 2 are legal.
let all_wh_moves = get_piece_moves(&b, &pos("e1"), &gs, true); let all_wh_moves = get_piece_moves(&b, &pos("e1"), &gs, true);
assert_eq!(all_wh_moves.len(), 2); // 5 moves in absolute but only 2 are legal. assert_eq!(all_wh_moves.len(), 2);
} }
#[test] #[test]