/* @(#)ConcentrationGame.java 26 September 2007 */ import edu.neu.ccs.*; import edu.neu.ccs.gui.*; import edu.neu.ccs.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** *
The class for the Concentration game.
* *Uses Java Power Tools 2.6.0.
* *Copyright, Richard Rasala, 2007.
* * @author Richard Rasala */ class ConcentrationGame extends DisplayPanel { /** The minimum tile size: 50. */ public static final int MINIMUM_TILE_SIZE = 50; /** The minimum grid size: 3. */ public static final int MINIMUM_GRID_SIZE = 3; /** The maximum grid size: 10. */ public static final int MAXIMUM_GRID_SIZE = 10; /** The paintables for the current game. */ protected Paintable[] paintables = null; /** The length of the current paintables array. */ protected int length = 0; /** The tile size in pixels. */ protected int tileSize = 0; /** The game grid size. */ protected int gridSize = 0; /** The middle index to skip if the grid size is odd. */ protected int gridSkip = -1; /** *The count of active tiles in the game grid.
* *
If gridSize is even,
* this is gridSize*gridSize.
If gridSize is odd,
* this is gridSize*gridSize-1.
The tile boxes in the grid.
* *The array size should be tileCount.
* The tiles should inserted in the paintable sequence
* by rows. If gridSize is odd, then the
* center tile position should be skipped.
The paintable contents corresponding to the tile boxes.
* *The array size should be tileCount.
The paintable contents[i] should correspond
* to the tile tiles[i].
The constructor that supplies the paintables, * the tile size, and the grid size.
* *If the paintables are null then
* a default set of shape paintables will be used,
* and the tile size and grid size will be adjusted.
The tile size will be forced to be at least * MINIMUM_TILE_SIZE.
* *The grid size will be forced to be between * MINIMUM_GRID_SIZE and MAXIMUM_GRID_SIZE.
*/ public ConcentrationGame (Paintable[] paintables, int tileSize, int gridSize) { if ((paintables == null) || (paintables.length < 1)) { GamePaintables gamePaintables = new GamePaintables(); paintables = gamePaintables.getShapePaintables(); tileSize = gamePaintables.getTileSize(); gridSize = 6; } tileSize = (tileSize > MINIMUM_TILE_SIZE) ? tileSize : MINIMUM_TILE_SIZE; gridSize = (gridSize > MAXIMUM_GRID_SIZE) ? MAXIMUM_GRID_SIZE : (gridSize < MINIMUM_GRID_SIZE) ? MINIMUM_GRID_SIZE : gridSize; this.paintables = paintables; this.tileSize = tileSize; this.gridSize = gridSize; length = paintables.length; initializeGame(); } /** The initializer. */ protected void initializeGame() { makeTiles(); makeGUI(); newGame(); } /** * Makes the tile boxes for the game * and related objects. */ protected void makeTiles() { tileCount = gridSize * gridSize; gridSkip = -1; if ((gridSize % 2) != 0) { tileCount --; gridSkip = gridSize / 2; } tiles = new TileBox[tileCount]; contents = new Paintable[tileCount]; int spacing = tileSize + gap; XRect bounds = new XRect(0, 0, tileSize, tileSize); blank = new ShapePaintable(); blank.setDefaultOriginalBounds2D(bounds); int index = 0; for (int row = 0; row < gridSize; row++) { int y = gap + row * spacing; for (int col = 0; col < gridSize; col++) { if ((row == gridSkip) && (col == gridSkip)) continue; int x = gap + col * spacing; TileBox tile = tiles[index] = new TileBox(blank); tile.setDefaultOriginalBounds2D(bounds); tile.moveCornerTo(x, y); tile.setBackgroundPaint(tileBackground); sequence.appendPaintable(tile); index++; } } int pixels = gap + gridSize * spacing; XRect sequenceBounds = new XRect(0, 0, pixels, pixels); sequence.setDefaultBounds2D(sequenceBounds); } /** * Make the game GUI and add decorations. */ protected void makeGUI() { board.lineBorder(Colors.black, 2); board.setBackground(gameBackground); board.setOpaque(true); newGameButton.setBackground(buttonBackground); revealAllButton.setBackground(buttonBackground); Object[] buttonStuff = { newGameButton, revealAllButton }; HTable buttonTable = new HTable(buttonStuff, 2 * gap, 2 * gap, CENTER); buttonTable.setBackground(panelBackground); Object[] mainStuff = { board, message, buttonTable }; VTable mainTable = new VTable(mainStuff, gap, gap, CENTER); mainTable.emptyBorder(gap); mainTable.setBackground(panelBackground); addObject(mainTable); adapter.addMouseClickedAction(clickAction); } /** Launch a new Concentration game. */ protected synchronized void newGame() { for (int i = 0; i < tileCount; i++) { tiles[i].setPaintable(blank); } guesses = 0; matches = 0; setMessage(); int[] indexList = selectRandomizedIndexList(); for (int i = 0; i < tileCount; i++) { int k = indexList[i]; contents[i] = paintables[k]; } index1 = -1; index2 = -1; } /** *Return a list of paintable indices * that have been selected randomly, * then duplicated to produce index pairs, * and then randomized again.
* *The size of the array returned is
* tileCount.
This main method opens a new ConcentrationOptions
* panel in a frame. From that panel, one or more instances of a
* ConcentrationGame may be opened.
If args are supplied, they are passed to the constructor
* of the ConcentrationOptions panel.