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  }