Part one: POJOs behind the game

This is part one of the Minesweeper portlet tutorial.



The source classes can be found in the minesweeper/src/main directory. The Game class represents a single minesweeper game session. It has one GameBoard object which contains a two dimensional array of Cell objects. Each Cell object represents a square in the game board.
public class Game {
    public long score = 0;
    private GameBoard gameBoard;
    private GameState gameState = GameState.ACTIVE;
}

public class GameBoard {
    private Cell[][] cells;
}

public class Cell {
    private GameBoard gameBoard;
    private boolean mine;
    private int x;
    private int y;
    private boolean clicked;
}

Handling the click

The main functionality of the Game class is the handling of the click event. Depending on the clicked cell the click can result in:
  • Uncovering a number, which tells how many mines lay hidden in the eight surrounding cells.
  • Uncovering an empty cell, and revealing all empty cells in the area.
  • Uncovering a mine, and the game is lost.
  • Uncovering the last clear cell, and winning the game.
The Game object delegates the click event to GameBoard and handles the losing and winning of the game.
public class Game {
   public void click(int x, int y) {
        Cell cell = gameBoard.click(x,y);
        if (cell.isMine()) {
            gameState = GameState.LOST;
            gameBoard.clickAll();
        } else if (gameBoard.isAllCleared()) {
            gameState = GameState.WIN;
            score = MAX_TIME - (System.currentTimeMillis() - startTime);
            if (score < 0) {
                score = 0;
            }
            gameBoard.clickAll();
        }
    }
}
The GameBoard delegates the click to the corresponding Cell object and handles the special case of uncovering all empty cells in the area if the cell is empty (count == 0).
public class GameBoard {
    public Cell click(int x, int y) {
        Cell cell = get(x, y);
        click(cell);
        return cell;
    }

    protected void click(Cell cell) {
        if (!cell.isClicked()) {
            cell.click();
            if (!cell.isMine()) {
                int count = cell.countNearMines();
                if (count == 0) {
                    click(listNear(cell));
                }
            }
        }
    }

    protected void click(Collection<Cell> cells) {
        for (Cell cell : cells) {
            click(cell);
        }
    }
}
The Cell just updates its state to clicked.
public class Cell {
    public void click() {
        clicked = true;        
    }
}

Generating the game board html

The Cell has methods which are used to generate the html for the game board.
public class Cell {
    public String getLabel() {
        if (clicked) {
            if (mine || countNearMines() == 0) {
                return "";
            } else {
                return String.valueOf(countNearMines());
            }
        } else {
            return "";
        }
    }

    public String getCssClass() {
        if (clicked) {
            StringBuilder builder = new StringBuilder();
            builder.append("clicked ");
            if (mine) {
                builder.append("mine");
            } else {
                builder.append("near-mines-" + countNearMines());
            }
            return builder.toString();
        } else {
            return "not-clicked";
        }
    }
}
These methods are used in the freemarker template _game_board.ftl.
<td class="${cell.cssClass}" xloc="${cell.x?c}" yloc="${cell.y?c}" >${cell.label}</td>
The actual style is defined in the minesweeper.css file.

Continue to Part two: Making the portlet with Struts2

No comments:

Post a Comment