use crate::board::Board;
use crate::movegen::{legal, semilegal, MoveList};
use crate::moves::{self, Move, MoveKind, Style};
use crate::types::{Cell, Coord, Piece};
#[derive(Debug, Eq)]
struct BoardFullEq<'a>(&'a Board);
impl<'a> PartialEq for BoardFullEq<'a> {
#[inline]
fn eq(&self, other: &BoardFullEq<'a>) -> bool {
return self.0.r == other.0.r
&& self.0.hash == other.0.hash
&& self.0.white == other.0.white
&& self.0.black == other.0.black
&& self.0.all == other.0.all
&& self.0.pieces == other.0.pieces;
}
}
fn test_board_valid(b: &Board) {
let b_other = b.raw().try_into().unwrap();
assert_eq!(BoardFullEq(&b_other), BoardFullEq(b));
}
fn move_key(m: &Move) -> (u8, u8, u8, u8) {
(
m.kind() as u8,
m.src_cell().index() as u8,
m.src().index() as u8,
m.dst().index() as u8,
)
}
pub fn selftest(b: &Board) {
test_board_valid(b);
let fen = b.as_fen();
assert_eq!(Board::from_fen(&fen).as_ref(), Ok(b));
let mut moves = semilegal::gen_all(b);
moves.sort_by_key(move_key);
let mut moves_simple = semilegal::gen_simple(b);
moves_simple.sort_by_key(move_key);
let mut moves2 = semilegal::gen_simple_no_promote(b);
semilegal::gen_simple_promote_into(b, &mut moves2);
moves2.sort_by_key(move_key);
assert_eq!(moves_simple, moves2);
semilegal::gen_capture_into(b, &mut moves2);
moves2.sort_by_key(move_key);
assert_eq!(moves, moves2);
for mv in &moves {
assert!(mv.is_well_formed());
}
for mv in &moves {
assert_eq!(Move::from_uci(&mv.to_string(), b), Ok(*mv));
}
let mut semilegals = MoveList::new();
for kind in [
MoveKind::Simple,
MoveKind::CastlingKingside,
MoveKind::CastlingQueenside,
MoveKind::PawnDouble,
MoveKind::Enpassant,
MoveKind::PromoteKnight,
MoveKind::PromoteBishop,
MoveKind::PromoteRook,
MoveKind::PromoteQueen,
] {
for piece in Piece::iter() {
if !kind.matches_piece(piece) {
continue;
}
for src in Coord::iter() {
for dst in Coord::iter() {
if let Ok(mv) = Move::new(kind, Cell::from_parts(b.side(), piece), src, dst) {
if mv.semi_validate(b).is_ok() {
semilegals.push(mv);
}
}
}
}
}
}
semilegals.sort_by_key(move_key);
assert_eq!(moves, semilegals);
let mut legals1 = MoveList::new();
let mut b_clone = b.clone();
for mv in &moves {
unsafe {
let undo = moves::make_move_unchecked(&mut b_clone, *mv);
if !b_clone.is_opponent_king_attacked() {
test_board_valid(&b_clone);
legals1.push(*mv);
}
moves::unmake_move_unchecked(&mut b_clone, *mv, undo);
}
assert_eq!(&b_clone, b);
}
legals1.sort_by_key(move_key);
let mut legals2 = moves;
legals2.retain(|mv| unsafe { mv.is_legal_unchecked(b) });
legals2.sort_by_key(move_key);
let mut legals3 = legal::gen_all(b);
legals3.sort_by_key(move_key);
assert_eq!(legals1, legals2);
assert_eq!(legals1, legals3);
for mv in &legals1 {
assert_eq!(
Move::from_san(&mv.styled(b, Style::San).unwrap().to_string(), b),
Ok(*mv),
);
}
for mv in &legals1 {
assert_eq!(mv.src_cell(), b.get(mv.src()));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::board::Board;
#[test]
fn test_simple() {
selftest(&Board::initial());
selftest(
&Board::from_fen("r1bqk1nr/pppp1ppp/2n5/2b1p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4")
.unwrap(),
)
}
}