Skip to content

Commit 83855ed

Browse files
authored
Simplify and speedup is_legal (#879)
STC Elo | 1.25 +- 1.87 (95%) SPRT | 8.0+0.08s Threads=1 Hash=16MB LLR | 3.03 (-2.25, 2.89) [-2.75, 0.25] Games | N: 32216 W: 8168 L: 8052 D: 15996 Penta | [83, 3517, 8803, 3611, 94] https://recklesschess.space/test/13337/ No functional change. Bench: 2701511
1 parent a1b4948 commit 83855ed

2 files changed

Lines changed: 33 additions & 47 deletions

File tree

src/board.rs

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -330,65 +330,47 @@ impl Board {
330330
| (king_attacks(square) & self.pieces(PieceType::King))
331331
}
332332

333-
/// Checks if the given move is legal in the current position.
334333
pub fn is_legal(&self, mv: Move) -> bool {
335334
debug_assert!(mv.is_present());
336-
337335
let stm = self.side_to_move();
338336
let king = self.king_square(stm);
339-
340337
let from = mv.from();
341338
let to = mv.to();
342339

343-
if self.in_check() && king != from {
344-
if self.checkers().is_multiple() {
345-
return false;
346-
}
347-
348-
if !mv.is_en_passant() && !(self.checkers() | between(king, self.checkers().lsb())).contains(to) {
349-
return false;
350-
}
351-
}
352-
353-
if self.pinned(stm).contains(from) && !ray_pass(king, from).contains(to) {
340+
if !self.colors(stm).contains(from) {
354341
return false;
355342
}
356343

357344
let piece = self.piece_on(from);
358-
let captured = self.piece_on(to).piece_type();
359345

360-
if mv.is_castling() {
361-
if king != from {
362-
return false;
346+
if piece.piece_type() == PieceType::King {
347+
if mv.is_castling() {
348+
let kind = match to {
349+
Square::G1 => CastlingKind::WhiteKingside,
350+
Square::C1 => CastlingKind::WhiteQueenside,
351+
Square::G8 => CastlingKind::BlackKingside,
352+
Square::C8 => CastlingKind::BlackQueenside,
353+
_ => return false,
354+
};
355+
356+
return self.castling().is_allowed(kind)
357+
&& (self.castling_path[kind] & self.occupancies()).is_empty()
358+
&& (self.castling_threat[kind] & self.all_threats()).is_empty()
359+
&& !self.pinned(stm).contains(self.castling_rooks[kind]);
363360
}
364361

365-
let kind = match to {
366-
Square::G1 => CastlingKind::WhiteKingside,
367-
Square::C1 => CastlingKind::WhiteQueenside,
368-
Square::G8 => CastlingKind::BlackKingside,
369-
Square::C8 => CastlingKind::BlackQueenside,
370-
_ => return false,
371-
};
372-
373-
return self.castling().is_allowed(kind)
374-
&& (self.castling_path[kind] & self.occupancies()).is_empty()
375-
&& (self.castling_threat[kind] & self.all_threats()).is_empty()
376-
&& !self.pinned(stm).contains(self.castling_rooks[kind]);
362+
return !mv.is_special()
363+
&& !self.colors(stm).contains(to)
364+
&& (mv.is_capture() == self.colors(!stm).contains(to))
365+
&& (king_attacks(from) & !self.all_threats()).contains(to);
377366
}
378367

379-
if king == from && self.all_threats().contains(to) {
380-
return false;
381-
}
382-
383-
if !self.colors(stm).contains(from) || self.colors(stm).contains(to) {
384-
return false;
385-
}
386-
387-
if captured != PieceType::None && (!mv.is_capture() || captured == PieceType::King) {
388-
return false;
389-
}
390-
391-
if mv.is_capture() && !mv.is_en_passant() && !self.colors(!stm).contains(to) {
368+
if self.colors(stm).contains(to)
369+
|| (self.pinned(stm).contains(from) && !ray_pass(king, from).contains(to))
370+
|| (self.in_check()
371+
&& (self.checkers().is_multiple()
372+
|| (!mv.is_en_passant() && !(self.checkers() | between(king, self.checkers().lsb())).contains(to))))
373+
{
392374
return false;
393375
}
394376

@@ -422,12 +404,12 @@ impl Board {
422404
&& !self.occupancies().contains(to);
423405
}
424406

425-
return from.shift(offset) == to && !self.occupancies().contains(to);
426-
} else if mv.is_double_push() || mv.is_promotion() || mv.is_en_passant() {
427-
return false;
407+
return !mv.is_castling() && from.shift(offset) == to && !self.occupancies().contains(to);
428408
}
429409

430-
attacks(piece, from, self.occupancies()).contains(to)
410+
!mv.is_special()
411+
&& (mv.is_capture() == self.colors(!stm).contains(to))
412+
&& attacks(piece, from, self.occupancies()).contains(to)
431413
}
432414

433415
/// Quickly checks if the move *might* give check to the opponent's king.

src/types/moves.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ impl Move {
8282
)
8383
}
8484

85+
pub const fn is_special(self) -> bool {
86+
(self.kind() as u8 & 11) != 0
87+
}
88+
8589
pub const fn is_capture(self) -> bool {
8690
(self.0 >> 14) & 1 != 0
8791
}

0 commit comments

Comments
 (0)