use crate::arrayvec::ArrayVec;
use crate::coretypes::MAX_HISTORY;
use crate::position::Game;
use crate::zobrist::{HashKind, ZobristTable};
type HashHistory = ArrayVec<HashKind, MAX_HISTORY>;
type Unrepeatables = ArrayVec<usize, MAX_HISTORY>;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct History {
hash_history: HashHistory, unrepeatables: Unrepeatables, head: usize, }
impl History {
pub fn empty() -> Self {
Self {
hash_history: HashHistory::new(),
unrepeatables: Unrepeatables::new(),
head: 0,
}
}
pub fn new(game: &Game, ztable: &ZobristTable) -> Self {
let mut history = Self::empty();
let mut position = game.base_position;
for move_ in &game.moves {
let hash = ztable.generate_hash((&position).into());
let move_info = position.do_legal_move(*move_).expect("move not legal");
history.push(hash, move_info.is_unrepeatable());
}
debug_assert_eq!(position, game.position);
history
}
pub fn push(&mut self, hash: HashKind, is_unrepeatable: bool) {
self.hash_history.push(hash);
if is_unrepeatable {
self.unrepeatables.push(self.head);
self.head = self.hash_history.len().checked_sub(1).unwrap_or(0);
}
}
pub fn pop(&mut self) {
self.hash_history.pop();
if self.head >= self.hash_history.len() {
self.head = self.unrepeatables.pop().unwrap_or(0);
}
}
pub fn contains(&self, hash: HashKind) -> bool {
self.contains_n(hash, 1)
}
pub fn contains_n(&self, hash: HashKind, count: usize) -> bool {
let mut counter = 0;
self.hash_history[self.head..].iter().rev().any(|old_hash| {
if *old_hash == hash {
counter += 1;
if counter >= count {
return true;
}
}
false
})
}
pub fn is_threefold_repetition(&self, hash: HashKind) -> bool {
self.contains_n(hash, 2)
}
pub fn is_twofold_repetition(&self, hash: HashKind) -> bool {
self.contains(hash)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Position;
#[test]
fn position_with_no_history() {
let ztable = ZobristTable::new();
let game = Game::from(Position::start_position());
let history = History::new(&game, &ztable);
assert_eq!(history.head, 0);
assert_eq!(history.hash_history.len(), 0);
assert_eq!(history.unrepeatables.len(), 0);
}
}