![JAR search and dependency download from the Maven repository](/logo.png)
org.ggp.base.apps.kiosk.templates.GameCanvas_FancyGrid Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alloy-ggp-base Show documentation
Show all versions of alloy-ggp-base Show documentation
A modified version of the GGP-Base library for Alloy.
The newest version!
package org.ggp.base.apps.kiosk.templates;
import java.awt.Graphics;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.ggp.base.util.statemachine.MachineState;
/**
* GameCanvas_FancyGrid expands on the GameCanvas_SimpleGrid model, with
* additional features based on situations that commonly occur when writing
* game visualizations. These features make stronger assumptions about the
* game being visualized, and so may not be appropriate for all games.
* These assumptions, in addition to the GameCanvas_SimpleGrid assumptions,
* are as follows:
*
* 1) Each cell of the grid can be drawn independently,
* using the following layers:
*
* a) Background layer, based only on coordinates.
* b) Content layer, based only on game propositions.
* c) Foreground layer, based only on coordinates.
* d) Selection layer, based only on the coordinates
* and the currently selected move.
*
* 2) The game propositions required to render the content layer
* of a given cell can be determined from the current state of
* the game and the cell's coordinates. As a result, they will
* not change unless the game state changes.
*
* 3) Each cell has a certain number of moves associated with it.
* These moves can be determined from the current state of the
* game and the cell's coordinates. As a result, they will not
* change unless the game state changes.
*
* NOTE: Multiple cells can share the same moves.
*
* Given these assumptions, GameCanvas_FancyGrid handles a lot of the work
* associated with selecting moves, rendering the grid, and caching useful
* parts of the game state. The player will be able to select their move by
* clicking on a cell: if there are multiple moves associated with the cell,
* they can click on the cell multiple times to cycle through them.
*
* To reflect the above assumptions, GameCanvas_FancyGrid overrides the
* andleClickOnCell() and clearMoveSelection() methods, and instead provides
* the following abstract methods:
*
* getFactsAboutCell(x,y) Get all facts associated with a cell.
* getLegalMovesForCell(x,y) Get all legal moves associated with a cell.
*
* renderCellBackground(g,x,y) Draw the background for a cell.
* renderCellContent(g,fact) Draw the content for a cell, given its fact.
* renderCellContent(g,facts) Draw the content for a cell, given its facts.
* renderCellForeground(g,x,y) Draw the foreground for a cell.
*
* renderMoveSelectionForCell(g,x,y,move) Draw the move selection for a cell.
*
* One common situation involves each cell having exactly one fact associated
* with it, often of the form "(cell 1 1 x)". In this situation, it's more convenient
* to have that single fact extracted and passed to renderCellContent() as a String,
* rather than as a {@code Set} containing one element. If you want that automatic
* extraction done, override the renderCellContent() method that takes a String as its
* second parameter. Otherwise, if your getFactsAboutCell() method is expected to return
* multiple facts about the same cell, override the renderCellContent() method that takes
* a {@code Set} as its second parameter.
*
* Another common situation involves having a game where you want to automatically
* display the grid, drawing black boxes around grid cells and always highlighting
* the selected grid cell with a green border. This grid visualization will be done
* by default. If you want to disable it, override the "useGridVisualization" function
* so that it returns false.
*
* @author Sam Schreiber
*/
public abstract class GameCanvas_FancyGrid extends GameCanvas_SimpleGrid {
private static final long serialVersionUID = 1L;
protected abstract Set getFactsAboutCell(int xCell, int yCell);
protected abstract Set getLegalMovesForCell(int xCell, int yCell);
protected void renderCellBackground(Graphics g, int xCell, int yCell) {};
protected void renderCellForeground(Graphics g, int xCell, int yCell) {};
protected void renderMoveSelectionForCell(Graphics g, int xCell, int yCell, String theMove) {};
protected void renderCellContent(Graphics g, String theFact) {};
protected void renderCellContent(Graphics g, Set theFacts){
if(!theFacts.isEmpty()) {
if(theFacts.size() > 1) {
System.err.println("More than one fact for a cell? Unexpected!");
}
String theFact = theFacts.iterator().next();
renderCellContent(g, theFact);
}
}
protected boolean useGridVisualization() { return true; }
protected final boolean isSelectedCell(int xCell, int yCell) {
return (yCell == selectedRow && xCell == selectedColumn);
}
private int selectedRow = -1;
private int selectedColumn = -1;
private String currentSelectedMove;
private Iterator possibleSelectedMoves = null;
@Override
protected final void handleClickOnCell(int xCell, int yCell, int xWithin, int yWithin) {
if(selectedRow != yCell || selectedColumn != xCell || !possibleSelectedMoves.hasNext()) {
SortedSet theMoves = new TreeSet(getLegalMovesForCell(xCell, yCell));
if(theMoves.isEmpty())
return;
possibleSelectedMoves = theMoves.iterator();
}
selectedRow = yCell;
selectedColumn = xCell;
currentSelectedMove = possibleSelectedMoves.next();
submitWorkingMove(stringToMove(currentSelectedMove));
}
// Cache all of the facts about cells that we compute, since they should not
// change unless the game state changes.
private Map> factsCache = new HashMap>();
protected Set getCachedFactsAboutCell(int xCell, int yCell) {
int cellHash = xCell*getGridHeight()*2 + yCell;
Set cachedFacts = factsCache.get(cellHash);
if(cachedFacts != null)
return cachedFacts;
Set realFacts = getFactsAboutCell(xCell, yCell);
factsCache.put(cellHash, realFacts);
return realFacts;
}
// When the game state changes, clear our cache of known facts.
@Override
public void updateGameState(MachineState gameState) {
factsCache.clear();
super.updateGameState(gameState);
}
@Override
protected final void renderCell(Graphics g, int xCell, int yCell) {
renderCellBackground(g, xCell, yCell);
renderCellContent(g, getCachedFactsAboutCell(xCell, yCell));
if(useGridVisualization()) CommonGraphics.drawCellBorder(g);
renderCellForeground(g, xCell, yCell);
if(!currentSelectedMove.isEmpty()) {
renderMoveSelectionForCell(g, xCell, yCell, currentSelectedMove);
if(useGridVisualization() && isSelectedCell(xCell, yCell))
CommonGraphics.drawSelectionBox(g);
}
}
@Override
public final void clearMoveSelection() {
submitWorkingMove(null);
possibleSelectedMoves = null;
currentSelectedMove = "";
selectedColumn = -1;
selectedRow = -1;
repaint();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy