use std::{
fmt::{self, Display, Formatter},
io::{Error, ErrorKind},
};
use console::style;
use shakmaty::{uci::Uci, Board, Color, Role, Square};
#[derive(Debug)]
pub struct PageBounds {
pub pad: i32,
pub low: i32,
pub high: i32,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ByteBoard {
pub bytes: [u8; 64],
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Ord)]
#[repr(u8)]
pub enum Nag {
Null,
Good,
Mistake,
Hard,
Blunder,
Interesting,
Dubious,
Forced,
Only,
Worst,
Drawish,
EqualQuiet,
EqualActive,
Unclear,
SlightEdgeWhite,
SlightEdgeBlack,
ModerateAdvantageWhite,
ModerateAdvantageBlack,
DecisiveAdvantageWhite,
DecisiveAdvantageBlack,
CrushingAdvantageWhite,
CrushingAdvantageBlack,
ZugzwangWhite,
ZugzwangBlack,
SlightSpaceAdvantageWhite,
SlightSpaceAdvantageBlack,
ModerateSpaceAdvantageWhite,
ModerateSpaceAdvantageBlack,
DecisiveSpaceAdvantageWhite,
DecisiveSpaceAdvantageBlack,
SlightDevelopmentAdvantageWhite,
SlightDevelopmentAdvantageBlack,
ModerateDevelopmentAdvantageWhite,
ModerateDevelopmentAdvantageBlack,
DecisiveDevelopmentAdvantageWhite,
DecisiveDevelopmentAdvantageBlack,
InitiativeWhite,
InitiativeBlack,
LastingInitiativeWhite,
LastingInitiativeBlack,
AttackWhite,
AttackBlack,
InsufficientCompensationWhite,
InsufficientCompensationBlack,
SufficientCompensationWhite,
SufficientCompensationBlack,
MoreThanAdequateCompensationWhite,
MoreThanAdequateCompensationBlack,
SlightCenterControlAdvantageWhite,
SlightCenterControlAdvantageBlack,
ModerateCenterControlAdvantageWhite,
ModerateCenterControlAdvantageBlack,
DecisiveCenterControlAdvantageWhite,
DecisiveCenterControlAdvantageBlack,
SlightKingSideControlAdvantageWhite,
SlightKingSideControlAdvantageBlack,
ModerateKingSideControlAdvantageWhite,
ModerateKingSideControlAdvantageBlack,
DecisiveKingSideControlAdvantageWhite,
DecisiveKingSideControlAdvantageBlack,
SlightQueenSideControlAdvantageWhite,
SlightQueenSideControlAdvantageBlack,
ModerateQueenSideControlAdvantageWhite,
ModerateQueenSideControlAdvantageBlack,
DecisiveQueenSideControlAdvantageWhite,
DecisiveQueenSideControlAdvantageBlack,
VulnerableFirstRankWhite,
VulnerableFirstRankBlack,
WellProtectedFirstRankWhite,
WellProtectedFirstRankBlack,
PoorlyProtectedKingWhite,
PoorlyProtectedKingBlack,
WellProtectedKingWhite,
WellProtectedKingBlack,
PoorlyPlacedKingWhite,
PoorlyPlacedKingBlack,
WellPlacedKingWhite,
WellPlacedKingBlack,
VeryWeakPawnStructureWhite,
VeryWeakPawnStructureBlack,
ModeratelyWeakPawnStructureWhite,
ModeratelyWeakPawnStructureBlack,
ModeratelyStrongPawnStructureWhite,
ModeratelyStrongPawnStructureBlack,
VeryStrongPawnStructureWhite,
VeryStrongPawnStructureBlack,
PoorKnightPlacementWhite,
PoorKnightPlacementBlack,
GoodKnightPlacementWhite,
GoodKnightPlacementBlack,
PoorBishopPlacementWhite,
PoorBishopPlacementBlack,
GoodBishopPlacementWhite,
GoodBishopPlacementBlack,
PoorRookPlacementWhite,
PoorRookPlacementBlack,
GoodRookPlacementWhite,
GoodRookPlacementBlack,
PoorQueenPlacementWhite,
PoorQueenPlacementBlack,
GoodQueenPlacementWhite,
GoodQueenPlacementBlack,
PoorPieceCoordinationWhite,
PoorPieceCoordinationBlack,
GoodPieceCoordinationWhite,
GoodPieceCoordinationBlack,
VeryPoorOpeningPlayWhite,
VeryPoorOpeningPlayBlack,
PoorOpeningPlayWhite,
PoorOpeningPlayBlack,
WellOpeningPlayWhite,
WellOpeningPlayBlack,
VeryWellOpeningPlayWhite,
VeryWellOpeningPlayBlack,
VeryPoorMiddleGamePlayWhite,
VeryPoorMiddleGamePlayBlack,
PoorMiddleGamePlayWhite,
PoorMiddleGamePlayBlack,
WellMiddleGamePlayWhite,
WellMiddleGamePlayBlack,
VeryWellMiddleGamePlayWhite,
VeryWellMiddleGamePlayBlack,
VeryPoorEndingPlayWhite,
VeryPoorEndingPlayBlack,
PoorEndingPlayWhite,
PoorEndingPlayBlack,
WellEndingPlayWhite,
WellEndingPlayBlack,
VeryWellEndingPlayWhite,
VeryWellEndingPlayBlack,
SlightCounterPlayWhite,
SlightCounterPlayBlack,
ModerateCounterPlayWhite,
ModerateCounterPlayBlack,
DecisiveCounterPlayWhite,
DecisiveCounterPlayBlack,
ModerateTimeControlPressureWhite,
ModerateTimeControlPressureBlack,
SevereTimeControlPressureWhite,
SevereTimeControlPressureBlack,
WithTheIdea,
AimedAgainst,
BetterIs,
WorseIs,
EquivalentIs,
EditorialComment,
Novelty,
Nag147,
Nag148,
Nag149,
Nag150,
Nag151,
Nag152,
Nag153,
Nag154,
Nag155,
Nag156,
Nag157,
Nag158,
Nag159,
Nag160,
Nag161,
Nag162,
Nag163,
Nag164,
Nag165,
Nag166,
Nag167,
Nag168,
Nag169,
Nag170,
Nag171,
Nag172,
Nag173,
Nag174,
Nag175,
Nag176,
Nag177,
Nag178,
Nag179,
Nag180,
Nag181,
Nag182,
Nag183,
Nag184,
Nag185,
Nag186,
Nag187,
Nag188,
Nag189,
Nag190,
Nag191,
Nag192,
Nag193,
Nag194,
Nag195,
Nag196,
Nag197,
Nag198,
Nag199,
Nag200,
Nag201,
Nag202,
Nag203,
Nag204,
Nag205,
Nag206,
Nag207,
Nag208,
Nag209,
Nag210,
Nag211,
Nag212,
Nag213,
Nag214,
Nag215,
Nag216,
Nag217,
Nag218,
Nag219,
Diagram,
DiagramFromBlack,
Nag222,
Nag223,
Nag224,
Nag225,
Nag226,
Nag227,
Nag228,
Nag229,
Nag230,
Nag231,
Nag232,
Nag233,
Nag234,
Nag235,
Nag236,
Nag237,
SpaceAdvantage,
File,
Diagonal,
Centre,
KingSide,
QueenSide,
WeakPoint,
Ending,
BishopPair,
OppositeBishops,
SameBishops,
ConnectedPawns,
IsolatedPawns,
DoubledPawns,
PassedPawn,
PawnMajority,
With,
Without,
}
impl Display for Nag {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Nag::Null => write!(f, " "),
Nag::Hard => write!(f, "!!"),
Nag::Good => write!(f, "!"),
Nag::Mistake => write!(f, "?"),
Nag::Blunder => write!(f, "??"),
Nag::Interesting => write!(f, "!?"),
Nag::Dubious => write!(f, "?!"),
Nag::Forced | Nag::Only => write!(f, "□"),
Nag::ZugzwangWhite | Nag::ZugzwangBlack => write!(f, "⊙"),
Nag::ModerateSpaceAdvantageWhite | Nag::ModerateSpaceAdvantageBlack => write!(f, "○"),
Nag::ModerateDevelopmentAdvantageWhite | Nag::ModerateDevelopmentAdvantageBlack => {
write!(f, "⟳")
}
Nag::InitiativeWhite | Nag::InitiativeBlack => write!(f, "↑"),
Nag::AttackWhite | Nag::AttackBlack => write!(f, "→"),
Nag::SufficientCompensationWhite | Nag::SufficientCompensationBlack => write!(f, "⯹"),
Nag::ModerateCounterPlayWhite
| Nag::DecisiveCounterPlayWhite
| Nag::ModerateCounterPlayBlack
| Nag::DecisiveCounterPlayBlack => write!(f, "⇆"),
Nag::SevereTimeControlPressureWhite | Nag::SevereTimeControlPressureBlack => {
write!(f, "⨁")
}
Nag::WithTheIdea => write!(f, "∆"),
Nag::AimedAgainst => write!(f, "∇"),
Nag::BetterIs => write!(f, "⌓"),
Nag::WorseIs => write!(f, "<="),
Nag::EquivalentIs => write!(f, "=="),
Nag::EditorialComment => write!(f, "RR"),
Nag::Novelty => write!(f, "N"),
Nag::Diagram => write!(f, "⬒"),
Nag::DiagramFromBlack => write!(f, "⬓"),
Nag::SpaceAdvantage => write!(f, "○"),
Nag::File => write!(f, "⇔"),
Nag::Diagonal => write!(f, "⇗"),
Nag::Centre => write!(f, "⊞"),
Nag::KingSide => write!(f, "⟫"),
Nag::QueenSide => write!(f, "⟪"),
Nag::WeakPoint => write!(f, "✕"),
Nag::Ending => write!(f, "⊥"),
Nag::ConnectedPawns => write!(f, "⯺"),
Nag::IsolatedPawns => write!(f, "⯻"),
Nag::DoubledPawns => write!(f, "⯼"),
Nag::PassedPawn => write!(f, "⯽"),
Nag::With => write!(f, "∟"),
Nag::Without => write!(f, "⯾"),
n => write!(f, "${}", n),
}
}
}
impl From<u8> for Nag {
fn from(num: u8) -> Self {
match num {
0 => Nag::Null,
1 => Nag::Good,
2 => Nag::Mistake,
3 => Nag::Hard,
4 => Nag::Blunder,
5 => Nag::Interesting,
6 => Nag::Dubious,
7 => Nag::Forced,
8 => Nag::Only,
9 => Nag::Worst,
10 => Nag::Drawish,
11 => Nag::EqualQuiet,
12 => Nag::EqualActive,
13 => Nag::Unclear,
14 => Nag::SlightEdgeWhite,
15 => Nag::SlightEdgeBlack,
16 => Nag::ModerateAdvantageWhite,
17 => Nag::ModerateAdvantageBlack,
18 => Nag::DecisiveAdvantageWhite,
19 => Nag::DecisiveAdvantageBlack,
20 => Nag::CrushingAdvantageWhite,
21 => Nag::CrushingAdvantageBlack,
22 => Nag::ZugzwangWhite,
23 => Nag::ZugzwangBlack,
24 => Nag::SlightSpaceAdvantageWhite,
25 => Nag::SlightSpaceAdvantageBlack,
26 => Nag::ModerateSpaceAdvantageWhite,
27 => Nag::ModerateSpaceAdvantageBlack,
28 => Nag::DecisiveSpaceAdvantageWhite,
29 => Nag::DecisiveSpaceAdvantageBlack,
30 => Nag::SlightDevelopmentAdvantageWhite,
31 => Nag::SlightDevelopmentAdvantageBlack,
32 => Nag::ModerateDevelopmentAdvantageWhite,
33 => Nag::ModerateDevelopmentAdvantageBlack,
34 => Nag::DecisiveDevelopmentAdvantageWhite,
35 => Nag::DecisiveDevelopmentAdvantageBlack,
36 => Nag::InitiativeWhite,
37 => Nag::InitiativeBlack,
38 => Nag::LastingInitiativeWhite,
39 => Nag::LastingInitiativeBlack,
40 => Nag::AttackWhite,
41 => Nag::AttackBlack,
42 => Nag::InsufficientCompensationWhite,
43 => Nag::InsufficientCompensationBlack,
44 => Nag::SufficientCompensationWhite,
45 => Nag::SufficientCompensationBlack,
46 => Nag::MoreThanAdequateCompensationWhite,
47 => Nag::MoreThanAdequateCompensationBlack,
48 => Nag::SlightCenterControlAdvantageWhite,
49 => Nag::SlightCenterControlAdvantageBlack,
50 => Nag::ModerateCenterControlAdvantageWhite,
51 => Nag::ModerateCenterControlAdvantageBlack,
52 => Nag::DecisiveCenterControlAdvantageWhite,
53 => Nag::DecisiveCenterControlAdvantageBlack,
54 => Nag::SlightKingSideControlAdvantageWhite,
55 => Nag::SlightKingSideControlAdvantageBlack,
56 => Nag::ModerateKingSideControlAdvantageWhite,
57 => Nag::ModerateKingSideControlAdvantageBlack,
58 => Nag::DecisiveKingSideControlAdvantageWhite,
59 => Nag::DecisiveKingSideControlAdvantageBlack,
60 => Nag::SlightQueenSideControlAdvantageWhite,
61 => Nag::SlightQueenSideControlAdvantageBlack,
62 => Nag::ModerateQueenSideControlAdvantageWhite,
63 => Nag::ModerateQueenSideControlAdvantageBlack,
64 => Nag::DecisiveQueenSideControlAdvantageWhite,
65 => Nag::DecisiveQueenSideControlAdvantageBlack,
66 => Nag::VulnerableFirstRankWhite,
67 => Nag::VulnerableFirstRankBlack,
68 => Nag::WellProtectedFirstRankWhite,
69 => Nag::WellProtectedFirstRankBlack,
70 => Nag::PoorlyProtectedKingWhite,
71 => Nag::PoorlyProtectedKingBlack,
72 => Nag::WellProtectedKingWhite,
73 => Nag::WellProtectedKingBlack,
74 => Nag::PoorlyPlacedKingWhite,
75 => Nag::PoorlyPlacedKingBlack,
76 => Nag::WellPlacedKingWhite,
77 => Nag::WellPlacedKingBlack,
78 => Nag::VeryWeakPawnStructureWhite,
79 => Nag::VeryWeakPawnStructureBlack,
80 => Nag::ModeratelyWeakPawnStructureWhite,
81 => Nag::ModeratelyWeakPawnStructureBlack,
82 => Nag::ModeratelyStrongPawnStructureWhite,
83 => Nag::ModeratelyStrongPawnStructureBlack,
84 => Nag::VeryStrongPawnStructureWhite,
85 => Nag::VeryStrongPawnStructureBlack,
86 => Nag::PoorKnightPlacementWhite,
87 => Nag::PoorKnightPlacementBlack,
88 => Nag::GoodKnightPlacementWhite,
89 => Nag::GoodKnightPlacementBlack,
90 => Nag::PoorBishopPlacementWhite,
91 => Nag::PoorBishopPlacementBlack,
92 => Nag::GoodBishopPlacementWhite,
93 => Nag::GoodBishopPlacementBlack,
94 => Nag::PoorRookPlacementWhite,
95 => Nag::PoorRookPlacementBlack,
96 => Nag::GoodRookPlacementWhite,
97 => Nag::GoodRookPlacementBlack,
98 => Nag::PoorQueenPlacementWhite,
99 => Nag::PoorQueenPlacementBlack,
100 => Nag::GoodQueenPlacementWhite,
101 => Nag::GoodQueenPlacementBlack,
102 => Nag::PoorPieceCoordinationWhite,
103 => Nag::PoorPieceCoordinationBlack,
104 => Nag::GoodPieceCoordinationWhite,
105 => Nag::GoodPieceCoordinationBlack,
106 => Nag::VeryPoorOpeningPlayWhite,
107 => Nag::VeryPoorOpeningPlayBlack,
108 => Nag::PoorOpeningPlayWhite,
109 => Nag::PoorOpeningPlayBlack,
110 => Nag::WellOpeningPlayWhite,
111 => Nag::WellOpeningPlayBlack,
112 => Nag::VeryWellOpeningPlayWhite,
113 => Nag::VeryWellOpeningPlayBlack,
114 => Nag::VeryPoorMiddleGamePlayWhite,
115 => Nag::VeryPoorMiddleGamePlayBlack,
116 => Nag::PoorMiddleGamePlayWhite,
117 => Nag::PoorMiddleGamePlayBlack,
118 => Nag::WellMiddleGamePlayWhite,
119 => Nag::WellMiddleGamePlayBlack,
120 => Nag::VeryWellMiddleGamePlayWhite,
121 => Nag::VeryWellMiddleGamePlayBlack,
122 => Nag::VeryPoorEndingPlayWhite,
123 => Nag::VeryPoorEndingPlayBlack,
124 => Nag::PoorEndingPlayWhite,
125 => Nag::PoorEndingPlayBlack,
126 => Nag::WellEndingPlayWhite,
127 => Nag::WellEndingPlayBlack,
128 => Nag::VeryWellEndingPlayWhite,
129 => Nag::VeryWellEndingPlayBlack,
130 => Nag::SlightCounterPlayWhite,
131 => Nag::SlightCounterPlayBlack,
132 => Nag::ModerateCounterPlayWhite,
133 => Nag::ModerateCounterPlayBlack,
134 => Nag::DecisiveCounterPlayWhite,
135 => Nag::DecisiveCounterPlayBlack,
136 => Nag::ModerateTimeControlPressureWhite,
137 => Nag::ModerateTimeControlPressureBlack,
138 => Nag::SevereTimeControlPressureWhite,
139 => Nag::SevereTimeControlPressureBlack,
140 => Nag::WithTheIdea,
141 => Nag::AimedAgainst,
142 => Nag::BetterIs,
143 => Nag::WorseIs,
144 => Nag::EquivalentIs,
145 => Nag::EditorialComment,
146 => Nag::Novelty,
147 => Nag::Nag147,
148 => Nag::Nag148,
149 => Nag::Nag149,
150 => Nag::Nag150,
151 => Nag::Nag151,
152 => Nag::Nag152,
153 => Nag::Nag153,
154 => Nag::Nag154,
155 => Nag::Nag155,
156 => Nag::Nag156,
157 => Nag::Nag157,
158 => Nag::Nag158,
159 => Nag::Nag159,
160 => Nag::Nag160,
161 => Nag::Nag161,
162 => Nag::Nag162,
163 => Nag::Nag163,
164 => Nag::Nag164,
165 => Nag::Nag165,
166 => Nag::Nag166,
167 => Nag::Nag167,
168 => Nag::Nag168,
169 => Nag::Nag169,
170 => Nag::Nag170,
171 => Nag::Nag171,
172 => Nag::Nag172,
173 => Nag::Nag173,
174 => Nag::Nag174,
175 => Nag::Nag175,
176 => Nag::Nag176,
177 => Nag::Nag177,
178 => Nag::Nag178,
179 => Nag::Nag179,
180 => Nag::Nag180,
181 => Nag::Nag181,
182 => Nag::Nag182,
183 => Nag::Nag183,
184 => Nag::Nag184,
185 => Nag::Nag185,
186 => Nag::Nag186,
187 => Nag::Nag187,
188 => Nag::Nag188,
189 => Nag::Nag189,
190 => Nag::Nag190,
191 => Nag::Nag191,
192 => Nag::Nag192,
193 => Nag::Nag193,
194 => Nag::Nag194,
195 => Nag::Nag195,
196 => Nag::Nag196,
197 => Nag::Nag197,
198 => Nag::Nag198,
199 => Nag::Nag199,
200 => Nag::Nag200,
201 => Nag::Nag201,
202 => Nag::Nag202,
203 => Nag::Nag203,
204 => Nag::Nag204,
205 => Nag::Nag205,
206 => Nag::Nag206,
207 => Nag::Nag207,
208 => Nag::Nag208,
209 => Nag::Nag209,
210 => Nag::Nag210,
211 => Nag::Nag211,
212 => Nag::Nag212,
213 => Nag::Nag213,
214 => Nag::Nag214,
215 => Nag::Nag215,
216 => Nag::Nag216,
217 => Nag::Nag217,
218 => Nag::Nag218,
219 => Nag::Nag219,
220 => Nag::Diagram,
221 => Nag::DiagramFromBlack,
222 => Nag::Nag222,
223 => Nag::Nag223,
224 => Nag::Nag224,
225 => Nag::Nag225,
226 => Nag::Nag226,
227 => Nag::Nag227,
228 => Nag::Nag228,
229 => Nag::Nag229,
230 => Nag::Nag230,
231 => Nag::Nag231,
232 => Nag::Nag232,
233 => Nag::Nag233,
234 => Nag::Nag234,
235 => Nag::Nag235,
236 => Nag::Nag236,
237 => Nag::Nag237,
238 => Nag::SpaceAdvantage,
239 => Nag::File,
240 => Nag::Diagonal,
241 => Nag::Centre,
242 => Nag::KingSide,
243 => Nag::QueenSide,
244 => Nag::WeakPoint,
245 => Nag::Ending,
246 => Nag::BishopPair,
247 => Nag::OppositeBishops,
248 => Nag::SameBishops,
249 => Nag::ConnectedPawns,
250 => Nag::IsolatedPawns,
251 => Nag::DoubledPawns,
252 => Nag::PassedPawn,
253 => Nag::PawnMajority,
254 => Nag::With,
255 => Nag::Without,
}
}
}
impl Nag {
pub fn is_question_mark(&self) -> bool {
matches!(
self,
Nag::Interesting | Nag::Dubious | Nag::Mistake | Nag::Blunder | Nag::Worst
)
}
}
impl ByteBoard {
pub fn new(board_str: &str) -> Self {
let bytes: [u8; 64] = board_str.as_bytes().try_into().unwrap();
Self { bytes }
}
pub fn from_bytes(slice: &[u8; 64]) -> Self {
Self { bytes: *slice }
}
pub fn from_board(board: &Board) -> Self {
let mut bytes: [u8; 64] = [b' '; 64];
let mut set_piece_byte = |role, color, byte: u8| {
for square in board.by_role(role) & board.by_color(color) {
let (file, rank) = square.coords();
let index = (7 - rank as usize) * 8 + file as usize;
bytes[index] = byte;
}
};
set_piece_byte(Role::Pawn, Color::Black, b'p');
set_piece_byte(Role::Pawn, Color::White, b'P');
set_piece_byte(Role::Knight, Color::Black, b'n');
set_piece_byte(Role::Knight, Color::White, b'N');
set_piece_byte(Role::Bishop, Color::Black, b'b');
set_piece_byte(Role::Bishop, Color::White, b'B');
set_piece_byte(Role::Rook, Color::Black, b'r');
set_piece_byte(Role::Rook, Color::White, b'R');
set_piece_byte(Role::Queen, Color::Black, b'q');
set_piece_byte(Role::Queen, Color::White, b'Q');
set_piece_byte(Role::King, Color::Black, b'k');
set_piece_byte(Role::King, Color::White, b'K');
Self { bytes }
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn from_fen(fen: &[u8]) -> Result<Self, Error> {
let mut bytes = [b' '; 64];
let mut i = 0;
for &ch in fen {
match ch {
b'r' | b'n' | b'b' | b'q' | b'k' | b'p' | b'R' | b'N' | b'B' | b'Q' | b'K'
| b'P' => {
if i < 64 {
bytes[i] = ch;
i += 1;
} else {
return Err(Error::from(ErrorKind::InvalidInput));
}
}
b'1'..=b'8' => {
let spaces = ch - b'0'; i = (i + spaces as usize).min(64); }
b'/' => {
let remainder = i % 8;
if remainder != 0 {
i += 8 - remainder;
}
}
b' ' => {
break;
}
_ => {
return Err(Error::from(ErrorKind::InvalidInput));
}
}
}
Ok(Self { bytes })
}
pub fn find_piece(&self, piece: char, num: i32) -> Option<i32> {
let piece_byte = piece as u8;
let mut occurrence = num;
for x in 0..8 {
let ux: usize = unsafe { x.try_into().unwrap_unchecked() };
for y in 0..8 {
let uy: usize = unsafe { y.try_into().unwrap_unchecked() };
let index = (7 - uy) * 8 + ux;
if self.bytes[index] != piece_byte {
continue;
}
if occurrence == 1 {
return Some(y * 8 + x);
}
occurrence -= 1;
}
}
None
}
pub fn invert(&mut self) {
for y in 0..4 {
for x in 0..8 {
let index1 = y * 8 + x;
let index2 = (7 - y) * 8 + x;
self.bytes.swap(index1, index2);
self.bytes[index1] = invert_color(self.bytes[index1]);
self.bytes[index2] = invert_color(self.bytes[index2]);
}
}
}
pub fn needs_flipping(&self) -> bool {
self.bytes[0..32].contains(&b'K')
}
pub fn flip(&mut self, eps: Option<Square>) -> Option<Square> {
self.bytes.reverse();
eps.map(|square| square.flip_horizontal())
}
}
impl std::fmt::Display for ByteBoard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", String::from_utf8_lossy(&self.bytes))
}
}
#[inline(always)]
fn invert_color(c: u8) -> u8 {
match c {
b'p' => b'P',
b'P' => b'p',
b'n' => b'N',
b'N' => b'n',
b'b' => b'B',
b'B' => b'b',
b'r' => b'R',
b'R' => b'r',
b'q' => b'Q',
b'Q' => b'q',
b'k' => b'K',
b'K' => b'k',
_ => c,
}
}
const TBL2: [u32; 64] = [
0x3100d2bf, 0x3118e3de, 0x34ab1372, 0x2807a847, 0x1633f566, 0x2143b359, 0x26d56488, 0x3b9e6f59,
0x37755656, 0x3089ca7b, 0x18e92d85, 0x0cd0e9d8, 0x1a9e3b54, 0x3eaa902f, 0x0d9bfaae, 0x2f32b45b,
0x31ed6102, 0x3d3c8398, 0x146660e3, 0x0f8d4b76, 0x02c77a5f, 0x146c8799, 0x1c47f51f, 0x249f8f36,
0x24772043, 0x1fbc1e4d, 0x1e86b3fa, 0x37df36a6, 0x16ed30e4, 0x02c3148e, 0x216e5929, 0x0636b34e,
0x317f9f56, 0x15f09d70, 0x131026fb, 0x38c784b1, 0x29ac3305, 0x2b485dc5, 0x3c049ddc, 0x35a9fbcd,
0x31d5373b, 0x2b246799, 0x0a2923d3, 0x08a96e9d, 0x30031a9f, 0x08f525b5, 0x33611c06, 0x2409db98,
0x0ca4feb2, 0x1000b71e, 0x30566e32, 0x39447d31, 0x194e3752, 0x08233a95, 0x0f38fe36, 0x29c7cd57,
0x0f7b3a39, 0x328e8a16, 0x1e7d1388, 0x0fba78f5, 0x274c7e7c, 0x1e8be65c, 0x2fa0b0bb, 0x1eb6c371,
];
pub fn colored_uci(uci: &Uci, nag: &Option<Nag>, recommendation: u8) -> String {
let is_question_mark = nag.map(|n| n.is_question_mark()).unwrap_or(false);
match recommendation {
0xa4 => style(uci.to_string()).green().to_string(),
0x80 => {
if is_question_mark {
style(uci.to_string()).blue().to_string()
} else {
style(uci.to_string()).green().to_string()
}
}
0x40 => style(uci.to_string()).red().to_string(),
_ => uci.to_string(),
}
}
#[inline(always)]
pub fn gen_hash(ptr: &[i8], len: usize) -> i32 {
let mut hash: i32 = 0;
let mut tmp: i16 = 0;
for ch in ptr.iter().take(len) {
let ch = i16::from(*ch);
tmp += ((0x0f - (ch & 0x0f)) << 2) + 1;
hash = hash.wrapping_add(TBL2[(tmp & 0x3f) as usize] as i32);
tmp += ((0xf0 - (ch & 0xf0)) >> 2) + 1;
hash = hash.wrapping_add(TBL2[(tmp & 0x3f) as usize] as i32);
}
hash
}
pub struct MoveEnc {
pub encoding: u8,
pub piece: char,
pub num: i32,
pub forward: i32,
pub right: i32,
}
pub const MOVETABLE_MAX: usize = 166;
pub static MOVETABLE: [MoveEnc; MOVETABLE_MAX] = [
MoveEnc {
encoding: 0x00,
piece: 'P',
num: 5,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x01,
piece: 'N',
num: 2,
forward: -1,
right: -2,
},
MoveEnc {
encoding: 0x03,
piece: 'Q',
num: 2,
forward: 0,
right: 2,
},
MoveEnc {
encoding: 0x04,
piece: 'P',
num: 2,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x05,
piece: 'Q',
num: 1,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x06,
piece: 'P',
num: 4,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x08,
piece: 'Q',
num: 2,
forward: 0,
right: 4,
},
MoveEnc {
encoding: 0x09,
piece: 'B',
num: 2,
forward: 6,
right: 6,
},
MoveEnc {
encoding: 0x0a,
piece: 'K',
num: 1,
forward: -1,
right: 0,
},
MoveEnc {
encoding: 0x0c,
piece: 'P',
num: 1,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x0d,
piece: 'B',
num: 1,
forward: 3,
right: 3,
},
MoveEnc {
encoding: 0x0e,
piece: 'R',
num: 2,
forward: 0,
right: 3,
},
MoveEnc {
encoding: 0x0f,
piece: 'N',
num: 1,
forward: -1,
right: -2,
},
MoveEnc {
encoding: 0x12,
piece: 'B',
num: 1,
forward: 7,
right: 7,
},
MoveEnc {
encoding: 0x13,
piece: 'K',
num: 1,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x14,
piece: 'P',
num: 8,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x15,
piece: 'B',
num: 1,
forward: 5,
right: 5,
},
MoveEnc {
encoding: 0x18,
piece: 'P',
num: 7,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x1a,
piece: 'Q',
num: 2,
forward: 6,
right: 0,
},
MoveEnc {
encoding: 0x1b,
piece: 'B',
num: 1,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x1d,
piece: 'B',
num: 2,
forward: 7,
right: 7,
},
MoveEnc {
encoding: 0x21,
piece: 'R',
num: 2,
forward: 0,
right: 7,
},
MoveEnc {
encoding: 0x22,
piece: 'B',
num: 2,
forward: 2,
right: -2,
},
MoveEnc {
encoding: 0x23,
piece: 'Q',
num: 2,
forward: 6,
right: 6,
},
MoveEnc {
encoding: 0x24,
piece: 'P',
num: 8,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x26,
piece: 'B',
num: 1,
forward: 7,
right: -7,
},
MoveEnc {
encoding: 0x27,
piece: 'P',
num: 3,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x28,
piece: 'Q',
num: 1,
forward: 5,
right: 5,
},
MoveEnc {
encoding: 0x29,
piece: 'Q',
num: 1,
forward: 0,
right: 6,
},
MoveEnc {
encoding: 0x2a,
piece: 'N',
num: 2,
forward: -2,
right: 1,
},
MoveEnc {
encoding: 0x2d,
piece: 'P',
num: 6,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x2e,
piece: 'B',
num: 1,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x2f,
piece: 'Q',
num: 1,
forward: 0,
right: 1,
},
MoveEnc {
encoding: 0x30,
piece: 'N',
num: 2,
forward: -2,
right: -1,
},
MoveEnc {
encoding: 0x31,
piece: 'Q',
num: 1,
forward: 0,
right: 3,
},
MoveEnc {
encoding: 0x32,
piece: 'B',
num: 2,
forward: 5,
right: 5,
},
MoveEnc {
encoding: 0x34,
piece: 'N',
num: 1,
forward: 2,
right: 1,
},
MoveEnc {
encoding: 0x36,
piece: 'N',
num: 1,
forward: 1,
right: 2,
},
MoveEnc {
encoding: 0x37,
piece: 'Q',
num: 1,
forward: 4,
right: 0,
},
MoveEnc {
encoding: 0x38,
piece: 'Q',
num: 2,
forward: 4,
right: -4,
},
MoveEnc {
encoding: 0x39,
piece: 'Q',
num: 1,
forward: 0,
right: 5,
},
MoveEnc {
encoding: 0x3a,
piece: 'B',
num: 1,
forward: 6,
right: 6,
},
MoveEnc {
encoding: 0x3b,
piece: 'Q',
num: 2,
forward: 5,
right: -5,
},
MoveEnc {
encoding: 0x3c,
piece: 'B',
num: 1,
forward: 5,
right: -5,
},
MoveEnc {
encoding: 0x41,
piece: 'Q',
num: 2,
forward: 5,
right: 5,
},
MoveEnc {
encoding: 0x42,
piece: 'Q',
num: 1,
forward: 7,
right: -7,
},
MoveEnc {
encoding: 0x44,
piece: 'K',
num: 1,
forward: -1,
right: 1,
},
MoveEnc {
encoding: 0x45,
piece: 'Q',
num: 1,
forward: 3,
right: 3,
},
MoveEnc {
encoding: 0x4a,
piece: 'P',
num: 8,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0x4b,
piece: 'Q',
num: 1,
forward: 5,
right: -5,
},
MoveEnc {
encoding: 0x4c,
piece: 'N',
num: 2,
forward: 2,
right: 1,
},
MoveEnc {
encoding: 0x4d,
piece: 'Q',
num: 2,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x50,
piece: 'R',
num: 1,
forward: 6,
right: 0,
},
MoveEnc {
encoding: 0x52,
piece: 'R',
num: 1,
forward: 0,
right: 6,
},
MoveEnc {
encoding: 0x54,
piece: 'B',
num: 2,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x55,
piece: 'P',
num: 3,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x5c,
piece: 'P',
num: 7,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x5f,
piece: 'P',
num: 5,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0x61,
piece: 'Q',
num: 1,
forward: 6,
right: 6,
},
MoveEnc {
encoding: 0x62,
piece: 'P',
num: 2,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0x63,
piece: 'Q',
num: 2,
forward: 7,
right: -7,
},
MoveEnc {
encoding: 0x66,
piece: 'B',
num: 1,
forward: 3,
right: -3,
},
MoveEnc {
encoding: 0x67,
piece: 'K',
num: 1,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x69,
piece: 'R',
num: 2,
forward: 7,
right: 0,
},
MoveEnc {
encoding: 0x6a,
piece: 'B',
num: 1,
forward: 4,
right: 4,
},
MoveEnc {
encoding: 0x6b,
piece: 'K',
num: 1,
forward: 0,
right: 2,
},
MoveEnc {
encoding: 0x6e,
piece: 'R',
num: 1,
forward: 0,
right: 5,
},
MoveEnc {
encoding: 0x6f,
piece: 'Q',
num: 2,
forward: 7,
right: 7,
},
MoveEnc {
encoding: 0x72,
piece: 'B',
num: 2,
forward: 7,
right: -7,
},
MoveEnc {
encoding: 0x74,
piece: 'Q',
num: 1,
forward: 0,
right: 2,
},
MoveEnc {
encoding: 0x79,
piece: 'B',
num: 2,
forward: 6,
right: -6,
},
MoveEnc {
encoding: 0x7a,
piece: 'R',
num: 1,
forward: 3,
right: 0,
},
MoveEnc {
encoding: 0x7b,
piece: 'R',
num: 2,
forward: 6,
right: 0,
},
MoveEnc {
encoding: 0x7c,
piece: 'P',
num: 3,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x7d,
piece: 'R',
num: 2,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x7e,
piece: 'Q',
num: 1,
forward: 3,
right: -3,
},
MoveEnc {
encoding: 0x7f,
piece: 'R',
num: 1,
forward: 0,
right: 1,
},
MoveEnc {
encoding: 0x80,
piece: 'Q',
num: 1,
forward: 6,
right: -6,
},
MoveEnc {
encoding: 0x81,
piece: 'R',
num: 1,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0x82,
piece: 'P',
num: 6,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0x85,
piece: 'N',
num: 1,
forward: 2,
right: -1,
},
MoveEnc {
encoding: 0x86,
piece: 'R',
num: 1,
forward: 0,
right: 7,
},
MoveEnc {
encoding: 0x87,
piece: 'R',
num: 1,
forward: 5,
right: 0,
},
MoveEnc {
encoding: 0x8a,
piece: 'N',
num: 1,
forward: -2,
right: 1,
},
MoveEnc {
encoding: 0x8b,
piece: 'P',
num: 1,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x8c,
piece: 'K',
num: 1,
forward: -1,
right: -1,
},
MoveEnc {
encoding: 0x8e,
piece: 'Q',
num: 2,
forward: 2,
right: -2,
},
MoveEnc {
encoding: 0x8f,
piece: 'Q',
num: 1,
forward: 0,
right: 7,
},
MoveEnc {
encoding: 0x92,
piece: 'Q',
num: 2,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x94,
piece: 'Q',
num: 1,
forward: 3,
right: 0,
},
MoveEnc {
encoding: 0x96,
piece: 'P',
num: 2,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0x97,
piece: 'K',
num: 1,
forward: 0,
right: -1,
},
MoveEnc {
encoding: 0x98,
piece: 'R',
num: 1,
forward: 0,
right: 3,
},
MoveEnc {
encoding: 0x99,
piece: 'R',
num: 1,
forward: 4,
right: 0,
},
MoveEnc {
encoding: 0x9a,
piece: 'Q',
num: 1,
forward: 6,
right: 0,
},
MoveEnc {
encoding: 0x9b,
piece: 'P',
num: 3,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0x9d,
piece: 'Q',
num: 1,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0x9f,
piece: 'B',
num: 2,
forward: 4,
right: -4,
},
MoveEnc {
encoding: 0xa0,
piece: 'Q',
num: 2,
forward: 3,
right: 0,
},
MoveEnc {
encoding: 0xa2,
piece: 'Q',
num: 1,
forward: 2,
right: 2,
},
MoveEnc {
encoding: 0xa3,
piece: 'P',
num: 8,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0xa5,
piece: 'R',
num: 2,
forward: 5,
right: 0,
},
MoveEnc {
encoding: 0xa9,
piece: 'R',
num: 2,
forward: 0,
right: 2,
},
MoveEnc {
encoding: 0xab,
piece: 'Q',
num: 2,
forward: 6,
right: -6,
},
MoveEnc {
encoding: 0xad,
piece: 'R',
num: 2,
forward: 0,
right: 4,
},
MoveEnc {
encoding: 0xae,
piece: 'Q',
num: 2,
forward: 3,
right: 3,
},
MoveEnc {
encoding: 0xb0,
piece: 'Q',
num: 2,
forward: 4,
right: 0,
},
MoveEnc {
encoding: 0xb1,
piece: 'P',
num: 6,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xb2,
piece: 'B',
num: 1,
forward: 6,
right: -6,
},
MoveEnc {
encoding: 0xb5,
piece: 'R',
num: 2,
forward: 0,
right: 5,
},
MoveEnc {
encoding: 0xb7,
piece: 'Q',
num: 1,
forward: 5,
right: 0,
},
MoveEnc {
encoding: 0xb9,
piece: 'B',
num: 2,
forward: 3,
right: 3,
},
MoveEnc {
encoding: 0xbb,
piece: 'P',
num: 5,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0xbc,
piece: 'Q',
num: 2,
forward: 0,
right: 5,
},
MoveEnc {
encoding: 0xbd,
piece: 'Q',
num: 2,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xbe,
piece: 'K',
num: 1,
forward: 0,
right: 1,
},
MoveEnc {
encoding: 0xc1,
piece: 'B',
num: 1,
forward: 2,
right: 2,
},
MoveEnc {
encoding: 0xc2,
piece: 'B',
num: 2,
forward: 2,
right: 2,
},
MoveEnc {
encoding: 0xc3,
piece: 'B',
num: 1,
forward: 2,
right: -2,
},
MoveEnc {
encoding: 0xc4,
piece: 'R',
num: 2,
forward: 0,
right: 1,
},
MoveEnc {
encoding: 0xc5,
piece: 'R',
num: 2,
forward: 4,
right: 0,
},
MoveEnc {
encoding: 0xc6,
piece: 'Q',
num: 2,
forward: 5,
right: 0,
},
MoveEnc {
encoding: 0xc7,
piece: 'P',
num: 7,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xc8,
piece: 'P',
num: 7,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xc9,
piece: 'Q',
num: 2,
forward: 7,
right: 0,
},
MoveEnc {
encoding: 0xca,
piece: 'B',
num: 2,
forward: 3,
right: -3,
},
MoveEnc {
encoding: 0xcb,
piece: 'P',
num: 6,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0xcc,
piece: 'B',
num: 2,
forward: 5,
right: -5,
},
MoveEnc {
encoding: 0xcd,
piece: 'R',
num: 1,
forward: 0,
right: 2,
},
MoveEnc {
encoding: 0xcf,
piece: 'P',
num: 4,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0xd1,
piece: 'P',
num: 2,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xd2,
piece: 'N',
num: 2,
forward: 1,
right: 2,
},
MoveEnc {
encoding: 0xd3,
piece: 'N',
num: 2,
forward: 1,
right: -2,
},
MoveEnc {
encoding: 0xd7,
piece: 'Q',
num: 1,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xd8,
piece: 'R',
num: 2,
forward: 0,
right: 6,
},
MoveEnc {
encoding: 0xd9,
piece: 'Q',
num: 1,
forward: 2,
right: -2,
},
MoveEnc {
encoding: 0xda,
piece: 'N',
num: 1,
forward: -2,
right: -1,
},
MoveEnc {
encoding: 0xdb,
piece: 'P',
num: 1,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xde,
piece: 'P',
num: 5,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xdf,
piece: 'K',
num: 1,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xe0,
piece: 'N',
num: 2,
forward: -1,
right: 2,
},
MoveEnc {
encoding: 0xe1,
piece: 'R',
num: 1,
forward: 7,
right: 0,
},
MoveEnc {
encoding: 0xe3,
piece: 'R',
num: 2,
forward: 3,
right: 0,
},
MoveEnc {
encoding: 0xe5,
piece: 'Q',
num: 1,
forward: 0,
right: 4,
},
MoveEnc {
encoding: 0xe6,
piece: 'P',
num: 4,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xe7,
piece: 'Q',
num: 1,
forward: 4,
right: 4,
},
MoveEnc {
encoding: 0xe8,
piece: 'R',
num: 1,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xe9,
piece: 'N',
num: 1,
forward: -1,
right: 2,
},
MoveEnc {
encoding: 0xeb,
piece: 'P',
num: 4,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0xec,
piece: 'P',
num: 1,
forward: 1,
right: 0,
},
MoveEnc {
encoding: 0xed,
piece: 'Q',
num: 1,
forward: 7,
right: 7,
},
MoveEnc {
encoding: 0xee,
piece: 'Q',
num: 2,
forward: 1,
right: -1,
},
MoveEnc {
encoding: 0xef,
piece: 'R',
num: 1,
forward: 0,
right: 4,
},
MoveEnc {
encoding: 0xf0,
piece: 'Q',
num: 2,
forward: 0,
right: 7,
},
MoveEnc {
encoding: 0xf1,
piece: 'Q',
num: 1,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0xf3,
piece: 'N',
num: 2,
forward: 2,
right: -1,
},
MoveEnc {
encoding: 0xf4,
piece: 'R',
num: 2,
forward: 2,
right: 0,
},
MoveEnc {
encoding: 0xf5,
piece: 'B',
num: 2,
forward: 1,
right: 1,
},
MoveEnc {
encoding: 0xf6,
piece: 'K',
num: 1,
forward: 0,
right: -2,
},
MoveEnc {
encoding: 0xf7,
piece: 'N',
num: 1,
forward: 1,
right: -2,
},
MoveEnc {
encoding: 0xf8,
piece: 'Q',
num: 2,
forward: 0,
right: 1,
},
MoveEnc {
encoding: 0xf9,
piece: 'Q',
num: 2,
forward: 6,
right: 0,
},
MoveEnc {
encoding: 0xfa,
piece: 'Q',
num: 2,
forward: 0,
right: 3,
},
MoveEnc {
encoding: 0xfb,
piece: 'Q',
num: 2,
forward: 2,
right: 2,
},
MoveEnc {
encoding: 0xfd,
piece: 'Q',
num: 1,
forward: 7,
right: 0,
},
MoveEnc {
encoding: 0xfe,
piece: 'Q',
num: 2,
forward: 3,
right: -3,
},
];
#[cfg(test)]
mod tests {
use shakmaty::*;
use super::*;
#[test]
fn test_byteboard_from_board() {
let pos = Chess::default();
let epd = format!(
"{}",
shakmaty::fen::Epd::from_position(pos.clone(), EnPassantMode::PseudoLegal)
);
let bb0 = ByteBoard::from_fen(epd.as_bytes()).expect("invalid fen");
let bb1 = ByteBoard::from_board(&pos.board());
assert_eq!(bb0, bb1);
}
}