1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! A simple Move representation - a turn which moves a piece on a chessboard
use crate::flag::{Flag, FlagCheck};
use crate::parser;
use crate::piece::Piece;
use crate::square::Square;
use std::fmt;
/// # Move turn
///
/// `Move` struct represents any chess turn in which piece is moved from *square
/// A* to *square B*, with some additional information.
///
/// `Move` can represent any chess turn expect for castling. Castling is
/// described separately within 'Castling' struct.
///
/// ## Example
/// ```
/// use chess_notation_parser::{Turn, Move, Square, Piece, Flag};
///
/// let turn = Turn::Move(
/// Move {
/// who: Piece::Pawn,
/// dst: Square::C3,
/// flags: Flag::NONE,
/// src: None,
/// promotion: None,
/// }
/// );
/// assert_eq!(turn, Turn::try_from("c3").unwrap());
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Move {
/// The piece which is moving from *square A* to *square B*
pub who: Piece,
/// Destination square (*square B*)
pub dst: Square,
/// Extra bits of information stored in a bitmask about the turn, check
/// `Flag` for more info
pub flags: u8,
/// Description of a *square A*
/// - Can be a specific square
/// - Can be a rank or a file. In that case it is a set of 8 squares
/// - Can be `None` when `src` doesn't need to be provided
pub src: Option<Vec<Square>>,
/// The `Piece` to which pawns are promoted to
pub promotion: Option<Piece>,
}
impl Move {
fn constuct_src_string(src: &Vec<Square>) -> String {
match src.len() {
1 => return src[0].to_string(),
8 => (),
_ => panic!("'Source' should contain a set of 8 ranks/files"),
}
// Get rank/file chars for the first square
let (file, rank) = {
let s = src[0].to_string();
let mut square_chars = s.chars();
(square_chars.next().unwrap(), square_chars.next().unwrap())
};
// Return whatever rank/file the second square can match
match src[1].to_string().contains(file) {
true => String::from(file),
false => String::from(rank),
}
}
}
impl FlagCheck for Move {
fn get_flags(&self) -> u8 {
self.flags
}
}
impl fmt::Display for Move {
// Stringification goes in this order:
// <who><src><capture><dst><promotion><check/checkmate>
//
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// This capacity should be more than enough
let mut s = String::with_capacity(16);
// Pawns are not annotated in chess notation
if self.who != Piece::Pawn {
s.push(parser::get_piece_char(self.who));
}
// Append source if any
if let Some(ref src) = self.src {
s.push_str(Self::constuct_src_string(src).as_str());
}
if self.check_flag(Flag::CAPTURE) {
s.push('x');
}
s.push_str(self.dst.to_string().as_str());
if let Some(promotion_piece) = self.promotion {
s.push('=');
s.push(parser::get_piece_char(promotion_piece));
}
if self.check_flag(Flag::CHECK) {
s.push('+');
} else if self.check_flag(Flag::CHECKMATE) {
s.push('#');
}
write!(f, "{}", s)
}
}