Skip to content

Commit

Permalink
is_legal_partial returns meaningful errors
Browse files Browse the repository at this point in the history
  • Loading branch information
koba-e964 committed Jun 6, 2022
1 parent 220ccf4 commit 5085c3f
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 9 deletions.
12 changes: 6 additions & 6 deletions shogi_legality_lite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,14 @@ impl LegalityChecker for LiteLegalityChecker {
position: &PartialPosition,
mv: Move,
) -> Result<(), IllegalMoveKind> {
if !prelegality::check(position, mv) {
return Err(IllegalMoveKind::IncorrectMove);
}
prelegality::check_with_error(position, mv)?;
let mut next = position.clone();
if next.make_move(mv).is_none() {}
if prelegality::will_king_be_captured(&next) != Some(false) {
if next.make_move(mv).is_none() {
return Err(IllegalMoveKind::IncorrectMove);
}
if prelegality::will_king_be_captured(&next) == Some(true) {
return Err(IllegalMoveKind::IgnoredCheck);
}
Ok(())
}

Expand All @@ -123,7 +123,7 @@ impl LegalityChecker for LiteLegalityChecker {
if next.make_move(mv).is_none() {
return false;
}
if prelegality::will_king_be_captured(&next) != Some(false) {
if prelegality::will_king_be_captured(&next) == Some(true) {
return false;
}
true
Expand Down
108 changes: 105 additions & 3 deletions shogi_legality_lite/src/prelegality.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use shogi_core::{Bitboard, Color, Move, PartialPosition, Piece, PieceKind, Square};
use shogi_core::{
Bitboard, Color, IllegalMoveKind, Move, PartialPosition, Piece, PieceKind, Square,
};

pub fn check(position: &PartialPosition, mv: Move) -> bool {
let side = position.side_to_move();
Expand Down Expand Up @@ -98,6 +100,108 @@ pub fn check(position: &PartialPosition, mv: Move) -> bool {
}
}

pub fn check_with_error(position: &PartialPosition, mv: Move) -> Result<(), IllegalMoveKind> {
let side = position.side_to_move();
match mv {
Move::Normal { from, to, promote } => {
// Is `from` occupied by `side`'s piece?
let from_piece = if let Some(x) = position.piece_at(from) {
x
} else {
return Err(IllegalMoveKind::IncorrectMove);
};
if from_piece.color() != side {
return Err(IllegalMoveKind::IncorrectMove);
}
// Is `to` occupied by `side`'s piece?
let to_piece = position.piece_at(to);
if let Some(x) = to_piece {
if x.color() == side {
return Err(IllegalMoveKind::IncorrectMove);
}
}
// Stuck?
let rel_rank = to.relative_rank(side);
if rel_rank == 1
&& matches!(
from_piece.piece_kind(),
PieceKind::Pawn | PieceKind::Lance | PieceKind::Knight,
)
&& !promote
{
return Err(IllegalMoveKind::NormalStuck);
}
if rel_rank == 2 && from_piece.piece_kind() == PieceKind::Knight && !promote {
return Err(IllegalMoveKind::NormalStuck);
}
// Can promote?
if promote && from.relative_rank(side) > 3 && to.relative_rank(side) > 3 {
return Err(IllegalMoveKind::IncorrectMove);
}
if promote && from_piece.promote().is_none() {
return Err(IllegalMoveKind::IncorrectMove);
}
// Is the move valid?
if crate::normal::check(position, from_piece, from, to) {
Ok(())
} else {
Err(IllegalMoveKind::IncorrectMove)
}
}
Move::Drop { piece, to } => {
// Does `side` have a piece?
if piece.color() != side {
return Err(IllegalMoveKind::IncorrectMove);
}
let remaining = if let Some(x) = position.hand(piece) {
x
} else {
return Err(IllegalMoveKind::IncorrectMove);
};
if remaining == 0 {
return Err(IllegalMoveKind::IncorrectMove);
}
// Is `to` vacant?
if position.piece_at(to).is_some() {
return Err(IllegalMoveKind::IncorrectMove);
}
// Stuck?
let rel_rank = to.relative_rank(side);
if rel_rank == 1
&& matches!(
piece.piece_kind(),
PieceKind::Pawn | PieceKind::Lance | PieceKind::Knight,
)
{
return Err(IllegalMoveKind::DropStuck);
}
if rel_rank == 2 && piece.piece_kind() == PieceKind::Knight {
return Err(IllegalMoveKind::DropStuck);
}
// Does a double-pawn (`二歩`, *nifu*) happen?
if piece.piece_kind() == PieceKind::Pawn {
let file = to.file();
for i in 1..=9 {
let square = unsafe { Square::new(file, i).unwrap_unchecked() };
if position.piece_at(square) == Some(piece) {
return Err(IllegalMoveKind::TwoPawns);
}
}
}
// Does a drop-pawn-mate (`打ち歩詰め`, *uchifu-zume*) happen?
if piece.piece_kind() == PieceKind::Pawn {
let mut next = position.clone();
let result = next.make_move(mv); // always Some(())
debug_assert_eq!(result, Some(()));
if is_mate(&next) != Some(false) {
return Err(IllegalMoveKind::DropPawnMate);
}
}
Ok(())
}
}
}

const FIRST_RANK: Bitboard = {
let mut result = Bitboard::empty();
let mut i = 1;
Expand Down Expand Up @@ -138,7 +242,6 @@ const WHITE_PROMOTION: Bitboard = {
result
};

#[allow(unused)] // TODO: remove
pub fn normal_from_candidates(position: &PartialPosition, from: Square) -> [Bitboard; 2] {
let side = position.side_to_move();
let from_piece = if let Some(x) = position.piece_at(from) {
Expand Down Expand Up @@ -176,7 +279,6 @@ pub fn normal_from_candidates(position: &PartialPosition, from: Square) -> [Bitb
[unpromote_prohibited.andnot(base), base & promotable]
}

#[allow(unused)]
pub fn all_legal_moves(position: &PartialPosition) -> impl Iterator<Item = Move> + '_ {
Square::all()
.flat_map(|from| {
Expand Down

0 comments on commit 5085c3f

Please sign in to comment.