-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add age to transposition table replacement scheme (#23)
- Loading branch information
Showing
10 changed files
with
346 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 111 additions & 20 deletions
131
src/main/java/com/kelseyde/calvin/transposition/HashEntry.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,139 @@ | ||
package com.kelseyde.calvin.transposition; | ||
|
||
import com.kelseyde.calvin.board.Move; | ||
import lombok.AllArgsConstructor; | ||
|
||
/** | ||
* Individual entry in the transposition table containing the 64-bit zobrist key, and a 64-bit encoding of the score, | ||
* move, flag and depth: | ||
* - score: 32 bits (-1000000-1000000, capturing negative -> positive checkmate score) | ||
* - move: 16 bits (0-5 = start square, 6-11 = end square, 12-15 = special move flag, see {@link Move}) | ||
* - flag: 4 bits (0-2, capturing three possible flag values + 1 bit padding) | ||
* - depth: 12 bits (0-265, max depth = 256 = 8 bits + 4 bit padding) | ||
* Entry in the {@link TranspositionTable}. Contains a 64-bit key and a 64-bit value which encodes the relevant | ||
* information about the position. | ||
* </p> | ||
* | ||
* Key encoding: | ||
* 0-47: 48 bits representing three-quarters of the zobrist hash. Used to verify that the position truly matches. | ||
* 48-63: 16 bits representing the generation of the entry, i.e. how old it is. Used to gradually replace old entries. | ||
* </p> | ||
* | ||
* Value encoding: | ||
* 0-11: the depth to which this position was last searched. | ||
* 12-15: the {@link HashFlag} indicating what type of node this is. | ||
* 16-31: the {@link Move} start square, end square, and special move flag. | ||
* 32-63: the eval of the position in centipawns. | ||
*/ | ||
public record HashEntry(long key, long value) { | ||
@AllArgsConstructor | ||
public class HashEntry { | ||
|
||
private static final long CLEAR_SCORE_MASK = 0xffffffffL; | ||
private static final long ZOBRIST_PART_MASK = 0x0000ffffffffffffL; | ||
private static final long GENERATION_MASK = 0xffff000000000000L; | ||
private static final long SCORE_MASK = 0xffffffff00000000L; | ||
private static final long MOVE_MASK = 0x00000000ffff0000L; | ||
private static final long FLAG_MASK = 0x000000000000f000L; | ||
private static final long DEPTH_MASK = 0x0000000000000fffL; | ||
|
||
private long key; | ||
private long value; | ||
|
||
/** | ||
* Extracts the 48-bits representing the zobrist part of the given zobrist key. | ||
*/ | ||
public static long zobristPart(long zobrist) { | ||
return zobrist & ZOBRIST_PART_MASK; | ||
} | ||
|
||
/** | ||
* Returns the 48-bits representing zobrist part of the hash entry key. | ||
*/ | ||
public long getZobristPart() { | ||
return key & ZOBRIST_PART_MASK; | ||
} | ||
|
||
/** | ||
* Gets the generation part of this entry's key. | ||
*/ | ||
public int getGeneration() { | ||
return (int) ((key & GENERATION_MASK) >>> 48); | ||
} | ||
|
||
/** | ||
* Sets the generation part of this entry's key. | ||
*/ | ||
public void setGeneration(int generation) { | ||
key = (key &~ GENERATION_MASK) | (long) generation << 48; | ||
} | ||
|
||
/** | ||
* Gets the score from this entry's value. | ||
*/ | ||
public int getScore() { | ||
long score = value >>> 32; | ||
long score = (value & SCORE_MASK) >>> 32; | ||
return (int) score; | ||
} | ||
|
||
/** | ||
* Sets the score in this entry's value. | ||
*/ | ||
public void setScore(int score) { | ||
value = (value &~ SCORE_MASK) | (long) score << 32; | ||
} | ||
|
||
/** | ||
* Creates a new {@link HashEntry} with the adjusted score. | ||
*/ | ||
public HashEntry withAdjustedScore(int score) { | ||
long newValue = (value &~ SCORE_MASK) | (long) score << 32; | ||
return new HashEntry(key, newValue); | ||
} | ||
|
||
/** | ||
* Sets the move in this entry's value. | ||
*/ | ||
public void setMove(Move move) { | ||
value = (value &~ MOVE_MASK) | (long) move.value() << 16; | ||
} | ||
|
||
/** | ||
* Gets the move from this entry's value. | ||
*/ | ||
public Move getMove() { | ||
long move = (value >> 16) & 0xffff; | ||
long move = (value & MOVE_MASK) >>> 16; | ||
return move > 0 ? new Move((short) move) : null; | ||
} | ||
|
||
/** | ||
* Gets the flag from this entry's value. | ||
*/ | ||
public HashFlag getFlag() { | ||
long flag = (value >>> 12) & 0xf; | ||
long flag = (value & FLAG_MASK) >>> 12; | ||
return HashFlag.valueOf((int) flag); | ||
} | ||
|
||
/** | ||
* Gets the depth from this entry's value. | ||
*/ | ||
public int getDepth() { | ||
return (int) value & 0xfff; | ||
return (int) (value & DEPTH_MASK); | ||
} | ||
|
||
public static HashEntry of(long zobristKey, int score, Move move, HashFlag flag, int depth) { | ||
/** | ||
* Creates a new {@link HashEntry} with the specified parameters. | ||
* | ||
* @param zobristKey the Zobrist key | ||
* @param score the score | ||
* @param move the move | ||
* @param flag the flag | ||
* @param depth the depth | ||
* @param generation the generation | ||
* @return a new {@link HashEntry} | ||
*/ | ||
public static HashEntry of(long zobristKey, int score, Move move, HashFlag flag, int depth, int generation) { | ||
// Build the key using 48 bits for the zobrist part and 16 bits for the generation part. | ||
long key = (zobristKey & ZOBRIST_PART_MASK) | (long) generation << 48; | ||
// Get the 16-bit encoded move | ||
long moveValue = move != null ? move.value() : 0; | ||
// Get the 3-bit encoded flag | ||
long flagValue = HashFlag.value(flag); | ||
// Combine the score, move, flag and depth to create the hash entry value | ||
long value = (long) score << 32 | moveValue << 16 | flagValue << 12 | depth; | ||
return new HashEntry(zobristKey, value); | ||
} | ||
|
||
public static HashEntry withScore(HashEntry entry, int score) { | ||
long value = (entry.value() & CLEAR_SCORE_MASK) | (long) score << 32; | ||
return new HashEntry(entry.key(), value); | ||
return new HashEntry(key, value); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.