stub: movegen
This commit is contained in:
parent
1914d812e4
commit
77838fd417
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
|
TODO.txt
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
use chess_inator::Position;
|
|
||||||
use chess_inator::fen::FromFen;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1";
|
|
||||||
let board = Position::from_fen(fen.into()).unwrap();
|
|
||||||
println!("{}", board);
|
|
||||||
println!("{:#?}", board);
|
|
||||||
}
|
|
34
src/fen.rs
34
src/fen.rs
@ -1,4 +1,4 @@
|
|||||||
use crate::{Position, Index, Color, ColPiece};
|
use crate::{BoardState, Square, Color, ColPiece};
|
||||||
use crate::{BOARD_WIDTH, BOARD_HEIGHT};
|
use crate::{BOARD_WIDTH, BOARD_HEIGHT};
|
||||||
|
|
||||||
pub trait FromFen {
|
pub trait FromFen {
|
||||||
@ -29,9 +29,9 @@ pub enum FenError {
|
|||||||
InternalError(usize),
|
InternalError(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromFen for Position {
|
impl FromFen for BoardState {
|
||||||
type Error = FenError;
|
type Error = FenError;
|
||||||
fn from_fen(fen: String) -> Result<Position, FenError> {
|
fn from_fen(fen: String) -> Result<BoardState, FenError> {
|
||||||
//! Parse FEN string into position.
|
//! Parse FEN string into position.
|
||||||
|
|
||||||
/// Parser state machine.
|
/// Parser state machine.
|
||||||
@ -55,7 +55,7 @@ impl FromFen for Position {
|
|||||||
FullMove,
|
FullMove,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pos = Position::default();
|
let mut pos = BoardState::default();
|
||||||
|
|
||||||
let mut parser_state = FenState::Piece(0, 0);
|
let mut parser_state = FenState::Piece(0, 0);
|
||||||
let mut next_state = FenState::Space;
|
let mut next_state = FenState::Space;
|
||||||
@ -105,7 +105,7 @@ impl FromFen for Position {
|
|||||||
let pc = ColPiece::try_from(pc_char).or(bad_char!(i))?;
|
let pc = ColPiece::try_from(pc_char).or(bad_char!(i))?;
|
||||||
|
|
||||||
pos.set_piece(
|
pos.set_piece(
|
||||||
Index::from_row_col(real_row, col)
|
Square::from_row_col(real_row, col)
|
||||||
.or(Err(FenError::InternalError(i)))?,
|
.or(Err(FenError::InternalError(i)))?,
|
||||||
pc,
|
pc,
|
||||||
);
|
);
|
||||||
@ -174,7 +174,7 @@ impl FromFen for Position {
|
|||||||
parse_space_and_goto!(FenState::HalfMove);
|
parse_space_and_goto!(FenState::HalfMove);
|
||||||
}
|
}
|
||||||
'a'..='h' => {
|
'a'..='h' => {
|
||||||
pos.ep_square = Some(Index(c as usize - 'a' as usize));
|
pos.ep_square = Some(Square(c as usize - 'a' as usize));
|
||||||
parser_state = FenState::EnPassantFile;
|
parser_state = FenState::EnPassantFile;
|
||||||
}
|
}
|
||||||
_ => return bad_char!(i),
|
_ => return bad_char!(i),
|
||||||
@ -182,8 +182,8 @@ impl FromFen for Position {
|
|||||||
}
|
}
|
||||||
FenState::EnPassantFile => {
|
FenState::EnPassantFile => {
|
||||||
if let Some(digit) = c.to_digit(10) {
|
if let Some(digit) = c.to_digit(10) {
|
||||||
pos.ep_square = Some(Index(
|
pos.ep_square = Some(Square(
|
||||||
usize::from(pos.ep_square.unwrap_or(Index(0)))
|
usize::from(pos.ep_square.unwrap_or(Square(0)))
|
||||||
+ (digit as usize - 1) * 8,
|
+ (digit as usize - 1) * 8,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
@ -193,7 +193,7 @@ impl FromFen for Position {
|
|||||||
}
|
}
|
||||||
FenState::HalfMove => {
|
FenState::HalfMove => {
|
||||||
if let Some(digit) = c.to_digit(10) {
|
if let Some(digit) = c.to_digit(10) {
|
||||||
if pos.half_moves > Position::MAX_MOVES {
|
if pos.half_moves > BoardState::MAX_MOVES {
|
||||||
return Err(FenError::TooManyMoves);
|
return Err(FenError::TooManyMoves);
|
||||||
}
|
}
|
||||||
pos.half_moves *= 10;
|
pos.half_moves *= 10;
|
||||||
@ -206,7 +206,7 @@ impl FromFen for Position {
|
|||||||
}
|
}
|
||||||
FenState::FullMove => {
|
FenState::FullMove => {
|
||||||
if let Some(digit) = c.to_digit(10) {
|
if let Some(digit) = c.to_digit(10) {
|
||||||
if pos.half_moves > Position::MAX_MOVES {
|
if pos.half_moves > BoardState::MAX_MOVES {
|
||||||
return Err(FenError::TooManyMoves);
|
return Err(FenError::TooManyMoves);
|
||||||
}
|
}
|
||||||
pos.full_moves *= 10;
|
pos.full_moves *= 10;
|
||||||
@ -237,22 +237,22 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fen_pieces() {
|
fn test_fen_pieces() {
|
||||||
let fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1";
|
let fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1";
|
||||||
let board = Position::from_fen(fen.into()).unwrap();
|
let board = BoardState::from_fen(fen.into()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(0..N_SQUARES)
|
(0..N_SQUARES)
|
||||||
.map(Index)
|
.map(Square)
|
||||||
.map(|i| board.get_piece(i))
|
.map(|i| board.get_piece(i))
|
||||||
.map(ColPiece::opt_to_char)
|
.map(ColPiece::opt_to_char)
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
"RNBQKBNRPPPP.PPP............P...................pppppppprnbqkbnr"
|
"RNBQKBNRPPPP.PPP............P...................pppppppprnbqkbnr"
|
||||||
);
|
);
|
||||||
assert_eq!(board.ep_square.unwrap(), Index(20));
|
assert_eq!(board.ep_square.unwrap(), Square(20));
|
||||||
assert_eq!(board.turn, Color::Black);
|
assert_eq!(board.turn, Color::Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! make_board{
|
macro_rules! make_board{
|
||||||
($fen_fmt: expr) => {
|
($fen_fmt: expr) => {
|
||||||
Position::from_fen(format!($fen_fmt)).unwrap()
|
BoardState::from_fen(format!($fen_fmt)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ mod tests {
|
|||||||
let test_cases = [("e3", 20), ("h8", 63), ("a8", 56), ("h4", 31), ("a1", 0)];
|
let test_cases = [("e3", 20), ("h8", 63), ("a8", 56), ("h4", 31), ("a1", 0)];
|
||||||
for (sqr, idx) in test_cases {
|
for (sqr, idx) in test_cases {
|
||||||
let board = make_board!("8/8/8/8/8/8/8/8 w - {sqr} 0 0");
|
let board = make_board!("8/8/8/8/8/8/8/8 w - {sqr} 0 0");
|
||||||
assert_eq!(board.ep_square.unwrap(), Index(idx));
|
assert_eq!(board.ep_square.unwrap(), Square(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
let board = make_board!("8/8/8/8/8/8/8/8 w - - 0 0");
|
let board = make_board!("8/8/8/8/8/8/8/8 w - - 0 0");
|
||||||
@ -338,7 +338,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fen_half_move_counter() {
|
fn test_fen_half_move_counter() {
|
||||||
for i in 0..=Position::MAX_MOVES {
|
for i in 0..=BoardState::MAX_MOVES {
|
||||||
let board = make_board!("8/8/8/8/8/8/8/8 w - - {i} 0");
|
let board = make_board!("8/8/8/8/8/8/8/8 w - - {i} 0");
|
||||||
assert_eq!(board.half_moves, i);
|
assert_eq!(board.half_moves, i);
|
||||||
assert_eq!(board.full_moves, 0);
|
assert_eq!(board.full_moves, 0);
|
||||||
@ -347,7 +347,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fen_move_counter() {
|
fn test_fen_move_counter() {
|
||||||
for i in 0..=Position::MAX_MOVES {
|
for i in 0..=BoardState::MAX_MOVES {
|
||||||
let board = make_board!("8/8/8/8/8/8/8/8 w - - 0 {i}");
|
let board = make_board!("8/8/8/8/8/8/8/8 w - - 0 {i}");
|
||||||
assert_eq!(board.half_moves, 0);
|
assert_eq!(board.half_moves, 0);
|
||||||
assert_eq!(board.full_moves, i);
|
assert_eq!(board.full_moves, i);
|
||||||
|
64
src/lib.rs
64
src/lib.rs
@ -1,6 +1,8 @@
|
|||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
|
|
||||||
pub mod fen;
|
pub mod fen;
|
||||||
|
pub mod movegen;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
const BOARD_WIDTH: usize = 8;
|
const BOARD_WIDTH: usize = 8;
|
||||||
const BOARD_HEIGHT: usize = 8;
|
const BOARD_HEIGHT: usize = 8;
|
||||||
@ -9,11 +11,21 @@ const N_SQUARES: usize = BOARD_WIDTH * BOARD_HEIGHT;
|
|||||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
enum Color {
|
enum Color {
|
||||||
#[default]
|
#[default]
|
||||||
White,
|
White = 0,
|
||||||
Black,
|
Black = 1,
|
||||||
}
|
}
|
||||||
const N_COLORS: usize = 2;
|
const N_COLORS: usize = 2;
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
/// Return opposite color (does not assign).
|
||||||
|
pub fn flip(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Color::White => Color::Black,
|
||||||
|
Color::Black => Color::White,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
enum Piece {
|
enum Piece {
|
||||||
Rook,
|
Rook,
|
||||||
@ -88,29 +100,29 @@ impl ColPiece {
|
|||||||
///
|
///
|
||||||
/// A1 is (0, 0) -> 0, A2 is (0, 1) -> 2, and H8 is (7, 7) -> 63.
|
/// A1 is (0, 0) -> 0, A2 is (0, 1) -> 2, and H8 is (7, 7) -> 63.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
struct Index(usize);
|
struct Square(usize);
|
||||||
|
|
||||||
enum IndexError {
|
enum IndexError {
|
||||||
OutOfBounds,
|
OutOfBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<usize> for Index {
|
impl TryFrom<usize> for Square {
|
||||||
type Error = IndexError;
|
type Error = IndexError;
|
||||||
|
|
||||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||||
if (0..N_SQUARES).contains(&value) {
|
if (0..N_SQUARES).contains(&value) {
|
||||||
Ok(Index(value))
|
Ok(Square(value))
|
||||||
} else {
|
} else {
|
||||||
Err(IndexError::OutOfBounds)
|
Err(IndexError::OutOfBounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<Index> for usize {
|
impl From<Square> for usize {
|
||||||
fn from(value: Index) -> Self {
|
fn from(value: Square) -> Self {
|
||||||
value.0
|
value.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Index {
|
impl Square {
|
||||||
fn from_row_col(r: usize, c: usize) -> Result<Self, IndexError> {
|
fn from_row_col(r: usize, c: usize) -> Result<Self, IndexError> {
|
||||||
//! Get index of square based on row and column.
|
//! Get index of square based on row and column.
|
||||||
let ret = BOARD_WIDTH * r + c;
|
let ret = BOARD_WIDTH * r + c;
|
||||||
@ -147,16 +159,16 @@ impl From<Piece> for char {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
struct Bitboard(u64);
|
struct Bitboard(u64);
|
||||||
|
|
||||||
impl Bitboard {
|
impl Bitboard {
|
||||||
pub fn on_idx(&mut self, idx: Index) {
|
pub fn on_idx(&mut self, idx: Square) {
|
||||||
//! Set the square at an index to on.
|
//! Set the square at an index to on.
|
||||||
self.0 |= 1 << usize::from(idx);
|
self.0 |= 1 << usize::from(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn off_idx(&mut self, idx: Index) {
|
pub fn off_idx(&mut self, idx: Square) {
|
||||||
//! Set the square at an index to off.
|
//! Set the square at an index to off.
|
||||||
self.0 &= !(1 << usize::from(idx));
|
self.0 &= !(1 << usize::from(idx));
|
||||||
}
|
}
|
||||||
@ -165,7 +177,7 @@ impl Bitboard {
|
|||||||
/// Array form board.
|
/// Array form board.
|
||||||
///
|
///
|
||||||
/// Complements bitboards, notably for "what piece is at this square?" queries.
|
/// Complements bitboards, notably for "what piece is at this square?" queries.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct Mailbox([Option<ColPiece>; N_SQUARES]);
|
struct Mailbox([Option<ColPiece>; N_SQUARES]);
|
||||||
|
|
||||||
impl Default for Mailbox {
|
impl Default for Mailbox {
|
||||||
@ -176,12 +188,12 @@ impl Default for Mailbox {
|
|||||||
|
|
||||||
impl Mailbox {
|
impl Mailbox {
|
||||||
/// Get mutable reference to square at index.
|
/// Get mutable reference to square at index.
|
||||||
fn sq_mut(&mut self, idx: Index) -> &mut Option<ColPiece> {
|
fn sq_mut(&mut self, idx: Square) -> &mut Option<ColPiece> {
|
||||||
&mut self.0[usize::from(idx)]
|
&mut self.0[usize::from(idx)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get non-mutable reference to square at index.
|
/// Get non-mutable reference to square at index.
|
||||||
fn sq(&self, idx: Index) -> &Option<ColPiece> {
|
fn sq(&self, idx: Square) -> &Option<ColPiece> {
|
||||||
&self.0[usize::from(idx)]
|
&self.0[usize::from(idx)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +201,7 @@ impl Mailbox {
|
|||||||
/// Piece bitboards and state for one player.
|
/// Piece bitboards and state for one player.
|
||||||
///
|
///
|
||||||
/// Default is all empty.
|
/// Default is all empty.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
struct Player {
|
struct Player {
|
||||||
/// Bitboards for individual pieces. Piece -> locations.
|
/// Bitboards for individual pieces. Piece -> locations.
|
||||||
bit: [Bitboard; N_PIECES],
|
bit: [Bitboard; N_PIECES],
|
||||||
@ -203,7 +215,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Castling rights for one player
|
/// Castling rights for one player
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct CastlingRights {
|
pub struct CastlingRights {
|
||||||
/// Kingside
|
/// Kingside
|
||||||
k: bool,
|
k: bool,
|
||||||
@ -211,11 +223,11 @@ pub struct CastlingRights {
|
|||||||
q: bool,
|
q: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Game state.
|
/// Immutable game state, unique to a position.
|
||||||
///
|
///
|
||||||
/// Default is empty.
|
/// Default is empty.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub struct Position {
|
pub struct BoardState {
|
||||||
/// Player bitboards
|
/// Player bitboards
|
||||||
players: [Player; N_COLORS],
|
players: [Player; N_COLORS],
|
||||||
|
|
||||||
@ -225,7 +237,7 @@ pub struct Position {
|
|||||||
/// En-passant square.
|
/// En-passant square.
|
||||||
///
|
///
|
||||||
/// (If a pawn moves twice, this is one square in front of the start position.)
|
/// (If a pawn moves twice, this is one square in front of the start position.)
|
||||||
ep_square: Option<Index>,
|
ep_square: Option<Square>,
|
||||||
|
|
||||||
/// Castling rights
|
/// Castling rights
|
||||||
castle: [CastlingRights; N_COLORS],
|
castle: [CastlingRights; N_COLORS],
|
||||||
@ -240,21 +252,21 @@ pub struct Position {
|
|||||||
turn: Color,
|
turn: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl BoardState {
|
||||||
/// Get mutable reference to a player.
|
/// Get mutable reference to a player.
|
||||||
fn pl_mut(&mut self, col: Color) -> &mut Player {
|
fn pl_mut(&mut self, col: Color) -> &mut Player {
|
||||||
&mut self.players[col as usize]
|
&mut self.players[col as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new piece in a location.
|
/// Create a new piece in a location.
|
||||||
fn set_piece(&mut self, idx: Index, pc: ColPiece) {
|
fn set_piece(&mut self, idx: Square, pc: ColPiece) {
|
||||||
let pl = self.pl_mut(pc.col);
|
let pl = self.pl_mut(pc.col);
|
||||||
pl.board(pc.into()).on_idx(idx);
|
pl.board(pc.into()).on_idx(idx);
|
||||||
*self.mail.sq_mut(idx) = Some(pc);
|
*self.mail.sq_mut(idx) = Some(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete the piece in a location, if it exists.
|
/// Delete the piece in a location, if it exists.
|
||||||
fn del_piece(&mut self, idx: Index) {
|
fn del_piece(&mut self, idx: Square) {
|
||||||
if let Some(pc) = *self.mail.sq_mut(idx) {
|
if let Some(pc) = *self.mail.sq_mut(idx) {
|
||||||
let pl = self.pl_mut(pc.col);
|
let pl = self.pl_mut(pc.col);
|
||||||
pl.board(pc.into()).off_idx(idx);
|
pl.board(pc.into()).off_idx(idx);
|
||||||
@ -263,7 +275,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the piece at a location.
|
/// Get the piece at a location.
|
||||||
fn get_piece(&self, idx: Index) -> Option<ColPiece> {
|
fn get_piece(&self, idx: Square) -> Option<ColPiece> {
|
||||||
*self.mail.sq(idx)
|
*self.mail.sq(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,12 +283,12 @@ impl Position {
|
|||||||
const MAX_MOVES: usize = 9_999;
|
const MAX_MOVES: usize = 9_999;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Display for Position {
|
impl core::fmt::Display for BoardState {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let mut str = String::with_capacity(N_SQUARES + BOARD_HEIGHT);
|
let mut str = String::with_capacity(N_SQUARES + BOARD_HEIGHT);
|
||||||
for row in (0..BOARD_HEIGHT).rev() {
|
for row in (0..BOARD_HEIGHT).rev() {
|
||||||
for col in 0..BOARD_WIDTH {
|
for col in 0..BOARD_WIDTH {
|
||||||
let idx = Index::from_row_col(row, col).or(Err(std::fmt::Error))?;
|
let idx = Square::from_row_col(row, col).or(Err(std::fmt::Error))?;
|
||||||
let pc = self.get_piece(idx);
|
let pc = self.get_piece(idx);
|
||||||
str.push(ColPiece::opt_to_char(pc));
|
str.push(ColPiece::opt_to_char(pc));
|
||||||
}
|
}
|
||||||
|
68
src/movegen.rs
Normal file
68
src/movegen.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! Move generation.
|
||||||
|
|
||||||
|
use crate::{Color, Square, BoardState};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Game tree node.
|
||||||
|
struct Node {
|
||||||
|
/// Immutable position data.
|
||||||
|
pos: BoardState,
|
||||||
|
/// Backlink to previous node.
|
||||||
|
prev: Option<Rc<Node>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Piece enum specifically for promotions.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum PromotePiece {
|
||||||
|
Rook,
|
||||||
|
Bishop,
|
||||||
|
Knight,
|
||||||
|
Queen,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move data common to all move types.
|
||||||
|
struct MoveData {
|
||||||
|
src: Square,
|
||||||
|
dest: Square,
|
||||||
|
}
|
||||||
|
/// Pseudo-legal move.
|
||||||
|
enum Move {
|
||||||
|
/// Pawn promotes to another piece.
|
||||||
|
Promotion { data: MoveData, piece: PromotePiece },
|
||||||
|
/// King castles with rook.
|
||||||
|
Castle { data: MoveData },
|
||||||
|
/// Capture, or push move.
|
||||||
|
Normal { data: MoveData },
|
||||||
|
/// This move is an en-passant capture.
|
||||||
|
EnPassant { data: MoveData },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Move {
|
||||||
|
/// Make move and return new position.
|
||||||
|
///
|
||||||
|
/// Old position is saved in a backlink.
|
||||||
|
pub fn make(self, old_node: Node) -> Node {
|
||||||
|
let old_pos = old_node.pos;
|
||||||
|
let mut node = Node {
|
||||||
|
prev: Some(Rc::new(old_node)),
|
||||||
|
pos: old_pos,
|
||||||
|
};
|
||||||
|
node.pos.turn = node.pos.turn.flip();
|
||||||
|
if node.pos.turn == Color::White {
|
||||||
|
node.pos.full_moves += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Move::Promotion { data, piece } => todo!(),
|
||||||
|
Move::Castle { data } => todo!(),
|
||||||
|
Move::Normal { data } => {
|
||||||
|
let pc = node.pos.get_piece(data.src).unwrap();
|
||||||
|
node.pos.del_piece(data.src);
|
||||||
|
node.pos.set_piece(data.dest, pc);
|
||||||
|
}
|
||||||
|
Move::EnPassant { data } => todo!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
node
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user