|
@@ -3,6 +3,7 @@ use bitboard::Square;
|
|
use bitboard::*;
|
|
use bitboard::*;
|
|
use game::Game;
|
|
use game::Game;
|
|
use hash::{Cache, EntryType};
|
|
use hash::{Cache, EntryType};
|
|
|
|
+use std::f32::consts::PI;
|
|
use std::iter::Iterator;
|
|
use std::iter::Iterator;
|
|
|
|
|
|
use crate::evaluate::evaluate;
|
|
use crate::evaluate::evaluate;
|
|
@@ -30,11 +31,14 @@ pub struct SimpleMove {
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
+pub struct PieceCaptureType(u8);
|
|
|
|
+
|
|
|
|
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
pub enum Move {
|
|
pub enum Move {
|
|
- Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
|
|
|
|
|
|
+ Default { mov: SimpleMove, pc: PieceCaptureType },
|
|
Castling { side: Side, left: bool },
|
|
Castling { side: Side, left: bool },
|
|
EnPassant { mov: SimpleMove, beaten: Square },
|
|
EnPassant { mov: SimpleMove, beaten: Square },
|
|
- Promotion { mov: SimpleMove, promote_to: PieceType, captured: Option<PieceType> },
|
|
|
|
|
|
+ Promotion { mov: SimpleMove, pc: PieceCaptureType },
|
|
Nullmove
|
|
Nullmove
|
|
}
|
|
}
|
|
|
|
|
|
@@ -47,6 +51,38 @@ pub struct MoveUndo {
|
|
pub mov: Move
|
|
pub mov: Move
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl PieceCaptureType {
|
|
|
|
+
|
|
|
|
+ pub fn new(piece_type: PieceType, capture_type: Option<PieceType>) -> Self {
|
|
|
|
+ if piece_type > KING {
|
|
|
|
+ panic!("ILLEGAL PIECE");
|
|
|
|
+ }
|
|
|
|
+ let upper = piece_type << 4;
|
|
|
|
+ let lower = capture_type.unwrap_or(0xF);
|
|
|
|
+ PieceCaptureType(upper | lower)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn piece_type(&self) -> PieceType {
|
|
|
|
+ (self.0 >> 4) as PieceType
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn capture_type(&self) -> Option<PieceType> {
|
|
|
|
+ let ct = (self.0 & 0xF) as PieceType;
|
|
|
|
+
|
|
|
|
+ if ct == 0xF {
|
|
|
|
+ None
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ Some(ct)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn has_capture(&self) -> bool {
|
|
|
|
+ let ct = (self.0 >> 4) as PieceType;
|
|
|
|
+ ct != 0xF
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
impl Default for Move {
|
|
impl Default for Move {
|
|
fn default() -> Move {
|
|
fn default() -> Move {
|
|
Move::Nullmove
|
|
Move::Nullmove
|
|
@@ -81,7 +117,7 @@ impl Move {
|
|
|
|
|
|
pub fn to_string(&self) -> String {
|
|
pub fn to_string(&self) -> String {
|
|
match self {
|
|
match self {
|
|
- Move::Default{ mov, piece_type: _pt, captured: _c } => {
|
|
|
|
|
|
+ Move::Default{ mov, pc: _} => {
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
},
|
|
},
|
|
Move::Castling{ side, left } => {
|
|
Move::Castling{ side, left } => {
|
|
@@ -103,12 +139,13 @@ impl Move {
|
|
Move::EnPassant{ mov, beaten: _ } => {
|
|
Move::EnPassant{ mov, beaten: _ } => {
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
},
|
|
},
|
|
- Move::Promotion{ mov, promote_to, captured: _c } => {
|
|
|
|
|
|
+ Move::Promotion{ mov, pc } => {
|
|
|
|
+ let promote_to = pc.piece_type();
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
|
|
- if *promote_to == QUEEN { "q" }
|
|
|
|
- else if *promote_to == ROOK { "r" }
|
|
|
|
- else if *promote_to == KNIGHT { "n" }
|
|
|
|
- else if *promote_to == BISHOP { "b" }
|
|
|
|
|
|
+ if promote_to == QUEEN { "q" }
|
|
|
|
+ else if promote_to == ROOK { "r" }
|
|
|
|
+ else if promote_to == KNIGHT { "n" }
|
|
|
|
+ else if promote_to == BISHOP { "b" }
|
|
else { "" }
|
|
else { "" }
|
|
},
|
|
},
|
|
Move::Nullmove => {
|
|
Move::Nullmove => {
|
|
@@ -119,8 +156,8 @@ impl Move {
|
|
|
|
|
|
pub fn is_capture(&self) -> bool {
|
|
pub fn is_capture(&self) -> bool {
|
|
match self {
|
|
match self {
|
|
- Move::Default{ mov: _, piece_type: _, captured: c } => c.is_some(),
|
|
|
|
- Move::Promotion{ mov: _, promote_to: _, captured: c } => c.is_some(),
|
|
|
|
|
|
+ Move::Default{ mov: _, pc } => pc.capture_type().is_some(),
|
|
|
|
+ Move::Promotion{ mov: _, pc } => pc.capture_type().is_some(),
|
|
Move::EnPassant{ mov: _, beaten: _ } => true,
|
|
Move::EnPassant{ mov: _, beaten: _ } => true,
|
|
Move::Castling{ side: _, left: _ } => false,
|
|
Move::Castling{ side: _, left: _ } => false,
|
|
Move::Nullmove => false
|
|
Move::Nullmove => false
|
|
@@ -366,8 +403,8 @@ pub fn generate_legal_moves(game: &mut Game, side: Side, captures_only: bool) ->
|
|
let check_legality = |m: &Move| {
|
|
let check_legality = |m: &Move| {
|
|
if !check {
|
|
if !check {
|
|
match m {
|
|
match m {
|
|
- Move::Default { mov, piece_type: _, captured: _ } |
|
|
|
|
- Move::Promotion { mov, promote_to: _, captured: _ } => {
|
|
|
|
|
|
+ Move::Default { mov, pc: _ } |
|
|
|
|
+ Move::Promotion { mov, pc: _ } => {
|
|
let from = from_square(mov.from);
|
|
let from = from_square(mov.from);
|
|
if from & possible_pins == 0 && from != king {
|
|
if from & possible_pins == 0 && from != king {
|
|
return true;
|
|
return true;
|
|
@@ -476,13 +513,13 @@ fn mvv_lva_score(mov: &Move) -> i32 {
|
|
];
|
|
];
|
|
|
|
|
|
match mov {
|
|
match mov {
|
|
- Move::Default { mov: _, piece_type, captured } => {
|
|
|
|
- let attack = PIECE_VALUES[*piece_type as usize];
|
|
|
|
- let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
|
|
|
|
|
|
+ Move::Default { mov: _, pc } => {
|
|
|
|
+ let attack = PIECE_VALUES[pc.piece_type() as usize];
|
|
|
|
+ let victim = pc.capture_type().map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
|
|
attack - victim * 5
|
|
attack - victim * 5
|
|
},
|
|
},
|
|
- Move::Promotion { mov: _, promote_to: _, captured } => {
|
|
|
|
- let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
|
|
|
|
|
|
+ Move::Promotion { mov: _, pc } => {
|
|
|
|
+ let victim = pc.capture_type().map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
|
|
PIECE_VALUES[PAWN as usize] - victim * 5
|
|
PIECE_VALUES[PAWN as usize] - victim * 5
|
|
},
|
|
},
|
|
_ => 0
|
|
_ => 0
|
|
@@ -521,7 +558,7 @@ fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
WHITE => south_one(p),
|
|
WHITE => south_one(p),
|
|
BLACK => north_one(p)
|
|
BLACK => north_one(p)
|
|
};
|
|
};
|
|
- move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, pc: PieceCaptureType::new(PAWN, None) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -544,7 +581,7 @@ fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>
|
|
WHITE => south_one(south_one(p)),
|
|
WHITE => south_one(south_one(p)),
|
|
BLACK => north_one(north_one(p))
|
|
BLACK => north_one(north_one(p))
|
|
};
|
|
};
|
|
- move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, pc: PieceCaptureType::new(PAWN, None) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -570,12 +607,12 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
let captured = game.find_piece(*cap);
|
|
let captured = game.find_piece(*cap);
|
|
let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
|
|
let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
|
|
if cap & promotion_mask != 0 {
|
|
if cap & promotion_mask != 0 {
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN, captured: captured });
|
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK, captured: captured });
|
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP, captured: captured });
|
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT, captured: captured });
|
|
|
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(QUEEN, captured) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(KNIGHT, captured) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(ROOK, captured) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(BISHOP, captured) });
|
|
} else {
|
|
} else {
|
|
- move_list.push(Move::Default { mov: simple_move, piece_type: PAWN, captured: captured });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: simple_move, pc: PieceCaptureType::new(PAWN, captured) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -601,10 +638,10 @@ fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
};
|
|
};
|
|
let movement = SimpleMove { from: square(origin), to: square(p) };
|
|
let movement = SimpleMove { from: square(origin), to: square(p) };
|
|
//move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
|
|
//move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN, captured: None });
|
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: ROOK, captured: None });
|
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP, captured: None });
|
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT, captured: None });
|
|
|
|
|
|
+ move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(QUEEN, None) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(KNIGHT, None) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(ROOK, None) });
|
|
|
|
+ move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(BISHOP, None) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -657,12 +694,12 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
|
|
for target in cap_targets {
|
|
for target in cap_targets {
|
|
let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
let captured = game.find_piece(target);
|
|
let captured = game.find_piece(target);
|
|
- move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });
|
|
|
|
|
|
+ move_list.push(Move::Default{ mov: simple_move, pc: PieceCaptureType::new(KNIGHT, captured) });
|
|
}
|
|
}
|
|
if !captures_only {
|
|
if !captures_only {
|
|
for target in nocap_targets {
|
|
for target in nocap_targets {
|
|
let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
- move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured: None });
|
|
|
|
|
|
+ move_list.push(Move::Default{ mov: simple_move, pc: PieceCaptureType::new(KNIGHT, None) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -740,10 +777,10 @@ fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, piec
|
|
for dest in dest_iter {
|
|
for dest in dest_iter {
|
|
let smove = SimpleMove{ from: square(piece), to: square(dest) };
|
|
let smove = SimpleMove{ from: square(piece), to: square(dest) };
|
|
if dest & others != 0 {
|
|
if dest & others != 0 {
|
|
- move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: game.find_piece(dest) });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: smove, pc: PieceCaptureType::new(piece_type, game.find_piece(dest)) });
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: None });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: smove, pc: PieceCaptureType::new(piece_type, None) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -818,7 +855,7 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captu
|
|
for destination in area_iter {
|
|
for destination in area_iter {
|
|
let simple_move = SimpleMove{ from: square(king), to: square(destination) };
|
|
let simple_move = SimpleMove{ from: square(king), to: square(destination) };
|
|
let captured = game.find_piece(destination);
|
|
let captured = game.find_piece(destination);
|
|
- move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
|
|
|
|
|
|
+ move_list.push(Move::Default { mov: simple_move, pc: PieceCaptureType::new(KING, captured) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|