///|
/// The shape of a move, which the board alone cannot infer.
pub(all) enum MoveKind {
/// A quiet move or an ordinary capture.
Normal
/// A two square pawn advance, which sets the en passant target.
DoublePawnPush
/// A pawn captures a pawn that has just advanced two squares.
EnPassant
/// The king moves from e1 to g1, or from e8 to g8.
CastleKingside
/// The king moves from e1 to c1, or from e8 to c8.
CastleQueenside
/// A pawn reaches the last rank and becomes a queen, rook, bishop or
/// knight.
Promotion
} derive(Eq, @debug.Debug)
///|
pub extend MoveKind with Eq::{equal, not_equal}
///|
pub extend MoveKind with @debug.Debug::{to_repr}
///|
pub extend MoveKind with Show::{to_string, output}
///|
pub impl Show for MoveKind with fn output(self, logger) {
logger.write_string(MoveKind::name(self))
}
///|
/// The lower-case name of the move shape.
pub fn MoveKind::name(self : MoveKind) -> String {
match self {
Normal => "normal"
DoublePawnPush => "double pawn push"
EnPassant => "en passant"
CastleKingside => "castle kingside"
CastleQueenside => "castle queenside"
Promotion => "promotion"
}
}
///|
/// A move between two squares.
///
/// The fields are public because move generation touches them in tight
/// loops. `promotion` is `Some` exactly when `kind` is `Promotion`.
pub(all) struct Move {
from : Square
to : Square
kind : MoveKind
promotion : PieceKind?
} derive(Eq, @debug.Debug)
///|
pub extend Move with Eq::{equal, not_equal}
///|
pub extend Move with @debug.Debug::{to_repr}
///|
pub extend Move with Show::{to_string, output}
///|
pub impl Show for Move with fn output(self, logger) {
logger.write_string(Move::to_uci(self))
}
///|
/// Builds a quiet move or an ordinary capture.
pub fn Move::new(from : Square, to : Square) -> Move {
{ from, to, kind: Normal, promotion: None, }
}
///|
/// Builds a two square pawn advance.
pub fn Move::double_push(from : Square, to : Square) -> Move {
{ from, to, kind: DoublePawnPush, promotion: None, }
}
///|
/// Builds an en passant capture into the empty square behind the pawn.
pub fn Move::en_passant(from : Square, to : Square) -> Move {
{ from, to, kind: EnPassant, promotion: None, }
}
///|
/// Builds a king, rook, bishop or queen promotion.
pub fn Move::promotion(from : Square, to : Square, piece : PieceKind) -> Move {
{ from, to, kind: Promotion, promotion: Some(piece), }
}
///|
/// Builds the king move of a castling.
pub fn Move::castle(color : Color, kingside : Bool) -> Move {
let rank = if color == White { 0 } else { 7 }
let from = Square::make(4, rank)
let to = Square::make(if kingside { 6 } else { 2 }, rank)
{
from,
to,
kind: if kingside {
CastleKingside
} else {
CastleQueenside
},
promotion: None,
}
}
///|
/// The promotion piece, or `None` for a move that does not promote.
pub fn Move::promotion_piece(self : Move) -> PieceKind? {
self.promotion
}
///|
/// Whether the move promotes.
pub fn Move::is_promotion(self : Move) -> Bool {
self.kind == Promotion
}
///|
/// Whether the move captures something, directly or in passing.
pub fn Move::is_capture(self : Move, position : Position) -> Bool {
match self.kind {
EnPassant => true
_ =>
match position.piece_at(self.to) {
Some(_) => true
None => false
}
}
}
///|
/// Whether the move castles.
pub fn Move::is_castling(self : Move) -> Bool {
self.kind == CastleKingside || self.kind == CastleQueenside
}
///|
/// The move in UCI notation, for example `e2e4` or `e7e8q`.
///
/// Castling is written as the king move, which is what UCI sends.
pub fn Move::to_uci(self : Move) -> String {
let buf = StringBuilder()
buf.write_string(self.from.to_string())
buf.write_string(self.to.to_string())
match self.promotion {
Some(kind) => buf.write_char(kind.fen_char())
None => ()
}
buf.to_string()
}