eschac 0.6.1

computing chess moves
Documentation
use crate::bitboard::*;
use crate::board::*;

pub(crate) const BISHOP_SHR: u8 = 55;
pub(crate) const ROOK_SHR: u8 = 52;

#[inline]
pub const fn hash(shr: u8, factor: u64, x: Bitboard) -> usize {
	(x.0.wrapping_mul(factor) >> shr) as usize
}

macro_rules! by_square {
    ($sq:ident, $init:expr, $e:expr) => {{
        let mut res = [$init; 64];
        let mut $sq: u8 = 0;
        while $sq < 64 {
            res[$sq as usize] = {
                let $sq = Square::new($sq).unwrap();
                $e
            };
            $sq += 1;
        }
        BySquare(res)
    }};
}

macro_rules! loop_bishop_directions {
	($d:ident, $e:expr) => {{
		{
			let $d = Direction::NorthEast;
			$e
		}
		{
			let $d = Direction::NorthWest;
			$e
		}
		{
			let $d = Direction::SouthWest;
			$e
		}
		{
			let $d = Direction::SouthEast;
			$e
		}
	}};
}

macro_rules! loop_rook_directions {
	($d:ident, $e:expr) => {{
		{
			let $d = Direction::East;
			$e
		}
		{
			let $d = Direction::North;
			$e
		}
		{
			let $d = Direction::West;
			$e
		}
		{
			let $d = Direction::South;
			$e
		}
	}};
}

macro_rules! loop_all_directions {
	($d:ident, $e:expr) => {{
		loop_bishop_directions!($d, $e);
		loop_rook_directions!($d, $e);
	}};
}

macro_rules! by_direction {
    ($d:ident, $e:expr) => {{
        let mut res = [Bitboard(0); 8];
        let mut $d: u8 = 0;
        while $d < 8 {
            res[$d as usize] = {
                let $d = Direction::new($d).unwrap();
                $e
            };
            $d += 1;
        }
        ByDirection(res)
    }};
}

#[inline]
pub(crate) const fn ray(square: Square, direction: Direction) -> Bitboard {
	static DATA: BySquare<ByDirection<Bitboard>> = by_square!(
		square,
		ByDirection([Bitboard(0); 8]),
		by_direction!(direction, {
			let mut square = square;
			let mut res = 0;
			while let Some(x) = square.trans(direction) {
				square = x;
				res |= square.bitboard().0;
			}
			Bitboard(res)
		})
	);
	*DATA.get(square).get(direction)
}

#[inline]
pub(crate) const fn line(a: Square, b: Square) -> Bitboard {
	static DATA: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard(0); 64]), {
		by_square!(b, Bitboard(0), {
			let mut res = Bitboard(0);
			loop_all_directions!(d, {
				let r = ray(a, d);
				if r.contains(b) {
					res = r;
				}
			});
			res
		})
	});
	*DATA.get(a).get(b)
}

#[inline]
pub(crate) const fn segment(a: Square, b: Square) -> Bitboard {
	static DATA: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard(0); 64]), {
		by_square!(b, Bitboard(0), {
			let mut res = 0;
			loop_all_directions!(d, {
				let r = ray(a, d);
				if r.contains(b) {
					res = r.0 & !ray(b, d).0;
				}
			});
			Bitboard(res | b.bitboard().0)
		})
	});
	*DATA.get(a).get(b)
}

#[inline]
pub(crate) const fn bishop_lines(square: Square) -> Bitboard {
	static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
		let mut res = 0;
		loop_bishop_directions!(d, {
			res |= ray(sq, d).0;
		});
		Bitboard(res)
	});
	*DATA.get(square)
}

#[inline]
pub(crate) const fn rook_lines(square: Square) -> Bitboard {
	static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
		let mut res = 0;
		loop_rook_directions!(d, {
			res |= ray(sq, d).0;
		});
		Bitboard(res)
	});
	*DATA.get(square)
}

#[inline]
pub(crate) const fn king(square: Square) -> Bitboard {
	static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
		let mut res = 0;
		loop_all_directions!(d, {
			if let Some(x) = sq.trans(d) {
				res |= x.bitboard().0;
			}
		});
		Bitboard(res)
	});
	*DATA.get(square)
}

#[inline]
pub(crate) const fn knight(square: Square) -> Bitboard {
	static DATA: BySquare<Bitboard> = by_square!(s, Bitboard(0), {
		let mut res = Bitboard(0);
		if let Some(s) = s.trans(Direction::North) {
			if let Some(s) = s.trans(Direction::NorthEast) {
				res.insert(s);
			}
			if let Some(s) = s.trans(Direction::NorthWest) {
				res.insert(s)
			};
		}
		if let Some(s) = s.trans(Direction::West) {
			if let Some(s) = s.trans(Direction::NorthWest) {
				res.insert(s)
			};
			if let Some(s) = s.trans(Direction::SouthWest) {
				res.insert(s)
			};
		}
		if let Some(s) = s.trans(Direction::South) {
			if let Some(s) = s.trans(Direction::SouthWest) {
				res.insert(s)
			};
			if let Some(s) = s.trans(Direction::SouthEast) {
				res.insert(s)
			};
		}
		if let Some(s) = s.trans(Direction::East) {
			if let Some(s) = s.trans(Direction::SouthEast) {
				res.insert(s)
			};
			if let Some(s) = s.trans(Direction::NorthEast) {
				res.insert(s)
			};
		}
		res
	});
	*DATA.get(square)
}

#[inline]
pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard {
	let m = square.bitboard().trans(color.forward());
	m.trans(Direction::East) | m.trans(Direction::West)
}