|
@@ -4,6 +4,7 @@ use log::info;
|
|
use std::sync::Arc;
|
|
use std::sync::Arc;
|
|
use zobrist::{ZobristTable};
|
|
use zobrist::{ZobristTable};
|
|
use zobrist;
|
|
use zobrist;
|
|
|
|
+use hash::RepetitionTable;
|
|
|
|
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
pub struct Game
|
|
pub struct Game
|
|
@@ -59,6 +60,7 @@ impl Default for Game {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
impl std::hash::Hash for Game {
|
|
impl std::hash::Hash for Game {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
if let Some((ref _zt, ref zb)) = &self.zobrist {
|
|
if let Some((ref _zt, ref zb)) = &self.zobrist {
|
|
@@ -78,7 +80,7 @@ impl PartialEq for Game {
|
|
|
|
|
|
impl Eq for Game {
|
|
impl Eq for Game {
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+*/
|
|
|
|
|
|
impl Game {
|
|
impl Game {
|
|
pub fn empty() -> Game {
|
|
pub fn empty() -> Game {
|
|
@@ -157,10 +159,10 @@ impl Game {
|
|
|
|
|
|
// parse en passant
|
|
// parse en passant
|
|
game.en_passant = Move::parse_square(en_passant).map(|sq| indices_from_square(sq).0);
|
|
game.en_passant = Move::parse_square(en_passant).map(|sq| indices_from_square(sq).0);
|
|
- info!("en passant on file {:?}", game.en_passant);
|
|
|
|
|
|
+ //info!("en passant on file {:?}", game.en_passant);
|
|
|
|
|
|
game.halfmoves_since_last_event = halfmoves_since_last_event.parse::<i8>().unwrap_or(0);
|
|
game.halfmoves_since_last_event = halfmoves_since_last_event.parse::<i8>().unwrap_or(0);
|
|
- //game.turn_number = turn_number.parse::<i32>().unwrap_or(0);
|
|
|
|
|
|
+ game.turn_number = turn_number.parse::<i32>().unwrap_or(0);
|
|
|
|
|
|
Some(game)
|
|
Some(game)
|
|
}
|
|
}
|
|
@@ -179,11 +181,31 @@ impl Game {
|
|
let origin = Move::parse_square(&mov[0..2]);
|
|
let origin = Move::parse_square(&mov[0..2]);
|
|
let target = Move::parse_square(&mov[2..4]);
|
|
let target = Move::parse_square(&mov[2..4]);
|
|
|
|
|
|
|
|
+ let promote_to = if mov.len() == 5 {
|
|
|
|
+ Some(match mov.chars().nth(4) {
|
|
|
|
+ Some('Q') | Some('q') => QUEEN,
|
|
|
|
+ Some('N') | Some('n') => KNIGHT,
|
|
|
|
+ Some('B') | Some('b') => BISHOP,
|
|
|
|
+ Some('R') | Some('r') => ROOK,
|
|
|
|
+ _ => panic!("invalid move: {}", mov)
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ None
|
|
|
|
+ };
|
|
|
|
|
|
if let (Some(from), Some(to)) = (origin, target) {
|
|
if let (Some(from), Some(to)) = (origin, target) {
|
|
let (piece_type, side) = self.get_square(from);
|
|
let (piece_type, side) = self.get_square(from);
|
|
//println!("from: {}", from);
|
|
//println!("from: {}", from);
|
|
|
|
|
|
|
|
+ let (cap, cs) = self.get_square(to);
|
|
|
|
+ let captured = if cap != NO_PIECE { Some(cap) } else { None };
|
|
|
|
+
|
|
|
|
+ if cap != NO_PIECE && cs == side {
|
|
|
|
+ // cannot capture own piece
|
|
|
|
+ return Err(());
|
|
|
|
+ }
|
|
|
|
+
|
|
if piece_type == NO_PIECE {
|
|
if piece_type == NO_PIECE {
|
|
return Err(());
|
|
return Err(());
|
|
}
|
|
}
|
|
@@ -191,20 +213,33 @@ impl Game {
|
|
if side != self.turn { // wrong side to move
|
|
if side != self.turn { // wrong side to move
|
|
return Err(());
|
|
return Err(());
|
|
}
|
|
}
|
|
-
|
|
|
|
- if mov.len() == 5 {
|
|
|
|
- Err(())
|
|
|
|
|
|
+
|
|
|
|
+ if let Some(promote_to) = promote_to {
|
|
|
|
+ if piece_type != PAWN {
|
|
|
|
+ return Err(());
|
|
|
|
+ }
|
|
|
|
+ Ok(Move::Promotion{ mov: SimpleMove{ from, to }, promote_to, captured })
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- //println!("pt: {}", piece_type);
|
|
|
|
- let (cap_piece, cap_side) = self.get_square(to);
|
|
|
|
-
|
|
|
|
- if cap_piece == NO_PIECE {
|
|
|
|
- Ok(Move::Default{ mov: SimpleMove{ from, to }, piece_type, captured: None })
|
|
|
|
|
|
+ if piece_type == KING && (from as i32 - to as i32).abs() == 2 {
|
|
|
|
+ let left = from < to;
|
|
|
|
+ //println!("OMG castling!");
|
|
|
|
+ return Ok(Move::Castling{ side, left });
|
|
}
|
|
}
|
|
- else {
|
|
|
|
- Ok(Move::Default{ mov: SimpleMove{ from, to }, piece_type, captured: Some(cap_piece) })
|
|
|
|
|
|
+
|
|
|
|
+ // pawn capture
|
|
|
|
+ let (from_file, from_row) = indices_from_square(from);
|
|
|
|
+ let (to_file, to_row) = indices_from_square(to);
|
|
|
|
+ if piece_type == PAWN && from_file != to_file {
|
|
|
|
+ let others = self.get_all_side(!side);
|
|
|
|
+ if others & from_square(to) == 0 {
|
|
|
|
+ let beaten = square_from_indices(to_file, from_row);
|
|
|
|
+ return Ok(Move::EnPassant{ mov: SimpleMove{ from, to }, beaten });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ //println!("pt: {}", piece_type);
|
|
|
|
+ Ok(Move::Default{ mov: SimpleMove{ from, to }, piece_type, captured })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
@@ -538,6 +573,19 @@ impl Game {
|
|
|
|
|
|
pub fn apply(&mut self, mov: Move) -> MoveUndo {
|
|
pub fn apply(&mut self, mov: Move) -> MoveUndo {
|
|
|
|
|
|
|
|
+ /*if !self.is_zobrist_correct() {
|
|
|
|
+ println!("{}", self.beautiful_print());
|
|
|
|
+ println!("incorrect zobrist before apply {} {:?}", mov.to_string(), mov);
|
|
|
|
+ info!("incorrect zobrist before apply");
|
|
|
|
+ panic!("zobrist");
|
|
|
|
+ let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
|
|
+ self.calculate_zobrist(zt)
|
|
|
|
+ } else { 0 };
|
|
|
|
+ if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
|
|
+ *zv = val;
|
|
|
|
+ }
|
|
|
|
+ }*/
|
|
|
|
+
|
|
// save irrecoverable values
|
|
// save irrecoverable values
|
|
let castling_rights_before = self.castling_rights.clone();
|
|
let castling_rights_before = self.castling_rights.clone();
|
|
let halfmoves_since_last_event_before = self.halfmoves_since_last_event.clone();
|
|
let halfmoves_since_last_event_before = self.halfmoves_since_last_event.clone();
|
|
@@ -584,6 +632,23 @@ impl Game {
|
|
*self.get_piece_mut(other_piece, other_side) &= !from_square(mov.to);
|
|
*self.get_piece_mut(other_piece, other_side) &= !from_square(mov.to);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+ if pt == PAWN {
|
|
|
|
+ let row1 = indices_from_square(mov.from).1;
|
|
|
|
+ let row2 = indices_from_square(mov.to).1;
|
|
|
|
+ // check for double push
|
|
|
|
+ if i32::abs(row1 as i32 - row2 as i32) >= 2 {
|
|
|
|
+ let opponent_pawns = self.get_piece(PAWN, !side);
|
|
|
|
+ let target_bb = from_square(mov.to);
|
|
|
|
+ if (west_one(target_bb) | east_one(target_bb)) & opponent_pawns != 0 {
|
|
|
|
+ self.en_passant = Some(indices_from_square(mov.to).0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ self.en_passant = None;
|
|
|
|
+ }
|
|
|
|
+
|
|
let moved_piece = mov.apply_to(self.get_piece(pt, side));
|
|
let moved_piece = mov.apply_to(self.get_piece(pt, side));
|
|
self.set_piece(pt, side, moved_piece);
|
|
self.set_piece(pt, side, moved_piece);
|
|
if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
@@ -615,6 +680,8 @@ impl Game {
|
|
let hup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(new_rook));
|
|
let hup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(new_rook));
|
|
*zv ^= hup ^ hupk;
|
|
*zv ^= hup ^ hupk;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ self.en_passant = None;
|
|
},
|
|
},
|
|
Move::EnPassant { mov, beaten } => {
|
|
Move::EnPassant { mov, beaten } => {
|
|
if let Some(_ep) = self.en_passant {
|
|
if let Some(_ep) = self.en_passant {
|
|
@@ -627,6 +694,8 @@ impl Game {
|
|
let hupo = zt.piece_hash(PAWN, !side, beaten);
|
|
let hupo = zt.piece_hash(PAWN, !side, beaten);
|
|
*zv ^= hup ^ hupo;
|
|
*zv ^= hup ^ hupo;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ self.en_passant = None;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
panic!("internal en passant error");
|
|
panic!("internal en passant error");
|
|
@@ -661,7 +730,9 @@ impl Game {
|
|
let hup = zt.piece_hash(promote_to, side, mov.to);
|
|
let hup = zt.piece_hash(promote_to, side, mov.to);
|
|
*zv ^= hup;
|
|
*zv ^= hup;
|
|
}
|
|
}
|
|
|
|
+ self.en_passant = None;
|
|
},
|
|
},
|
|
|
|
+ Move::Nullmove => {}
|
|
}
|
|
}
|
|
|
|
|
|
if self.turn == BLACK {
|
|
if self.turn == BLACK {
|
|
@@ -676,15 +747,18 @@ impl Game {
|
|
*zv ^= hup ^ castling_hup ^ enpass_hup;
|
|
*zv ^= hup ^ castling_hup ^ enpass_hup;
|
|
}
|
|
}
|
|
|
|
|
|
- if !self.is_zobrist_correct() {
|
|
|
|
- println!("incorrect zobrist after apply");
|
|
|
|
|
|
+ /*if !self.is_zobrist_correct() {
|
|
|
|
+ println!("{}", self.beautiful_print());
|
|
|
|
+ println!("incorrect zobrist after apply {} {:?}", mov.to_string(), mov);
|
|
|
|
+ info!("incorrect zobrist after apply");
|
|
|
|
+ panic!("zobrist");
|
|
let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
self.calculate_zobrist(zt)
|
|
self.calculate_zobrist(zt)
|
|
} else { 0 };
|
|
} else { 0 };
|
|
if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
*zv = val;
|
|
*zv = val;
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ }*/
|
|
|
|
|
|
MoveUndo {
|
|
MoveUndo {
|
|
castling_rights_before,
|
|
castling_rights_before,
|
|
@@ -696,6 +770,13 @@ impl Game {
|
|
|
|
|
|
pub fn undo_move(&mut self, umov: MoveUndo) {
|
|
pub fn undo_move(&mut self, umov: MoveUndo) {
|
|
|
|
|
|
|
|
+ /*if !self.is_zobrist_correct() {
|
|
|
|
+ println!("{}", self.beautiful_print());
|
|
|
|
+ println!("incorrect zobrist before undo {} {:?}", umov.mov.to_string(), umov.mov);
|
|
|
|
+ info!("incorrect zobrist before undo {} {:?}", umov.mov.to_string(), umov.mov);
|
|
|
|
+ panic!("zobrist");
|
|
|
|
+ }*/
|
|
|
|
+
|
|
if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
if let Some((ref zt, ref mut zv)) = self.zobrist {
|
|
let crhup = zt.all_castling_rights_hash(self.castling_rights) ^ zt.all_castling_rights_hash(umov.castling_rights_before);
|
|
let crhup = zt.all_castling_rights_hash(self.castling_rights) ^ zt.all_castling_rights_hash(umov.castling_rights_before);
|
|
let enpass_hup = self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ umov.en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0);
|
|
let enpass_hup = self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ umov.en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0);
|
|
@@ -792,7 +873,8 @@ impl Game {
|
|
*zv ^= hup;
|
|
*zv ^= hup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ },
|
|
|
|
+ Move::Nullmove => {}
|
|
}
|
|
}
|
|
|
|
|
|
self.turn = side;
|
|
self.turn = side;
|
|
@@ -804,21 +886,18 @@ impl Game {
|
|
*zv ^= zt.turn_hash();
|
|
*zv ^= zt.turn_hash();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*if !self.is_zobrist_correct() {
|
|
|
|
+ println!("{}", self.beautiful_print());
|
|
|
|
+ println!("incorrect zobrist after undo {} {:?}", umov.mov.to_string(), umov.mov);
|
|
|
|
+ info!("incorrect zobrist after undo {} {:?}", umov.mov.to_string(), umov.mov);
|
|
|
|
+ panic!("zobrist");
|
|
|
|
+ }*/
|
|
|
|
+
|
|
/*let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
/*let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
self.calculate_zobrist(zt)
|
|
self.calculate_zobrist(zt)
|
|
} else { 0 };
|
|
} else { 0 };
|
|
if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
*zv = val;
|
|
*zv = val;
|
|
}*/
|
|
}*/
|
|
-
|
|
|
|
- if !self.is_zobrist_correct() {
|
|
|
|
- println!("incorrect zobrist after undo {}!", umov.mov.to_string());
|
|
|
|
- let val = if let Some((ref zt, _zv)) = self.zobrist {
|
|
|
|
- self.calculate_zobrist(zt)
|
|
|
|
- } else { 0 };
|
|
|
|
- if let Some((ref _zt, ref mut zv)) = self.zobrist {
|
|
|
|
- *zv = val;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|