github.com/gorgonia/agogo@v0.1.1/game/komi/zobrist.go (about) 1 package komi 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 [361 * 2]int32 // backing storage 26 it [][]int32 // iterator for the normal hash 27 hash int32 28 koHash int32 29 size int 30 } 31 32 func makeZobrist(m, n int) zobrist { 33 r := rand.New(rand.NewSource(time.Now().UnixNano())) 34 size := m * n 35 retVal := zobrist{ 36 size: size, 37 } 38 for i := range retVal.table[:size+1] { 39 retVal.table[i] = r.Int31() 40 } 41 retVal.makeIterator() 42 return retVal 43 } 44 45 // update calculates the hash and returns it. As per the namesake, the calculated hash is updaated as a side effect. 46 func (z *zobrist) update(m game.PlayerMove) (int32, error) { 47 switch game.Colour(m.Player) { 48 case game.Black: 49 z.hash ^= z.it[m.Single][0] 50 return z.hash, nil 51 case game.White: 52 z.hash ^= z.it[m.Single][1] 53 return z.hash, nil 54 default: 55 return 0, errors.Errorf("Cannot update hash for %v", m) 56 } 57 } 58 59 func (z *zobrist) clone() zobrist { 60 retVal := zobrist{ 61 hash: z.hash, 62 koHash: z.koHash, 63 size: z.size, 64 } 65 copy(retVal.table[:], z.table[:]) 66 retVal.makeIterator() 67 return retVal 68 }