feat: promotion moves
This commit is contained in:
parent
8804c0e1c4
commit
98b4f116d6
@ -34,7 +34,7 @@ impl From<Color> for char {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
enum Piece {
|
enum Piece {
|
||||||
Rook,
|
Rook,
|
||||||
Bishop,
|
Bishop,
|
||||||
@ -157,7 +157,7 @@ impl Square {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert typical human-readable form (e.g. `e4`) to square index.
|
/// Convert typical human-readable form (e.g. `e4`) to square index.
|
||||||
fn from_algebraic(value: String) -> Result<Self, SquareError> {
|
fn from_algebraic(value: &str) -> Result<Self, SquareError> {
|
||||||
let bytes = value.as_bytes();
|
let bytes = value.as_bytes();
|
||||||
let col = match bytes[0] as char {
|
let col = match bytes[0] as char {
|
||||||
'a' => 0,
|
'a' => 0,
|
||||||
@ -187,7 +187,7 @@ mod tests {
|
|||||||
let test_cases = [("a1", 0), ("a8", 56), ("h1", 7), ("h8", 63)];
|
let test_cases = [("a1", 0), ("a8", 56), ("h1", 7), ("h8", 63)];
|
||||||
for (sqr, idx) in test_cases {
|
for (sqr, idx) in test_cases {
|
||||||
assert_eq!(Square::try_from(idx).unwrap().to_algebraic(), sqr);
|
assert_eq!(Square::try_from(idx).unwrap().to_algebraic(), sqr);
|
||||||
assert_eq!(Square::from_algebraic(sqr.to_string()).unwrap(), Square::try_from(idx).unwrap());
|
assert_eq!(Square::from_algebraic(sqr).unwrap(), Square::try_from(idx).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Move generation.
|
//! Move generation.
|
||||||
|
|
||||||
use crate::fen::{FromFen, ToFen, START_POSITION};
|
use crate::fen::{FromFen, ToFen, START_POSITION};
|
||||||
use crate::{BoardState, Color, Piece, Square, BOARD_HEIGHT, BOARD_WIDTH, N_SQUARES};
|
use crate::{BoardState, ColPiece, Color, Piece, Square, BOARD_HEIGHT, BOARD_WIDTH, N_SQUARES};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Game tree node.
|
/// Game tree node.
|
||||||
@ -32,6 +32,17 @@ enum PromotePiece {
|
|||||||
Queen,
|
Queen,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<PromotePiece> for Piece {
|
||||||
|
fn from(value: PromotePiece) -> Self {
|
||||||
|
match value {
|
||||||
|
PromotePiece::Rook => Piece::Rook,
|
||||||
|
PromotePiece::Bishop => Piece::Bishop,
|
||||||
|
PromotePiece::Knight => Piece::Knight,
|
||||||
|
PromotePiece::Queen => Piece::Queen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Move data common to all move types.
|
/// Move data common to all move types.
|
||||||
struct MoveData {
|
struct MoveData {
|
||||||
src: Square,
|
src: Square,
|
||||||
@ -61,16 +72,46 @@ impl Move {
|
|||||||
prev: Some(Rc::new(old_node)),
|
prev: Some(Rc::new(old_node)),
|
||||||
pos: old_pos,
|
pos: old_pos,
|
||||||
};
|
};
|
||||||
node.pos.turn = node.pos.turn.flip();
|
|
||||||
if node.pos.turn == Color::White {
|
if old_pos.turn == Color::Black {
|
||||||
node.pos.full_moves += 1;
|
node.pos.full_moves += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the piece at the source square.
|
||||||
|
macro_rules! pc_src {
|
||||||
|
($data: ident) => {
|
||||||
|
node.pos
|
||||||
|
.get_piece($data.src)
|
||||||
|
.expect("Move source should have a piece")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// Perform sanity checks.
|
||||||
|
macro_rules! pc_asserts {
|
||||||
|
($pc_src: ident, $data: ident) => {
|
||||||
|
debug_assert_eq!($pc_src.col, node.pos.turn, "Moving piece on wrong turn.");
|
||||||
|
debug_assert_ne!($data.src, $data.dest, "Moving piece to itself.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Move::Promotion(data, piece) => todo!(),
|
Move::Promotion(data, to_piece) => {
|
||||||
|
let pc_src = pc_src!(data);
|
||||||
|
pc_asserts!(pc_src, data);
|
||||||
|
debug_assert_eq!(pc_src.pc, Piece::Pawn);
|
||||||
|
|
||||||
|
node.pos.del_piece(data.src);
|
||||||
|
node.pos.set_piece(
|
||||||
|
data.dest,
|
||||||
|
ColPiece {
|
||||||
|
pc: Piece::from(to_piece),
|
||||||
|
col: pc_src.col,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
Move::Castle(data) => todo!(),
|
Move::Castle(data) => todo!(),
|
||||||
Move::Normal(data) => {
|
Move::Normal(data) => {
|
||||||
let pc_src = node.pos.get_piece(data.src).unwrap();
|
let pc_src = pc_src!(data);
|
||||||
|
pc_asserts!(pc_src, data);
|
||||||
if matches!(pc_src.pc, Piece::Pawn) {
|
if matches!(pc_src.pc, Piece::Pawn) {
|
||||||
// pawn moves are irreversible
|
// pawn moves are irreversible
|
||||||
node.pos.half_moves = 0;
|
node.pos.half_moves = 0;
|
||||||
@ -129,6 +170,8 @@ impl Move {
|
|||||||
Move::EnPassant(data) => todo!(),
|
Move::EnPassant(data) => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.pos.turn = node.pos.turn.flip();
|
||||||
|
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,11 +272,14 @@ mod tests {
|
|||||||
|
|
||||||
// make move
|
// make move
|
||||||
println!("Starting test case {i}, make move.");
|
println!("Starting test case {i}, make move.");
|
||||||
let mut node = Node {pos: BoardState::from_fen(start_pos.to_string()).unwrap(), prev: None};
|
let mut node = Node {
|
||||||
|
pos: BoardState::from_fen(start_pos.to_string()).unwrap(),
|
||||||
|
prev: None,
|
||||||
|
};
|
||||||
for (src, dest, expect_fen) in moves {
|
for (src, dest, expect_fen) in moves {
|
||||||
println!("Moving {src} to {dest}.");
|
println!("Moving {src} to {dest}.");
|
||||||
let idx_src = Square::from_algebraic(src.to_string()).unwrap();
|
let idx_src = Square::from_algebraic(src).unwrap();
|
||||||
let idx_dest = Square::from_algebraic(dest.to_string()).unwrap();
|
let idx_dest = Square::from_algebraic(dest).unwrap();
|
||||||
let mv = Move::Normal(MoveData {
|
let mv = Move::Normal(MoveData {
|
||||||
src: idx_src,
|
src: idx_src,
|
||||||
dest: idx_dest,
|
dest: idx_dest,
|
||||||
|
Loading…
Reference in New Issue
Block a user