Spiral 4 – implementing the rules

However, wait! Our game can only work if the same color appears in only two cells: a cell and its twin cell. Moreover, a cell can be hidden or not: can the color be seen or not? To take care of this, the Cell class gets two new attributes:

  Cell twin;
  bool hidden = true;

Note

For the code files of this section, refer to Chapter 7codeeduc_memory_gamespiralss04 in the code bundle.

The _colorBox method in the Board class can now show the color of the cell when hidden is false (line (2)); when hidden = true (the default state), a neutral gray color will be used for the cell (line (1)):

  static const String COLOR_CODE = '#f0f0f0';

We also gave the gap variable a better name, boxSize:

void _colorBox(Cell cell) {
    var x = cell.column * boxSize;
    var y = cell.row * boxSize;
    context.beginPath();
    if (cell.hidden) {
      context.fillStyle = COLOR_CODE;                     (1)
    } else {
      context.fillStyle = colorMap[cell.color];           (2)
    }
// same code as in Spiral 3
}

The lines (1) and (2) can also be stated more succinctly with the ? ternary operator. Remember that the drawing changes because the _colorBox method is called via drawing at 60 frames per second and the board can react to a mouse click. In this spiral, we will show a cell when it is clicked together with its twin cell and then they will stay visible. Attaching an event handler for this is easy. We add the following line to the Board constructor:

querySelector('#canvas').onMouseDown.listen(onMouseDown);

The onMouseDown event handler has to know on which cell the click occurred. The mouse event e contains the coordinates of the click in its e.offset.x and e.offset.y properties (lines (3) and (4)). We will obtain the cell's row and column by using a truncating division ~/ operator dividing the x (which gives the column) and y (which gives the row) values by boxSize:

void onMouseDown(MouseEvent e) {
    int row = e.offset.y ~/ boxSize;                  (3)
    int column = e.offset.x ~/ boxSize;               (4)
    Cell cell = memory.getCell(row, column);          (5)
    cell.hidden = false;                              (6)
    cell.twin.hidden = false;                         (7)
}

Memory has a collection of cells. To get the cell with a specified row and column value, we will add a getCell method to memory and call it in line (5). When we have the cell, we will set its hidden property and that of its twin cell to false (lines (6) to (7)). The getCell method must return the cell at the given row and column. It loops through all the cells in line (8) and checks each cell, whether it is positioned at that row and column (line (9)). If yes, it will return that cell:

Cell getCell(int row, int column) {
    for (Cell cell in cells) {                        (8)
      if (cell.intersects(row, column)) {             (9)
        return cell;
      }
    }
}

For this purpose, we will add an intersects method to the Cell class. This checks whether its row and column match the given row and column for the current cell (see line (10)):

bool intersects(int row, int column) {
    if (this.row == row && this.column == column) {    (10)
      return true;
    }
    return false;
}

Now, we have already added a lot of functionality, but the drawing of the board will need some more thinking:

  • How to give a cell (and its twin cell) a random color that is not yet used?
  • How to attach a cell randomly to a twin cell that is not yet used?

To end this, we will have to make the constructor of Memory a lot more intelligent:

Memory(this.length) {
    if (length.isOdd) {                                   (1)
      throw new Exception(
          'Memory length must be an even integer: $length.'),
    }
    cells = new Cells();
    var cell, twinCell;
    for (var x = 0; x < length; x++) {
      for (var y = 0; y < length; y++) {
        cell = getCell(y, x);                             (2)
        if (cell == null) {                               (3)
          cell = new Cell(this, y, x);
          cell.color = _getFreeRandomColor();             (4)
          cells.add(cell);
          twinCell = _getFreeRandomCell();                (5)
          cell.twin = twinCell;                           (6)
          twinCell.twin = cell;
          twinCell.color = cell.color;
          cells.add(twinCell);
        }
      }
    }
}

The number of pairs given by ((length * length) / 2) must be even. This is only true if the length parameter of Memory itself is even, so we checked it in line (1). Again, we coded a nested loop and got the cell at that row and column. However, as the cell at that position has not yet been made (line (3)), we continued to construct it and assign its color and twin. In line (4), we called _getFreeRandomColor to get a color that is not yet used:

String _getFreeRandomColor() {
    var color;
    do {
      color = randomColor();
    } while (usedColors.any((c) => c == color));             (7)
    usedColors.add(color);                                   (8)
    return color;
}

The do…while loop continues as long as the color is already in a list of usedColors (this is elegantly checked with the any functional from Chapter 3, Structuring Code with Classes and Libraries). On exiting from the loop, we found an unused color, which is added to usedColors in line (8) and also returned. We then had to set everything for the twin cell. We searched for a free one with the _getFreeRandomCell method in line (5). Here, the do…while loop continues until a (row, column) position is found where cell == null is, meaning that we haven't yet created a cell there (line (9)). We will promptly do this in line (10):

Cell _getFreeRandomCell() {
    var row, column;
    Cell cell;
    do {
      row = randomInt(length);
      column = randomInt(length);
      cell = getCell(row, column);
    } while (cell != null);                               (9)
    return new Cell(this, row, column);                  (10)
}

From line (6) onwards, the properties of the twin cell are set and added to the list. This is all we need to produce the following result:

Spiral 4 – implementing the rules

Paired colored cells

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.4.174