@Override
 public void nextHashInTier() {
   if (dbh.getHash() < dbh.numHashes() - 1) dbh.next();
   else if (numPieces[BLACK] == 0) {
     numPieces[BLACK] = numPieces[WHITE];
     numPieces[WHITE] = 0;
     dbh.setNums(boardSize - getTier(), 0, getTier());
     if (turn != 0) throw new RuntimeException("Tier finished");
     else turn++;
   } else {
     dbh.setNums(boardSize - getTier(), ++numPieces[WHITE], --numPieces[BLACK]);
   }
   isChildrenValid = false;
 }
 public Reversi(Configuration conf) {
   super(conf);
   width = conf.getInteger("gamesman.game.width", 8);
   height = conf.getInteger("gamesman.game.height", 8);
   boardSize = width * height;
   board = new Cell[height][width];
   dbh = new DartboardHasher(boardSize, ' ', 'O', 'X');
   offsetTable = new long[boardSize + 1][2][];
   // initialize offset table
   for (int tier = 0; tier <= boardSize; tier++) {
     long total = 0;
     for (int turn = 0; turn < 2; turn++) {
       offsetTable[tier][turn] = new long[tier + 1];
       for (int offset = 0; offset <= tier; offset++) {
         dbh.setNums(boardSize - tier, offset, tier - offset);
         offsetTable[tier][turn][offset] = total;
         total += dbh.numHashes();
       }
     }
   }
   for (int row = 0; row < height; row++) {
     for (int col = 0; col < width; col++) {
       board[row][col] = new Cell(row, col, row * width + col);
     }
   }
   turn = BLACK;
   board[height / 2 - 1][width / 2 - 1].setPiece('X');
   board[height / 2][width / 2 - 1].setPiece('O');
   board[height / 2 - 1][width / 2].setPiece('O');
   board[height / 2][width / 2].setPiece('X');
   isChildrenValid = false;
   children = newStateArray(maxChildren());
   stringMoves = new String[maxChildren()]; // only for testing.
   oldPosition = new char[boardSize];
   tempPosition = new char[boardSize];
 }