I’m writing a chess engine in Haskell (not my greatest idea) and have implemented Zobrist hashing, which is a form of incremental hashing. Before implementing hashing, this was my Game type:
data Pieces = Pieces
{ _pawns :: !Bitboard
, _knights :: !Bitboard
, _bishops :: !Bitboard
, _rooks :: !Bitboard
, _queens :: !Bitboard
, _kings :: !Bitboard
} deriving (Eq, Show)
mkLenses ''Pieces
data Game = Game
{ _gamePlaying :: Pieces
, _gameWaiting :: Pieces
, _gameCastling :: !Int
, _gameEnPassant :: !(Maybe Int)
, _gameTurn :: !Color
} deriving (Eq, Show)
makeLenses ''Game
For incremental hashing I came up with two approaches: adding the hash to the Game type
data Game = Game
{ _gamePlaying :: Pieces
, _gameWaiting :: Pieces
, _gameCastling :: !Int
, _gameEnPassant :: !(Maybe Int)
, _gameTurn :: !Color
, _gameHash :: !Int
} deriving (Eq, Show)
makeLenses ''Game
and creating a separate type that wraps Game
data HGame = HGame
{ _hgGame :: {-# UNPACK #-} !Game
, _hgHash :: !Int
} deriving (Eq, Show)
makeLenses ''HGame
None of these approaches are really satisfactory to me. The first approach isn’t great because ideally I’d like the board specific information (info required to generate moves) to stay separate from auxiliary info like the hash. The second approach is unwieldy because most of the time the code is accessing hgGame, not hgHash, which leaves lots of game ^. hgGame . whatever
in the code. It also causes some extra unboxing/reboxing to happen when the Game is passed to a function from within a HGame; I tried removing the UNPACK, performance got worse. I’ve also tried benchmarking both of these; performance is better during perft for the first approach, performance during searching is better for the second.
Is there any approach I’m overlooking? Can any of these be improved?