I am implementing a specialized hashtable. I'm trying store a lot of data in a single 64-bit int key, for space usage and performance reasons.
Each key should have this structure:
// Key structure, from LSB
// eval result (16 bits)
// move (16 bits)
// age (16 bits): the move of the game on which this position would have occurred
// depth (8 bits)
// node type (8 bits): from the three constants above
Here is a simple implementation:
var keys [1000]uint64
var values [1000]uint64
func Put(b *dragontoothmg.Board, m dragontoothmg.Move, eval int16, depth uint8, ntype uint8) {
var value uint64 = uint64(eval) | (uint64(m) << 16) | (uint64(b.Fullmoveno) << 32) |
(uint64(depth) << 48) | (uint64(ntype) << 56)
hash := b.Hash()
key := hash ^ value
index := hash % uint64(len(keys))
keys[index] = key
values[index] = value
}
func Get(b *dragontoothmg.Board) (found bool, move dragontoothmg.Move,
eval int16, depth uint8, ntype uint8) {
hash := b.Hash()
index := hash % uint64(len(keys))
key := keys[index]
value := values[index]
found = (hash == (key ^ value))
if !found {
return false, 0, 0, 0, 0
}
eval = int16(value & 0xFFFF)
move = dragontoothmg.Move((value >> 16) & 0xFFFF)
depth = uint8((value >> 48) & 0xFF)
ntype = uint8((value >> 56) & 0xFF)
return
}
However, when I try to Get()
the data, it comes back corrupted. I suspect this might be related to the fact that eval
is a signed int, and the cast converts it to a signed uint64. What have I done wrong, and how can I fix it?
This is failing test result:
--- FAIL: TestSimpleTt (0.10s)
transtable_test.go:37: Simple ttable test failed.
Put data: (board: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 0) e2e4 -30 6 2
Fetched data: true h8h8 -30 255 255
FAIL
h8h8
is the maximum value of the field, for what it's worth.