-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add doc comments & tests. Some refactoring #28
Changes from 1 commit
78968f1
92a53fc
2ed61bc
1a96943
10f783c
5776c78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,50 +43,49 @@ impl Position { | |
/// Generate moves to evade check, optimized using AttackInfo. | ||
fn generate_evasions(&self, av: &mut ArrayVec<Move, MAX_LEGAL_MOVES>) { | ||
let c = self.side_to_move(); | ||
if let Some(king) = self.king_position(c) { | ||
let mut checkers_attacks = Bitboard::empty(); | ||
let mut checkers_count = 0; | ||
for ch in self.checkers() { | ||
if let Some(p) = self.piece_at(ch) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unwrapped |
||
let pk = p.piece_kind(); | ||
// 龍が斜め位置から王手している場合のみ、他の駒の裏に逃がれることができる可能性がある | ||
if pk == PieceKind::ProRook | ||
&& ch.file() != king.file() | ||
&& ch.rank() != king.rank() | ||
{ | ||
checkers_attacks |= ATTACK_TABLE.hi.attack(ch, &self.occupied_bitboard()); | ||
} else { | ||
checkers_attacks |= ATTACK_TABLE.pseudo_attack(pk, ch, c.flip()); | ||
} | ||
} | ||
checkers_count += 1; | ||
} | ||
for to in ATTACK_TABLE.ou.attack(king, c) & !self.player_bitboard(c) & !checkers_attacks | ||
let king = self.king_position(c).unwrap(); | ||
let mut checkers_attacks = Bitboard::empty(); | ||
let mut checkers_count = 0; | ||
for ch in self.checkers() { | ||
let pk = self.piece_at(ch).unwrap().piece_kind(); | ||
// 龍が斜め位置から王手している場合のみ、他の駒の裏に逃がれることができる可能性がある | ||
if pk == PieceKind::ProRook | ||
&& ch.file() != king.file() | ||
&& ch.rank() != king.rank() | ||
{ | ||
av.push(Move::Normal { | ||
from: king, | ||
to, | ||
promote: false, | ||
}); | ||
} | ||
// 両王手の場合は玉が逃げるしかない | ||
if checkers_count > 1 { | ||
return; | ||
} | ||
if let Some(ch) = self.checkers().into_iter().next() { | ||
let target_drop = BETWEEN_TABLE[ch.array_index()][king.array_index()]; | ||
let target_move = target_drop | self.checkers(); | ||
self.generate_for_fu(av, &target_move); | ||
self.generate_for_ky(av, &target_move); | ||
self.generate_for_ke(av, &target_move); | ||
self.generate_for_gi(av, &target_move); | ||
self.generate_for_ka(av, &target_move); | ||
self.generate_for_hi(av, &target_move); | ||
self.generate_for_ki(av, &target_move); | ||
self.generate_for_um(av, &target_move); | ||
self.generate_for_ry(av, &target_move); | ||
self.generate_drop(av, &target_drop); | ||
checkers_attacks |= ATTACK_TABLE.hi.attack(ch, &self.occupied_bitboard()); | ||
} else { | ||
checkers_attacks |= ATTACK_TABLE.pseudo_attack(pk, ch, c.flip()); | ||
} | ||
checkers_count += 1; | ||
} | ||
for to in ATTACK_TABLE.ou.attack(king, c) & !self.player_bitboard(c) & !checkers_attacks | ||
{ | ||
av.push(Move::Normal { | ||
from: king, | ||
to, | ||
promote: false, | ||
}); | ||
} | ||
// 両王手の場合は玉が逃げるしかない | ||
if checkers_count > 1 { | ||
return; | ||
} | ||
let ch = self.checkers().into_iter().next().unwrap(); | ||
let target_drop = BETWEEN_TABLE[ch.array_index()][king.array_index()]; | ||
let target_move = target_drop | self.checkers(); | ||
self.generate_for_fu(av, &target_move); | ||
self.generate_for_ky(av, &target_move); | ||
self.generate_for_ke(av, &target_move); | ||
self.generate_for_gi(av, &target_move); | ||
self.generate_for_ka(av, &target_move); | ||
self.generate_for_hi(av, &target_move); | ||
self.generate_for_ki(av, &target_move); | ||
self.generate_for_um(av, &target_move); | ||
self.generate_for_ry(av, &target_move); | ||
if !target_drop.is_empty() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing |
||
// No need to exclude occupied bitboard: Existence of cells between attacker and king is given. | ||
self.generate_drop(av, &target_drop); | ||
} | ||
} | ||
fn generate_for_fu(&self, av: &mut ArrayVec<Move, MAX_LEGAL_MOVES>, target: &Bitboard) { | ||
|
@@ -333,8 +332,8 @@ impl Position { | |
// 玉が相手の攻撃範囲内に動いてしまう指し手は除外 | ||
if self.piece_at(from) == Some(king) | ||
&& !self | ||
.attackers_to(c.flip(), m.to(), &self.occupied_bitboard()) | ||
.is_empty() | ||
.attackers_to(c.flip(), m.to(), &self.occupied_bitboard()) | ||
.is_empty() | ||
{ | ||
return false; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,25 +73,21 @@ impl Position { | |
match m { | ||
Move::Normal { from, to, promote } => { | ||
let piece = self.inner.piece_at(from).unwrap(); | ||
let p = if promote { | ||
if let Some(p) = piece.promote() { | ||
p | ||
} else { | ||
piece | ||
} | ||
let pk = piece.piece_kind(); | ||
let pk = if promote { | ||
pk.promote().unwrap_or(pk) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did a few refactor with |
||
} else { | ||
piece | ||
pk | ||
}; | ||
if self.checkable(p.piece_kind(), to) { | ||
if self.checkable(pk, to) { | ||
return true; | ||
} | ||
// 開き王手 | ||
let c = self.inner.side; | ||
if self.pinned(c.flip()).contains(from) { | ||
if let Some(sq) = self.king_position(c.flip()) { | ||
return !(BETWEEN_TABLE[sq.array_index()][from.array_index()].contains(to) | ||
|| BETWEEN_TABLE[sq.array_index()][to.array_index()].contains(from)); | ||
} | ||
let c = self.inner.side.flip(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When only flip side is used for multiple times, I rewrote to flipping it once than doing it in every occurrence. |
||
if self.pinned(c).contains(from) { | ||
let sq = self.king_position(c).unwrap(); | ||
return !(BETWEEN_TABLE[sq.array_index()][from.array_index()].contains(to) | ||
|| BETWEEN_TABLE[sq.array_index()][to.array_index()].contains(from)); | ||
} | ||
false | ||
} | ||
|
@@ -110,11 +106,7 @@ impl Position { | |
last_moved = Some(piece); | ||
if let Some(p) = captured { | ||
let pk = p.piece_kind(); | ||
let pk_unpromoted = if let Some(pk) = pk.unpromote() { | ||
pk | ||
} else { | ||
pk | ||
}; | ||
let pk_unpromoted = pk.unpromote().unwrap_or(pk); | ||
// Update keys | ||
keys.0 ^= ZOBRIST_TABLE.board(to, p); | ||
keys.1 ^= ZOBRIST_TABLE.hand( | ||
|
@@ -182,7 +174,7 @@ impl Position { | |
}); | ||
} | ||
pub fn undo_move(&mut self, m: Move) { | ||
let c = self.side_to_move(); | ||
let c = self.side_to_move().flip(); | ||
match m { | ||
Move::Normal { | ||
from, | ||
|
@@ -193,13 +185,9 @@ impl Position { | |
let captured = self.captured(); | ||
if let Some(p_cap) = captured { | ||
let pk = p_cap.piece_kind(); | ||
let pk_unpromoted = if let Some(pk) = pk.unpromote() { | ||
pk | ||
} else { | ||
pk | ||
}; | ||
let pk_unpromoted = pk.unpromote().unwrap_or(pk); | ||
self.inner.xor_piece(to, p_cap); | ||
let hand = self.inner.hand_of_a_player_mut(c.flip()); | ||
let hand = self.inner.hand_of_a_player_mut(c); | ||
*hand = hand.removed(pk_unpromoted).unwrap(); | ||
} | ||
self.inner.xor_piece(from, last_moved); | ||
|
@@ -210,11 +198,11 @@ impl Position { | |
Move::Drop { to, piece } => { | ||
self.inner.xor_piece(to, piece); | ||
*self.inner.piece_at_mut(to) = None; | ||
let hand = self.inner.hand_of_a_player_mut(c.flip()); | ||
let hand = self.inner.hand_of_a_player_mut(c); | ||
*hand = hand.added(piece.piece_kind()).unwrap(); | ||
} | ||
} | ||
self.inner.side = c.flip(); | ||
self.inner.side = c; | ||
self.inner.ply -= 1; | ||
self.states.pop(); | ||
} | ||
|
@@ -393,14 +381,14 @@ impl AttackInfo { | |
let ka = ATTACK_TABLE.ka.attack(sq, &occ); | ||
let hi = ATTACK_TABLE.hi.attack(sq, &occ); | ||
let ki = ATTACK_TABLE.ki.attack(sq, opp); | ||
let ou = ATTACK_TABLE.ou.attack(sq, opp); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inspired by |
||
let gi = ATTACK_TABLE.gi.attack(sq, opp); | ||
Self { | ||
checkers, | ||
checkables: [ | ||
ATTACK_TABLE.fu.attack(sq, opp), | ||
ATTACK_TABLE.ky.attack(sq, opp, &occ), | ||
ATTACK_TABLE.ke.attack(sq, opp), | ||
ATTACK_TABLE.gi.attack(sq, opp), | ||
gi, | ||
ki, | ||
ka, | ||
hi, | ||
|
@@ -409,8 +397,8 @@ impl AttackInfo { | |
ki, | ||
ki, | ||
ki, | ||
ka | ou, | ||
hi | ou, | ||
ka | ki, | ||
hi | gi, | ||
], | ||
pinned, | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unwrapped
king_position()
as this method should be called during evading