use super::{Color, Move, Piece, PieceType, Position, SpecialMoveType};
use std::ops::RangeBounds;
pub fn sq_to_idx(file: char, rank: char) -> usize {
(rank.to_digit(10).unwrap() as usize - 1) * 8 + (file as usize - 97)
}
pub fn idx_to_sq(idx: usize) -> (char, char) {
((idx % 8 + 97) as u8 as char, char::from_digit((idx / 8 + 1) as u32, 10).unwrap())
}
pub fn long_range_can_move(sq: usize, axis_direction: isize) -> bool {
!(axis_direction == 1 && (sq + 1) % 8 == 0
|| axis_direction == -1 && sq % 8 == 0
|| axis_direction == 8 && sq >= 56
|| axis_direction == -8 && sq < 8
|| axis_direction == 7 && (sq >= 56 || sq % 8 == 0)
|| axis_direction == -7 && (sq < 8 || (sq + 1) % 8 == 0)
|| axis_direction == 9 && (sq >= 56 || (sq + 1) % 8 == 0)
|| axis_direction == -9 && (sq < 8 || sq % 8 == 0))
}
pub fn count_piece<R>(rng: R, piece: Piece, content: &[Option<Piece>; 64]) -> usize
where
R: RangeBounds<usize> + Iterator<Item = usize>,
{
find_pieces(piece, rng, content).len()
}
pub fn count_pieces<R>(rng: R, content: &[Option<Piece>; 64]) -> usize
where
R: RangeBounds<usize> + Iterator<Item = usize>,
{
rng.fold(0, |acc, sq| if content[sq].is_some() { acc + 1 } else { acc })
}
pub fn find_pieces<R>(piece: Piece, rng: R, content: &[Option<Piece>; 64]) -> Vec<usize>
where
R: RangeBounds<usize> + Iterator<Item = usize>,
{
let piece = Some(piece);
rng.filter(|&sq| content[sq] == piece).collect()
}
pub fn find_all_pieces<R>(rng: R, content: &[Option<Piece>; 64]) -> Vec<usize>
where
R: RangeBounds<usize> + Iterator<Item = usize>,
{
rng.filter(|&sq| content[sq].is_some()).collect()
}
pub fn king_capture_pseudolegal(content: &[Option<Piece>; 64], side: Color) -> bool {
let enemy_king = find_king(!side, content);
Position {
content: *content,
side,
castling_rights: [None, None, None, None],
ep_target: None,
}
.controls_square(enemy_king, side)
}
pub fn find_king(color: Color, content: &[Option<Piece>; 64]) -> usize {
content
.iter()
.enumerate()
.find(|(_, o)| if let Some(Piece(PieceType::K, s)) = o { *s == color } else { false })
.unwrap()
.0
}
pub fn change_content(content: &[Option<Piece>; 64], move_: &Move, castling_rights: &[Option<usize>]) -> [Option<Piece>; 64] {
let mut content = *content;
let Move(src, dest, spec) = move_;
(content[*src], content[*dest]) = (None, content[*src]);
match spec {
Some(SpecialMoveType::CastlingKingside | SpecialMoveType::CastlingQueenside) => match *dest {
6 => {
let krook = castling_rights[0].unwrap();
(content[krook], content[5]) = (None, content[krook]);
}
2 => {
let qrook = castling_rights[1].unwrap();
(content[qrook], content[3]) = (None, content[qrook]);
}
62 => {
let krook = castling_rights[2].unwrap();
(content[krook], content[61]) = (None, content[krook]);
}
58 => {
let qrook = castling_rights[3].unwrap();
(content[qrook], content[59]) = (None, content[qrook]);
}
_ => panic!("the universe is malfunctioning"),
},
Some(SpecialMoveType::EnPassant) => match dest {
16..=23 => content[dest + 8] = None,
40..=47 => content[dest - 8] = None,
_ => panic!("the universe is malfunctioning"),
},
Some(SpecialMoveType::Promotion(piece_type)) => {
if let Some(Piece(_, color)) = content[*dest] {
content[*dest] = Some(Piece(*piece_type, color));
}
}
_ => (),
}
content
}
pub fn color_complex_of(sq: usize) -> bool {
(match sq {
0..=7 | 16..=23 | 32..=39 | 48..=55 => sq + 1,
_ => sq,
}) % 2
== 0
}
pub fn squares_in_file(file: char) -> Vec<usize> {
let mut vec = Vec::new();
let bottom = sq_to_idx(file, '1');
for i in 0..8 {
vec.push(bottom + 8 * i);
}
vec
}
pub fn squares_in_rank(rank: char) -> Vec<usize> {
let mut vec = Vec::new();
let left = 8 * (rank.to_digit(10).unwrap() as usize - 1);
for i in 0..8 {
vec.push(left + i);
}
vec
}
pub fn as_legal(move_: Move, legal: &[Move]) -> Option<Move> {
if legal.contains(&move_) {
Some(move_)
} else if move_.2 == Some(SpecialMoveType::Unclear) {
match legal.iter().find(|m| (m.0, m.1) == (move_.0, move_.1) && !matches!(m.2, Some(SpecialMoveType::Promotion(_)))) {
Some(&m) => Some(m),
_ => None,
}
} else {
None
}
}