The Board Class
      Before we implement the Board
class, we'll need to tackle two interesting problems. First we have to
decide on a data structure. A Meteor puzzle board is basically a
5-by-10 grid of regular hexagons, which we can represent as an array of
50 Cell objects. Instead of using the Cell class directly, we'll use the BoardCell subclass, shown in Listing 5, which keeps track of the piece that occupies the cell: 
Listing 5. The BoardCell subclass
public class BoardCell extends Cell {
  private Piece piece = null;
  public Piece getPiece() {
    return piece;
  }
  public void setPiece(Piece piece) {
    this.piece = piece;
  }
}
  | 
 If we store all 50 board
cells of the board in an array, we'll have to write some tedious
initialisation code. This initialisation identifies the neighbouring
board cells for each cell of the board, as illustrated in Figure 3. For
instance, cell 0 has two neighbours: cell 1 in the east and cell 5 in
the southeast. Listing 6 shows the initializeBoardCell() method that is called from the constructor of the Board class to do this initialisation.
Figure 3. The board represented as an array of cells

Now that we've implemented the data structure for the board, we move on to the next problem: writing a placePiece()
method that puts a piece on the board. The hardest part of writing this
method is deciding whether the piece fits on the board at the given
position. One way to determine whether the piece fits is to first find
all the board cells that would be occupied by the cells of the piece if
it were placed on the board. After we have this set of board cells, we
can easily determine if the new piece would fit: all corresponding
board cells need to be empty and the piece needs to fit completely on
the board. This process is implemented by the findOccupiedBoardCells() method and placePiece() method shown in Listing 6. Note that we use the processed field of the PieceCell objects to avoid an infinite recursion in the findOccupiedBoardCells() method.
Listing 6. The Board class
public class Board {
  public static final int NUMBEROFCELLS = 50;
  public static final int NUMBEROFCELLSINROW = 5;
  private BoardCell[] boardCells = new BoardCell[NUMBEROFCELLS];
  public Board() {
    for (int i = 0; i < NUMBEROFCELLS; i++) {
      boardCells[i] = new BoardCell();
    }
    for (int i = 0; i < NUMBEROFCELLS; i++) {
      initializeBoardCell(boardCells[i], i);
    }
  }
  /**
   * Initialize the neighbours of the given boardCell at the given
   * index on the board
   */
  private void initializeBoardCell(BoardCell boardCell, int index) {
    int row = index/NUMBEROFCELLSINROW;
    // Check if cell is in last or first column
    boolean isFirst = (index%NUMBEROFCELLSINROW == 0);
    boolean isLast = ((index+1)%NUMBEROFCELLSINROW == 0);
    if (row%2 == 0) { // Even rows
      if (row != 0) {
        // Northern neighbours
        if (!isFirst) {
          boardCell.setNeighbour(Cell.NORTHWEST, boardCells[index-6]);
        }
        boardCell.setNeighbour(Cell.NORTHEAST, boardCells[index-5]);
      }
      if (row != ((NUMBEROFCELLS/NUMBEROFCELLSINROW)-1)) {
        // Southern neighbours
        if (!isFirst) {
          boardCell.setNeighbour(Cell.SOUTHWEST, boardCells[index+4]);
        }
        boardCell.setNeighbour(Cell.SOUTHEAST, boardCells[index+5]);
      }
    }
    else { // Uneven rows
      // Northern neighbours
      if (!isLast) {
        boardCell.setNeighbour(Cell.NORTHEAST, boardCells[index-4]);
      }
      boardCell.setNeighbour(Cell.NORTHWEST, boardCells[index-5]);
      // Southern neighbours
      if (row != ((NUMBEROFCELLS/NUMBEROFCELLSINROW)-1)) {
        if (!isLast) {
          boardCell.setNeighbour(Cell.SOUTHEAST, boardCells[index+6]);
        }
        boardCell.setNeighbour(Cell.SOUTHWEST, boardCells[index+5]);
      }
    }
    // Set the east and west neighbours
    if (!isFirst) {
      boardCell.setNeighbour(Cell.WEST, boardCells[index-1]);
    }
    if (!isLast) {
      boardCell.setNeighbour(Cell.EAST, boardCells[index+1]);
    }
  }
  public void findOccupiedBoardCells(
    ArrayList occupiedCells, PieceCell pieceCell, BoardCell boardCell) {
    if (pieceCell != null && boardCell != null && !pieceCell.isProcessed()) {
      occupiedCells.add(boardCell);
      
      /* Neighbouring cells can form loops, which would lead to an
         infinite recursion. Avoid this by marking the processed 
         cells. */
      
      pieceCell.setProcessed(true);
      // Repeat for each neighbour of the piece cell
      for (int i = 0; i < Cell.NUMBEROFSIDES; i++) {
        findOccupiedBoardCells(occupiedCells,
                               (PieceCell)pieceCell.getNeighbour(i),
                               (BoardCell)boardCell.getNeighbour(i));
      }
    }
  }
  public boolean placePiece(Piece piece, int boardCellIdx) {
    // We will manipulate the piece using its first cell
    return placePiece(piece, 0, boardCellIdx);
  }
  public boolean 
    placePiece(Piece piece, int pieceCellIdx, int boardCellIdx) {
    // We're going to process the piece
    piece.resetProcessed();
    // Get all the boardCells that this piece would occupy
    ArrayList occupiedBoardCells = new ArrayList();
    findOccupiedBoardCells(occupiedBoardCells,
                           piece.getPieceCell(pieceCellIdx),
                           boardCells[boardCellIdx]);
    if (occupiedBoardCells.size() != Piece.NUMBEROFCELLS) {
      // Some cells of the piece don't fall on the board
      return false;
    }
    for (int i = 0; i < occupiedBoardCells.size(); i++) {
      if (((BoardCell)occupiedBoardCells.get(i)).getPiece() != null)
        // The board cell is already occupied by another piece
        return false;
    }
    // Occupy the board cells with the piece
    for (int i = 0; i < occupiedBoardCells.size(); i++) {
      ((BoardCell)occupiedBoardCells.get(i)).setPiece(piece);
    }
    return true; // The piece fits on the board
  }
  public void removePiece(Piece piece) {
    for (int i = 0; i < NUMBEROFCELLS; i++) {
      // Piece objects are unique, so use reference equality
      if (boardCells[i].getPiece() == piece) {
        boardCells[i].setPiece(null);
      }
    }
  }
}
  | 
This completes the implementation of our initial solution. Let's put it to the test.