+CACHE_LINE_ALIGNMENT
+
+Score pieceSquareTable[16][64]; // [piece][square]
+Value PieceValue[2][18] = { // [Mg / Eg][piece / pieceType]
+{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
+{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
+
+namespace Zobrist {
+
+Key psq[2][8][64]; // [color][pieceType][square / piece count]
+Key enpassant[8]; // [file]
+Key castle[16]; // [castleRight]
+Key side;
+Key exclusion;
+
+/// init() initializes at startup the various arrays used to compute hash keys
+/// and the piece square tables. The latter is a two-step operation: First, the
+/// white halves of the tables are copied from PSQT[] tables. Second, the black
+/// halves of the tables are initialized by flipping and changing the sign of
+/// the white scores.
+
+void init() {
+
+ RKISS rk;
+
+ for (Color c = WHITE; c <= BLACK; c++)
+ for (PieceType pt = PAWN; pt <= KING; pt++)
+ for (Square s = SQ_A1; s <= SQ_H8; s++)
+ psq[c][pt][s] = rk.rand<Key>();
+
+ for (File f = FILE_A; f <= FILE_H; f++)
+ enpassant[f] = rk.rand<Key>();
+
+ for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++)
+ {
+ Bitboard b = cr;
+ while (b)
+ {
+ Key k = castle[1ULL << pop_lsb(&b)];
+ castle[cr] ^= k ? k : rk.rand<Key>();
+ }
+ }
+
+ side = rk.rand<Key>();
+ exclusion = rk.rand<Key>();
+
+ for (PieceType pt = PAWN; pt <= KING; pt++)
+ {
+ PieceValue[Mg][make_piece(BLACK, pt)] = PieceValue[Mg][pt];
+ PieceValue[Eg][make_piece(BLACK, pt)] = PieceValue[Eg][pt];
+
+ Score v = make_score(PieceValue[Mg][pt], PieceValue[Eg][pt]);
+
+ for (Square s = SQ_A1; s <= SQ_H8; s++)
+ {
+ pieceSquareTable[make_piece(WHITE, pt)][ s] = (v + PSQT[pt][s]);
+ pieceSquareTable[make_piece(BLACK, pt)][~s] = -(v + PSQT[pt][s]);
+ }
+ }
+}
+
+} // namespace Zobrist
+