Skip to content

Commit

Permalink
Fix zobrist idx
Browse files Browse the repository at this point in the history
  • Loading branch information
bdmendes committed Dec 25, 2024
1 parent 3c1cb3a commit 9eeaa89
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 75 deletions.
22 changes: 19 additions & 3 deletions src/core/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl ZobristHash {
}

pub fn xor_piece(&mut self, piece: Piece, square: Square, color: Color) {
let idx = (color as usize) * (piece as usize) + square as usize;
let idx = (color as usize) * 6 * 64 + (piece as usize) * 64 + square as usize;
self.0 ^= ZOBRIST_NUMBERS[idx].0;
}

Expand All @@ -96,9 +96,9 @@ impl ZobristHash {

#[cfg(test)]
mod tests {
use crate::core::{castling_rights::CastlingSide, color::Color, piece::Piece, square::Square};

use super::ZobristHash;
use crate::core::{castling_rights::CastlingSide, color::Color, piece::Piece, square::Square};
use std::collections::HashSet;

#[test]
fn reflection() {
Expand Down Expand Up @@ -133,4 +133,20 @@ mod tests {
hash.xor_piece(Piece::King, Square::H8, Color::Black);
assert_eq!(hash.0, 0);
}

#[test]
fn piece_uniqueness() {
let mut hash = ZobristHash(0);
let mut seen = HashSet::new();

for piece in Piece::list() {
for color in Color::list() {
for square in Square::list() {
hash.xor_piece(*piece, *square, *color);
assert!(!seen.contains(&hash.0));
seen.insert(hash.0);
}
}
}
}
}
3 changes: 0 additions & 3 deletions src/core/moves/make.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ fn make_castle<const UPDATE_META: bool>(

pub fn make_move<const UPDATE_META: bool>(position: &Position, mov: Move) -> Position {
let mut position = *position;
if position.piece_at(mov.from()).is_none() {
panic!("m: {}", mov);
}
let piece = position.piece_at(mov.from()).unwrap();
let side_to_move = position.side_to_move();

Expand Down
1 change: 1 addition & 0 deletions src/core/moves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ impl Move {
|| (self.is_capture()
&& self.flag() != MoveFlag::EnpassantCapture
&& to_color != Some(position.side_to_move.flipped()))
|| (!self.is_capture() && to_color.is_some())
{
return false;
}
Expand Down
3 changes: 0 additions & 3 deletions src/evaluation/moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ use crate::{

pub fn evaluate_move(position: &Position, mov: Move) -> ValueScore {
let mut score = 0;
if position.piece_at(mov.from()).is_none() {
panic!("m: {}", mov);
}
let moving_piece = position.piece_at(mov.from()).unwrap();

if mov.is_capture() {
Expand Down
23 changes: 3 additions & 20 deletions src/search/movepick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
evaluation::{moves::evaluate_move, Evaluable, ValueScore},
};
use rand::{thread_rng, Rng};
use std::{sync::Arc, thread::panicking};
use std::sync::Arc;

type ScoredVec<Move> = Vec<(Move, ValueScore)>;

Expand All @@ -28,12 +28,7 @@ impl MovePicker<true> {
});
Self {
index: 0,
moves: decorate_moves_with_score(&moves, |mov| {
if mov.to_string().as_str() == "a1c1=N" || mov.to_string().as_str() == "a1g1=N" {
panic!("p2: {}", position.fen());
}
evaluate_move(position, mov)
}),
moves: decorate_moves_with_score(&moves, |mov| evaluate_move(position, mov)),
stage: MoveStage::CapturesAndPromotions,
position: *position,
table: None,
Expand Down Expand Up @@ -90,14 +85,7 @@ impl std::iter::Iterator for MovePicker<false> {
self.stage = MoveStage::CapturesAndPromotions;
self.moves = decorate_moves_with_score(
&self.position.moves(MoveStage::CapturesAndPromotions),
|mov| {
if mov.to_string().as_str() == "a1c1=N"
|| mov.to_string().as_str() == "a1g1=N"
{
panic!("p4: {}", self.position.fen());
}
evaluate_move(&self.position, mov)
},
|mov| evaluate_move(&self.position, mov),
);

self.index = 0;
Expand All @@ -112,11 +100,6 @@ impl std::iter::Iterator for MovePicker<false> {
if killers[1] == Some(mov) || killers[0] == Some(mov) {
Piece::Queen.value()
} else {
if mov.to_string().as_str() == "a1c1=N"
|| mov.to_string().as_str() == "a1g1=N"
{
panic!("p6: {}", self.position.fen());
}
evaluate_move(&self.position, mov)
}
});
Expand Down
55 changes: 9 additions & 46 deletions src/search/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ use portable_atomic::AtomicU128;

use super::{Depth, MAX_DEPTH};
use crate::{
core::{
moves::{make::make_move, Move},
Position,
},
core::{moves::Move, Position},
evaluation::{Score, ValueScore},
};
use std::{
Expand Down Expand Up @@ -37,7 +34,7 @@ struct TableEntry {
pub best_move: Move,
pub score_type: ScoreType,
pub depth: Depth,
pub age: bool,
pub age: u8,
pub hash: u64,
pub pad: u8,
}
Expand All @@ -49,7 +46,7 @@ impl TableEntry {
best_move: Move,
depth: Depth,
hash: u64,
age: bool,
age: u8,
) -> Self {
TableEntry { score, best_move, depth, hash, age, score_type, pad: 0 }
}
Expand All @@ -69,13 +66,13 @@ impl TableEntry {

struct TranspositionTable {
data: Vec<AtomicU128>,
age: bool,
age: u8,
}

impl TranspositionTable {
pub fn new(size_mb: usize) -> Self {
let data_len = Self::calculate_data_len(size_mb);
Self { data: (0..data_len).map(|_| AtomicU128::new(NULL_TT_ENTRY)).collect(), age: false }
Self { data: (0..data_len).map(|_| AtomicU128::new(NULL_TT_ENTRY)).collect(), age: 0 }
}

fn calculate_data_len(size_mb: usize) -> usize {
Expand Down Expand Up @@ -152,7 +149,7 @@ impl SearchTable {
// This is both faster and more effective than clearing the table completely,
// since we can profit from older entries that are still valid.
let mut tt = self.transposition.write().unwrap();
tt.age = !tt.age;
tt.age = tt.age.saturating_add(1);

// Killer moves are no longer at the same ply, so we clear them.
self.killer_moves.iter().for_each(|entry| entry.store(NULL_KILLER, Ordering::Relaxed));
Expand All @@ -168,20 +165,7 @@ impl SearchTable {
.unwrap()
.get(position)
.map(|entry| entry.best_move)
.filter(|e| {
if e.from() == e.to() {
println!("AAAAAAAAAAA");
};
true
})
.filter(|mov| mov.is_pseudo_legal(position))
.filter(|m| {
// Work around hash collisions.
// Our saved hash is a bit too short. Let's workaround that for now,
// and improve on 2.0.
let new_position = make_move::<false>(position, *m);
!new_position.is_check()
})
}

pub fn get_table_score(
Expand Down Expand Up @@ -318,31 +302,10 @@ mod tests {
},
};

#[test]
fn entry_packing() {
let entry1 = TableEntry::new(100, ScoreType::Exact, Move(0), MAX_DEPTH, 0, true);
let entry2 = TableEntry::new(100, ScoreType::Exact, Move(0), 0, 1, false);
let entry3 = TableEntry::new(100, ScoreType::Exact, Move(0), 1, 2, true);
let entry4 = TableEntry::new(100, ScoreType::Exact, Move(0), 2, 3, false);

assert_eq!(entry1.depth, MAX_DEPTH);
assert_eq!(entry2.depth, 0);
assert_eq!(entry3.depth, 1);
assert_eq!(entry4.depth, 2);

assert_eq!(entry1.score, 100);
assert_eq!(entry1.score_type, ScoreType::Exact);

assert!(entry1.age);
assert!(!entry2.age);
assert!(entry3.age);
assert!(!entry4.age);
}

#[test]
fn entry_transmutation() {
let entry1 = TableEntry::new(100, ScoreType::Exact, Move(0), MAX_DEPTH, 0, true);
let entry2 = TableEntry::new(100, ScoreType::Exact, Move(0), 0, 1, false);
let entry1 = TableEntry::new(100, ScoreType::Exact, Move(0), MAX_DEPTH, 0, 0);
let entry2 = TableEntry::new(100, ScoreType::Exact, Move(0), 0, 1, 1);

assert!(entry1.raw() != entry2.raw());

Expand All @@ -361,7 +324,7 @@ mod tests {
let first_move =
Move::new(Square::E2, Square::E4, crate::core::moves::MoveFlag::DoublePawnPush);
let first_move_entry =
TableEntry::new(100, ScoreType::Exact, first_move, 2, position.hash().0, true);
TableEntry::new(100, ScoreType::Exact, first_move, 2, position.hash().0, 1);

table.insert(&position, first_move_entry, false);

Expand Down

0 comments on commit 9eeaa89

Please sign in to comment.