use crate::types::*; use crate::bitboard::{Bitboard, EMPTY, pop_lsb}; use crate::position::Position; pub fn knight_mask(sq: Square) -> Bitboard { let b: Bitboard = 1 << (sq as u8); let mut mask = EMPTY; mask |= (b << 17) & !crate::bitboard::FILE_A; mask |= (b << 10) & !(crate::bitboard::FILE_A | 0x0202020202020202); mask |= (b >> 6) & !(crate::bitboard::FILE_A | 0x0202020202020202); mask |= (b >> 15) & !crate::bitboard::FILE_A; mask |= (b << 15) & !crate::bitboard::FILE_H; mask |= (b << 6) & !(crate::bitboard::FILE_H | 0x4040404040404040); mask |= (b >> 10) & !(crate::bitboard::FILE_H | 0x4040404040404040); mask |= (b >> 17) & !crate::bitboard::FILE_H; mask } pub fn king_mask(sq: Square) -> Bitboard { let b: Bitboard = 1 << (sq as u8); let mut mask = EMPTY; mask |= (b << 8) | (b >> 8); mask |= (b << 1) & !crate::bitboard::FILE_A; mask |= (b >> 7) & !crate::bitboard::FILE_A; mask |= (b << 9) & !crate::bitboard::FILE_A; mask |= (b >> 1) & !crate::bitboard::FILE_H; mask |= (b >> 9) & !crate::bitboard::FILE_H; mask |= (b << 7) & !crate::bitboard::FILE_H; mask } pub fn pawn_attack_mask(sq: Square, side: Color) -> Bitboard { let b: Bitboard = 1 << (sq as u8); let mut mask = EMPTY; if side == Color::White { mask |= (b << 7) & !crate::bitboard::FILE_H; mask |= (b << 9) & !crate::bitboard::FILE_A; } else { mask |= (b >> 9) & !crate::bitboard::FILE_H; mask |= (b >> 7) & !crate::bitboard::FILE_A; } mask } pub fn sliding_attacks(sq: Square, occ: Bitboard, diagonal: bool) -> Bitboard { let mut attacks = EMPTY; let r = (sq as u8) / 8; let f = (sq as u8) % 8; let dirs: &[(i8, i8)] = if diagonal { &[(1, 1), (1, -1), (-1, 1), (-1, -1)] } else { &[(1, 0), (-1, 0), (0, 1), (0, -1)] }; for &(dr, df) in dirs { let mut nr = r as i8 + dr; let mut nf = f as i8 + df; while nr >= 0 && nr < 8 && nf >= 0 && nf < 8 { let n_sq = nr * 8 + nf; attacks |= 1 << n_sq; if (occ & (1 << n_sq)) != 0 { break; } nr += dr; nf += df; } } attacks } pub fn generate_moves(pos: &Position, list: &mut Vec) { let us = pos.side_to_move; let occ = pos.colors[0] | pos.colors[1]; let target = !pos.colors[us as usize]; let mut knights = pos.pieces[PieceType::Knight as usize] & pos.colors[us as usize]; while knights != EMPTY { let from_sq = pop_lsb(&mut knights); let mut attacks = knight_mask(Square::from_u8(from_sq)) & target; while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } let mut king = pos.pieces[PieceType::King as usize] & pos.colors[us as usize]; if king != EMPTY { let from_sq = pop_lsb(&mut king); let mut attacks = king_mask(Square::from_u8(from_sq)) & target; while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } let mut sliders = (pos.pieces[PieceType::Bishop as usize] | pos.pieces[PieceType::Queen as usize]) & pos.colors[us as usize]; while sliders != EMPTY { let from_sq = pop_lsb(&mut sliders); let mut attacks = sliding_attacks(Square::from_u8(from_sq), occ, true) & target; while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } let mut straights = (pos.pieces[PieceType::Rook as usize] | pos.pieces[PieceType::Queen as usize]) & pos.colors[us as usize]; while straights != EMPTY { let from_sq = pop_lsb(&mut straights); let mut attacks = sliding_attacks(Square::from_u8(from_sq), occ, false) & target; while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } let mut pawns = pos.pieces[PieceType::Pawn as usize] & pos.colors[us as usize]; while pawns != EMPTY { let from_sq = pop_lsb(&mut pawns); let f_rank = from_sq / 8; if us == Color::White { let single_push = from_sq + 8; if (occ & (1 << single_push)) == 0 { if f_rank == 6 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Queen)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Rook)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Bishop)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Knight)); } else { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::None)); let double_push = from_sq + 16; if f_rank == 1 && (occ & (1 << double_push)) == 0 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(double_push), PieceType::None)); } } } let mut attacks = pawn_attack_mask(Square::from_u8(from_sq), Color::White) & pos.colors[Color::Black as usize]; if pos.ep_square != Square::None && (pawn_attack_mask(Square::from_u8(from_sq), Color::White) & (1 << (pos.ep_square as u8))) != 0 { attacks |= 1 << (pos.ep_square as u8); } while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); if f_rank == 6 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::Queen)); } else { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } } else { let single_push = from_sq - 8; if (occ & (1 << single_push)) == 0 { if f_rank == 1 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Queen)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Rook)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Bishop)); list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::Knight)); } else { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(single_push), PieceType::None)); let double_push = from_sq - 16; if f_rank == 6 && (occ & (1 << double_push)) == 0 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(double_push), PieceType::None)); } } } let mut attacks = pawn_attack_mask(Square::from_u8(from_sq), Color::Black) & pos.colors[Color::White as usize]; if pos.ep_square != Square::None && (pawn_attack_mask(Square::from_u8(from_sq), Color::Black) & (1 << (pos.ep_square as u8))) != 0 { attacks |= 1 << (pos.ep_square as u8); } while attacks != EMPTY { let to_sq = pop_lsb(&mut attacks); if f_rank == 1 { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::Queen)); } else { list.push(Move::new(Square::from_u8(from_sq), Square::from_u8(to_sq), PieceType::None)); } } } } }