Reinitialize repository and add working move generation for all pieces
This commit is contained in:
commit
951a8bbec6
28 changed files with 3373 additions and 0 deletions
174
src/move.rs
Normal file
174
src/move.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
use std::slice;
|
||||
use std::fmt;
|
||||
use crate::square::Square;
|
||||
use crate::board::PieceType;
|
||||
|
||||
// BIT 0 - 5: FROM SQUARE (0-63)
|
||||
pub const MOVE_FROM_MASK: u16 = 0b0000_0000_0011_1111;
|
||||
|
||||
// BIT 6 - 11: TO SQUARE (0-63)
|
||||
pub const MOVE_TO_MASK: u16 = 0b0000_1111_1100_0000;
|
||||
|
||||
// BIT 12 - 15: FLAGS (4 bits)
|
||||
// 1. 0 no capture, 1 capture
|
||||
pub const MOVE_FLAG_MASK: u16 = 0b1111_0000_0000_0000;
|
||||
|
||||
pub const MOVE_FLAG_QUIET: u16 = 0b0000_0000_0000_0000;
|
||||
pub const MOVE_FLAG_CAPTURE: u16 = 0b0001_0000_0000_0000;
|
||||
pub const MOVE_FLAG_EN_PASSANT: u16 = 0b0010_0000_0000_0000;
|
||||
|
||||
pub const MOVE_FLAG_WK_CASTLE: u16 = 0b0011_0000_0000_0000;
|
||||
pub const MOVE_FLAG_WQ_CASTLE: u16 = 0b0100_0000_0000_0000;
|
||||
pub const MOVE_FLAG_BK_CASTLE: u16 = 0b0101_0000_0000_0000;
|
||||
pub const MOVE_FLAG_BQ_CASTLE: u16 = 0b0110_0000_0000_0000;
|
||||
// 0111 is free
|
||||
|
||||
// Promotion flags (use the 1xxx bits)
|
||||
// We combine capture flag with promotion type
|
||||
pub const MOVE_FLAG_PROMO: u16 = 0b1000_0000_0000_0000;
|
||||
pub const MOVE_FLAG_NO_PROMO: u16 = 0b0000_0000_0000_0000;
|
||||
|
||||
pub const MOVE_FLAG_PROMO_N: u16 = 0b1000_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_B: u16 = 0b1001_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_R: u16 = 0b1010_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_Q: u16 = 0b1011_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_N: u16 = 0b1100_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_B: u16 = 0b1101_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_R: u16 = 0b1110_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_Q: u16 = 0b1111_0000_0000_0000;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Move(u16);
|
||||
|
||||
impl Move {
|
||||
pub fn new(from: Square, to: Square, flags: u16) -> Move {
|
||||
Move(flags |
|
||||
((to as u16) << 6 ) |
|
||||
from as u16)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_flags(&self) -> u16 {
|
||||
self.0 & MOVE_FLAG_MASK
|
||||
}
|
||||
|
||||
|
||||
/// Converts a square index (0-63) to algebraic notation (e.g., 0 -> "a1", 63 -> "h8").
|
||||
fn square_val_to_alg(val: u16) -> String {
|
||||
let file = (b'a' + (val % 8) as u8) as char;
|
||||
let rank = (b'1' + (val / 8) as u8) as char;
|
||||
format!("{}{}", file, rank)
|
||||
}
|
||||
|
||||
/// Converts the move to coordinate notation (e.g., "e2e4", "e7e8q", "e1g1").
|
||||
pub fn to_algebraic(&self) -> String {
|
||||
let flags = self.get_flags();
|
||||
|
||||
// Handle castling first. In this new format, the "to" square is
|
||||
// the *king's* destination square (g1/c1 or g8/c8).
|
||||
// Your old implementation reading the file is still fine.
|
||||
if (flags == MOVE_FLAG_WK_CASTLE) || (flags == MOVE_FLAG_BK_CASTLE) {
|
||||
return "O-O".to_string();
|
||||
}
|
||||
if (flags == MOVE_FLAG_WQ_CASTLE) || (flags == MOVE_FLAG_BQ_CASTLE) {
|
||||
return "O-O-O".to_string();
|
||||
}
|
||||
|
||||
let from_val = self.0 & MOVE_FROM_MASK;
|
||||
let to_val = (self.0 & MOVE_TO_MASK) >> 6;
|
||||
|
||||
let from_str = Self::square_val_to_alg(from_val);
|
||||
let to_str = Self::square_val_to_alg(to_val);
|
||||
|
||||
// Check if it's any promotion type (1xxx)
|
||||
if (flags & 0b1000_0000_0000_0000) != 0 {
|
||||
let promo_char = match flags {
|
||||
MOVE_FLAG_PROMO_N | MOVE_FLAG_PROMO_CAP_N => 'n',
|
||||
MOVE_FLAG_PROMO_B | MOVE_FLAG_PROMO_CAP_B => 'b',
|
||||
MOVE_FLAG_PROMO_R | MOVE_FLAG_PROMO_CAP_R => 'r',
|
||||
MOVE_FLAG_PROMO_Q | MOVE_FLAG_PROMO_CAP_Q => 'q',
|
||||
_ => '?', // Should not happen
|
||||
};
|
||||
format!("{}{}{}", from_str, to_str, promo_char)
|
||||
} else {
|
||||
// This covers Quiet, DoublePawn, Capture, EnPassant
|
||||
format!("{}{}", from_str, to_str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... Rest des MoveList-Codes bleibt exakt gleich ...
|
||||
// (MoveList, new, push, len, is_empty, iter, impl fmt::Display)
|
||||
pub struct MoveList {
|
||||
moves: [Move; 256],
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl MoveList {
|
||||
pub fn new() -> Self {
|
||||
MoveList {
|
||||
moves: [unsafe { std::mem::zeroed() }; 256],
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, mv: Move) {
|
||||
debug_assert!(self.count < 256, "Move list overflow!");
|
||||
|
||||
self.moves[self.count] = mv;
|
||||
self.count += 1;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.count == 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn iter(&self) -> slice::Iter<'_, Move> {
|
||||
self.moves[..self.count].iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MoveList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", &self.iter().map(|mv| mv.to_algebraic()).collect::<Vec<String>>().join(" "))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct UndoMove {
|
||||
mv: Move,
|
||||
captured_piece: Option<PieceType>,
|
||||
old_en_passant_square: Option<Square>,
|
||||
old_castling_rights: u8,
|
||||
old_halfmove_clock: u8,
|
||||
}
|
||||
|
||||
impl UndoMove {
|
||||
pub fn new(mv: Move,
|
||||
captured_piece: Option<PieceType>,
|
||||
old_en_passant_square: Option<Square>,
|
||||
old_castling_rights: u8,
|
||||
old_halfmove_clock: u8) -> Self {
|
||||
Self {
|
||||
mv,
|
||||
captured_piece,
|
||||
old_en_passant_square,
|
||||
old_castling_rights,
|
||||
old_halfmove_clock
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue