wip
This commit is contained in:
parent
bcd5a3182a
commit
bf6cc961dc
3 changed files with 122 additions and 86 deletions
173
src/board.rs
173
src/board.rs
|
|
@ -3,28 +3,31 @@
|
||||||
use crate::bitboard::*;
|
use crate::bitboard::*;
|
||||||
|
|
||||||
macro_rules! container {
|
macro_rules! container {
|
||||||
($a:ident, $b:ident, $n:literal) => {
|
($v:vis, $a:ident, $b:ident, $n:literal) => {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub(crate) struct $b<T>(pub(crate) [T; $n]);
|
$v struct $b<T>(pub(crate) [T; $n]);
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
impl<T> $b<T> {
|
impl<T> $b<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<F>(f: F) -> Self
|
pub const fn new(values: [T; $n]) -> Self {
|
||||||
|
Self(values)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with<F>(f: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut($a) -> T,
|
F: FnMut($a) -> T,
|
||||||
{
|
{
|
||||||
Self($a::all().map(f))
|
Self($a::all().map(f))
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, k: $a) -> &T {
|
pub const fn get(&self, k: $a) -> &T {
|
||||||
unsafe { self.0.get_unchecked(k as usize) }
|
// unsafe { self.0.get_unchecked(k as usize) }
|
||||||
|
&self.0[k as usize]
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut(&mut self, k: $a) -> &mut T {
|
pub const fn get_mut(&mut self, k: $a) -> &mut T {
|
||||||
unsafe { self.0.get_unchecked_mut(k as usize) }
|
// unsafe { self.0.get_unchecked_mut(k as usize) }
|
||||||
}
|
&mut self.0[k as usize]
|
||||||
pub(crate) const fn get_const(&self, k: $a) -> &T {
|
|
||||||
&self.0[k as usize]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -38,11 +41,11 @@ pub enum Color {
|
||||||
Black,
|
Black,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(Color, ByColor, 2);
|
container!(pub, Color, ByColor, 2);
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn all() -> [Self; 2] {
|
pub const fn all() -> [Self; 2] {
|
||||||
[Self::White, Self::Black]
|
[Self::White, Self::Black]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,11 +99,11 @@ pub enum File {
|
||||||
H,
|
H,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(File, ByFile, 8);
|
container!(pub(crate), File, ByFile, 8);
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn all() -> [Self; 8] {
|
pub const fn all() -> [Self; 8] {
|
||||||
[
|
[
|
||||||
Self::A,
|
Self::A,
|
||||||
Self::B,
|
Self::B,
|
||||||
|
|
@ -114,7 +117,35 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_char(self) -> char {
|
pub const fn new(_index: u8) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const unsafe fn new_unchecked(index: u8) -> Self {
|
||||||
|
debug_assert!(index < 8);
|
||||||
|
std::mem::transmute(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_ascii(self) -> u8 {
|
||||||
|
self as u8 + b'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_ascii(c: u8) -> Option<Self> {
|
||||||
|
if c <= b'h' {
|
||||||
|
match c.checked_sub(b'a') {
|
||||||
|
Some(i) => Some(unsafe { Self::new_unchecked(i) }),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_char(self) -> char {
|
||||||
self.to_ascii() as char
|
self.to_ascii() as char
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,28 +154,10 @@ impl File {
|
||||||
u8::try_from(file).ok().and_then(Self::from_ascii)
|
u8::try_from(file).ok().and_then(Self::from_ascii)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn to_ascii(self) -> u8 {
|
|
||||||
self as u8 + b'a'
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn from_ascii(c: u8) -> Option<Self> {
|
|
||||||
(c <= b'h')
|
|
||||||
.then(|| c.checked_sub(b'a').map(|i| unsafe { Self::transmute(i) }))
|
|
||||||
.flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) const fn bitboard(self) -> Bitboard {
|
pub(crate) const fn bitboard(self) -> Bitboard {
|
||||||
Bitboard(0x0101010101010101 << (self as u8))
|
Bitboard(0x0101010101010101 << (self as u8))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) const unsafe fn transmute(value: u8) -> Self {
|
|
||||||
debug_assert!(value < 8);
|
|
||||||
std::mem::transmute(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for File {
|
impl std::fmt::Display for File {
|
||||||
|
|
@ -168,11 +181,11 @@ pub enum Rank {
|
||||||
Eighth,
|
Eighth,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(Rank, ByRank, 8);
|
container!(pub(crate), Rank, ByRank, 8);
|
||||||
|
|
||||||
impl Rank {
|
impl Rank {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn all() -> [Self; 8] {
|
pub const fn all() -> [Self; 8] {
|
||||||
[
|
[
|
||||||
Self::First,
|
Self::First,
|
||||||
Self::Second,
|
Self::Second,
|
||||||
|
|
@ -186,7 +199,35 @@ impl Rank {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_char(self) -> char {
|
pub const fn new(_index: u8) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const unsafe fn new_unchecked(index: u8) -> Self {
|
||||||
|
debug_assert!(index < 8);
|
||||||
|
std::mem::transmute(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_ascii(self) -> u8 {
|
||||||
|
self as u8 + b'1'
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_ascii(c: u8) -> Option<Self> {
|
||||||
|
if c <= b'8' {
|
||||||
|
match c.checked_sub(b'1') {
|
||||||
|
Some(i) => Some(unsafe { Self::new_unchecked(i) }),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_char(self) -> char {
|
||||||
self.to_ascii() as char
|
self.to_ascii() as char
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,32 +237,14 @@ impl Rank {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mirror(self) -> Self {
|
pub const fn mirror(self) -> Self {
|
||||||
unsafe { Self::transmute(!(self as u8)) }
|
unsafe { Self::new_unchecked(!(self as u8)) }
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn to_ascii(self) -> u8 {
|
|
||||||
self as u8 + b'1'
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn from_ascii(c: u8) -> Option<Self> {
|
|
||||||
(c <= b'8')
|
|
||||||
.then(|| c.checked_sub(b'1').map(|i| unsafe { Self::transmute(i) }))
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) const fn bitboard(self) -> Bitboard {
|
pub(crate) const fn bitboard(self) -> Bitboard {
|
||||||
Bitboard(0xFF << ((self as u64) << 3))
|
Bitboard(0xFF << ((self as u64) << 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) const unsafe fn transmute(value: u8) -> Self {
|
|
||||||
debug_assert!(value < 8);
|
|
||||||
std::mem::transmute(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Rank {
|
impl std::fmt::Display for Rank {
|
||||||
|
|
@ -246,12 +269,12 @@ pub enum Square{
|
||||||
A8, B8, C8, D8, E8, F8, G8, H8,
|
A8, B8, C8, D8, E8, F8, G8, H8,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(Square, BySquare, 64);
|
container!(pub, Square, BySquare, 64);
|
||||||
|
|
||||||
impl Square {
|
impl Square {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn all() -> [Self; 64] {
|
pub const fn all() -> [Self; 64] {
|
||||||
[
|
[
|
||||||
Self::A1, Self::B1, Self::C1, Self::D1, Self::E1, Self::F1, Self::G1, Self::H1,
|
Self::A1, Self::B1, Self::C1, Self::D1, Self::E1, Self::F1, Self::G1, Self::H1,
|
||||||
Self::A2, Self::B2, Self::C2, Self::D2, Self::E2, Self::F2, Self::G2, Self::H2,
|
Self::A2, Self::B2, Self::C2, Self::D2, Self::E2, Self::F2, Self::G2, Self::H2,
|
||||||
|
|
@ -282,22 +305,22 @@ impl Square {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_coords(file: File, rank: Rank) -> Self {
|
pub const fn from_coords(file: File, rank: Rank) -> Self {
|
||||||
unsafe { Self::new_unchecked(((rank as u8) << 3) | file as u8) }
|
unsafe { Self::new_unchecked(((rank as u8) << 3) | file as u8) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn file(self) -> File {
|
pub const fn file(self) -> File {
|
||||||
unsafe { File::transmute((self as u8) & 7) }
|
unsafe { File::new_unchecked((self as u8) & 7) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn rank(self) -> Rank {
|
pub const fn rank(self) -> Rank {
|
||||||
unsafe { Rank::transmute((self as u8) >> 3) }
|
unsafe { Rank::new_unchecked((self as u8) >> 3) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mirror(self) -> Self {
|
pub const fn mirror(self) -> Self {
|
||||||
let sq = self as u8;
|
let sq = self as u8;
|
||||||
unsafe { Self::new_unchecked(sq & 0b000111 | (!sq & 0b111000)) }
|
unsafe { Self::new_unchecked(sq & 0b000111 | (!sq & 0b111000)) }
|
||||||
}
|
}
|
||||||
|
|
@ -465,7 +488,7 @@ pub enum Role {
|
||||||
|
|
||||||
impl Role {
|
impl Role {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn all() -> [Self; 6] {
|
pub const fn all() -> [Self; 6] {
|
||||||
[
|
[
|
||||||
Self::Pawn,
|
Self::Pawn,
|
||||||
Self::Knight,
|
Self::Knight,
|
||||||
|
|
@ -525,7 +548,7 @@ pub(crate) struct ByRole<T>(pub(crate) [T; 6]);
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
impl<T> ByRole<T> {
|
impl<T> ByRole<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<F>(f: F) -> Self
|
pub fn with<F>(f: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(Role) -> T,
|
F: FnMut(Role) -> T,
|
||||||
{
|
{
|
||||||
|
|
@ -533,13 +556,23 @@ impl<T> ByRole<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, kind: Role) -> &T {
|
pub const fn new(values: [T; 6]) -> Self {
|
||||||
unsafe { self.0.get_unchecked((kind as usize).unchecked_sub(1)) }
|
Self(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut(&mut self, kind: Role) -> &mut T {
|
pub const fn get(&self, kind: Role) -> &T {
|
||||||
unsafe { self.0.get_unchecked_mut((kind as usize).unchecked_sub(1)) }
|
// unsafe { self.0.get_unchecked((kind as usize).unchecked_sub(1)) }
|
||||||
|
let i = unsafe { (kind as usize).unchecked_sub(1) };
|
||||||
|
unsafe { std::hint::assert_unchecked(i < 6) };
|
||||||
|
&self.0[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn get_mut(&mut self, kind: Role) -> &mut T {
|
||||||
|
let i = unsafe { (kind as usize).unchecked_sub(1) };
|
||||||
|
unsafe { std::hint::assert_unchecked(i < 6) };
|
||||||
|
&mut self.0[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -593,7 +626,7 @@ pub(crate) enum Direction {
|
||||||
West,
|
West,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(Direction, ByDirection, 8);
|
container!(pub(crate), Direction, ByDirection, 8);
|
||||||
|
|
||||||
impl Direction {
|
impl Direction {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -644,7 +677,7 @@ pub enum CastlingSide {
|
||||||
Long,
|
Long,
|
||||||
}
|
}
|
||||||
|
|
||||||
container!(CastlingSide, ByCastlingSide, 2);
|
container!(pub(crate), CastlingSide, ByCastlingSide, 2);
|
||||||
|
|
||||||
impl CastlingSide {
|
impl CastlingSide {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ static LINES: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard(0)
|
||||||
by_square!(b, Bitboard(0), {
|
by_square!(b, Bitboard(0), {
|
||||||
let mut res = Bitboard(0);
|
let mut res = Bitboard(0);
|
||||||
loop_all_directions!(d, {
|
loop_all_directions!(d, {
|
||||||
let r = *RAYS.get_const(a).get_const(d);
|
let r = *RAYS.get(a).get(d);
|
||||||
if r.contains(b) {
|
if r.contains(b) {
|
||||||
res = r;
|
res = r;
|
||||||
}
|
}
|
||||||
|
|
@ -140,9 +140,9 @@ static SEGMENTS: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard
|
||||||
by_square!(b, Bitboard(0), {
|
by_square!(b, Bitboard(0), {
|
||||||
let mut res = 0;
|
let mut res = 0;
|
||||||
loop_all_directions!(d, {
|
loop_all_directions!(d, {
|
||||||
let r = *RAYS.get_const(a).get_const(d);
|
let r = *RAYS.get(a).get(d);
|
||||||
if r.contains(b) {
|
if r.contains(b) {
|
||||||
res = r.0 & !RAYS.get_const(b).get_const(d).0;
|
res = r.0 & !RAYS.get(b).get(d).0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Bitboard(res | b.bitboard().0)
|
Bitboard(res | b.bitboard().0)
|
||||||
|
|
@ -218,7 +218,7 @@ static PAWN_ATTACKS: ByColor<BySquare<Bitboard>> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -> Bitboard {
|
const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -> Bitboard {
|
||||||
let ray = *RAYS.get_const(square).get_const(direction);
|
let ray = *RAYS.get(square).get(direction);
|
||||||
let blockers = Bitboard(blockers.0 & ray.0);
|
let blockers = Bitboard(blockers.0 & ray.0);
|
||||||
let square = if (direction as u8) < 4 {
|
let square = if (direction as u8) < 4 {
|
||||||
Bitboard::first(&blockers)
|
Bitboard::first(&blockers)
|
||||||
|
|
@ -227,7 +227,7 @@ const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -
|
||||||
};
|
};
|
||||||
match square {
|
match square {
|
||||||
None => ray,
|
None => ray,
|
||||||
Some(square) => Bitboard(ray.0 & !RAYS.get_const(square).get_const(direction).0),
|
Some(square) => Bitboard(ray.0 & !RAYS.get(square).get(direction).0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +259,7 @@ pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard {
|
||||||
const fn bishop_premask(square: Square) -> Bitboard {
|
const fn bishop_premask(square: Square) -> Bitboard {
|
||||||
let mut premask = 0;
|
let mut premask = 0;
|
||||||
loop_bishop_directions!(direction, {
|
loop_bishop_directions!(direction, {
|
||||||
premask |= RAYS.get_const(square).get_const(direction).0;
|
premask |= RAYS.get(square).get(direction).0;
|
||||||
});
|
});
|
||||||
premask &= !Rank::First.bitboard().0;
|
premask &= !Rank::First.bitboard().0;
|
||||||
premask &= !Rank::Eighth.bitboard().0;
|
premask &= !Rank::Eighth.bitboard().0;
|
||||||
|
|
@ -269,12 +269,12 @@ const fn bishop_premask(square: Square) -> Bitboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn rook_premask(square: Square) -> Bitboard {
|
const fn rook_premask(square: Square) -> Bitboard {
|
||||||
let rays = RAYS.get_const(square);
|
let rays = RAYS.get(square);
|
||||||
let mut premask = 0;
|
let mut premask = 0;
|
||||||
premask |= rays.get_const(Direction::East).0 & !File::H.bitboard().0;
|
premask |= rays.get(Direction::East).0 & !File::H.bitboard().0;
|
||||||
premask |= rays.get_const(Direction::North).0 & !Rank::Eighth.bitboard().0;
|
premask |= rays.get(Direction::North).0 & !Rank::Eighth.bitboard().0;
|
||||||
premask |= rays.get_const(Direction::West).0 & !File::A.bitboard().0;
|
premask |= rays.get(Direction::West).0 & !File::A.bitboard().0;
|
||||||
premask |= rays.get_const(Direction::South).0 & !Rank::First.bitboard().0;
|
premask |= rays.get(Direction::South).0 & !Rank::First.bitboard().0;
|
||||||
Bitboard(premask)
|
Bitboard(premask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,7 +360,7 @@ static MAGIC_TABLE: [Bitboard; MAGICS.2] = {
|
||||||
premask,
|
premask,
|
||||||
factor,
|
factor,
|
||||||
offset,
|
offset,
|
||||||
} = *MAGICS.0.get_const(square);
|
} = *MAGICS.0.get(square);
|
||||||
let premask = !premask.0;
|
let premask = !premask.0;
|
||||||
loop_subsets!(premask, blockers, {
|
loop_subsets!(premask, blockers, {
|
||||||
let index = (hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize + offset)
|
let index = (hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize + offset)
|
||||||
|
|
@ -378,7 +378,7 @@ static MAGIC_TABLE: [Bitboard; MAGICS.2] = {
|
||||||
premask,
|
premask,
|
||||||
factor,
|
factor,
|
||||||
offset,
|
offset,
|
||||||
} = *MAGICS.1.get_const(square);
|
} = *MAGICS.1.get(square);
|
||||||
let premask = !premask.0;
|
let premask = !premask.0;
|
||||||
loop_subsets!(premask, blockers, {
|
loop_subsets!(premask, blockers, {
|
||||||
let index =
|
let index =
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,10 @@ impl Setup {
|
||||||
(file < 8).then_some(())?;
|
(file < 8).then_some(())?;
|
||||||
setup.set(
|
setup.set(
|
||||||
unsafe {
|
unsafe {
|
||||||
Square::from_coords(File::transmute(file), Rank::transmute(rank))
|
Square::from_coords(
|
||||||
|
File::new_unchecked(file),
|
||||||
|
Rank::new_unchecked(rank),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
Some(Piece { role, color }),
|
Some(Piece { role, color }),
|
||||||
);
|
);
|
||||||
|
|
@ -495,12 +498,12 @@ impl Setup {
|
||||||
let n = n_b_k ^ b ^ k;
|
let n = n_b_k ^ b ^ k;
|
||||||
let r = r_q_k ^ q ^ k;
|
let r = r_q_k ^ q ^ k;
|
||||||
let p = p_b_q ^ b ^ q;
|
let p = p_b_q ^ b ^ q;
|
||||||
ByColor::new(|color| {
|
ByColor::with(|color| {
|
||||||
let mask = match color {
|
let mask = match color {
|
||||||
Color::White => w,
|
Color::White => w,
|
||||||
Color::Black => !w,
|
Color::Black => !w,
|
||||||
};
|
};
|
||||||
ByRole::new(|kind| {
|
ByRole::with(|kind| {
|
||||||
mask & match kind {
|
mask & match kind {
|
||||||
Role::Pawn => p,
|
Role::Pawn => p,
|
||||||
Role::Knight => n,
|
Role::Knight => n,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue