github.com/gorgonia/agogo@v0.1.1/game/wq/zobrist.go (about) 1 package 围碁 2 3 import ( 4 "math/rand" 5 "time" 6 7 "github.com/gorgonia/agogo/game" 8 "github.com/pkg/errors" 9 ) 10 11 // zobrist is a data structure for calculating Zobrist hashes. 12 // https://en.wikipedia.org/wiki/Zobrist_hashing 13 // 14 // The original implementation uses gorgonia's tensor 15 // Fundamentally it is a (BOARDSIZE, BOARDSIZE 2) 3-Tensor, which stores the hash state. 16 // The hash is then calculated from that 17 // But in light of optimizing all the things for memory, it's been stripped down to the absolute fundamentals: 18 // - a backing storage 19 // - an iterator for quick access 20 // 21 // The semantics of the iterator has also been updated. Given that the board will be updated 22 // with a game.Single, instead of a game.Coord, another way to think of the table is as a matrix of 23 // (BOARDSIZE * BOARDSIZE, 2). The design of the iterator is geared around that. 24 type zobrist struct { 25 table []int32 // backing storage 26 it [][]int32 // iterator for the normal hash 27 hash int32 28 koHash int32 29 } 30 31 func makeZobrist(size int) zobrist { 32 r := rand.New(rand.NewSource(time.Now().UnixNano())) 33 table, it := makeZobristTable(size) // see naughty.go 34 for i := range table { 35 table[i] = r.Int31() 36 } 37 return zobrist{ 38 table: table, 39 it: it, 40 } 41 } 42 43 // update calculates the hash and returns it. As per the namesake, the calculated hash is updaated as a side effect. 44 func (z *zobrist) update(m game.PlayerMove) (int32, error) { 45 switch game.Colour(m.Player) { 46 case game.Black: 47 z.hash ^= z.it[m.Single][0] 48 return z.hash, nil 49 case game.White: 50 z.hash ^= z.it[m.Single][1] 51 return z.hash, nil 52 default: 53 return 0, errors.Errorf("Cannot update hash for %v", m) 54 } 55 }