Implemented claim groups and the necessary code to properly propagate

claim groups to newly placed tiles and to existing tiles when a piecen is
placed or a tile is placed that joins groups. Whee!


git-svn-id: https://samskivert.googlecode.com/svn/trunk@359 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-10-16 09:31:46 +00:00
parent df898f60d1
commit 56873a6443
6 changed files with 714 additions and 264 deletions
@@ -1,14 +1,16 @@
//
// $Id: TileGeometryTest.java,v 1.2 2001/10/16 01:41:55 mdb Exp $
// $Id: TileGeometryTest.java,v 1.3 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.util.IntTuple;
/**
* A simple class for testing the tile geometry specifications by drawing
@@ -19,87 +21,18 @@ public class TileGeometryTest
{
public TileGeometryTest ()
{
ArrayList polys = new ArrayList();
ArrayList colors = new ArrayList();
// create polygons from the various tile features
for (int i = 0; i < TileUtil.TILE_FEATURES.length; i++) {
// convert tile index into x and y coordinates (in tile
// feature coords which will be converted to screen coords)
int x = 4 * (i % 5), y = 4 * (i / 5);
// the first feature is the background color
Object[] features = (Object[])TileUtil.TILE_FEATURES[i];
IntTuple base = (IntTuple)features[0];
// add a polygon containing the whole tile colored with the
// background color
colors.add(COLOR_MAP[base.left]);
Polygon poly = new Polygon();
poly.addPoint(((x + 0) * TILE_WIDTH) / 4,
((y + 0) * TILE_HEIGHT) / 4);
poly.addPoint(((x + 4) * TILE_WIDTH) / 4,
((y + 0) * TILE_HEIGHT) / 4);
poly.addPoint(((x + 4) * TILE_WIDTH) / 4,
((y + 4) * TILE_HEIGHT) / 4);
poly.addPoint(((x + 0) * TILE_WIDTH) / 4,
((y + 4) * TILE_HEIGHT) / 4);
polys.add(poly);
// the remainder are tuple/coordinate pairs
for (int f = 1; f < features.length; f += 2) {
IntTuple type = (IntTuple)features[f];
int[] coords = (int[])features[f+1];
// create a color for this polygon
colors.add(COLOR_MAP[type.left]);
// if this is a road segment, we need to create a special
// polygon
if (type.left == ROAD) {
poly = TileUtil.roadSegmentToPolygon(
coords[0], coords[1], coords[2], coords[3]);
// translate the polygon into our coordinate space
poly.translate((x * TILE_WIDTH)/4, (y * TILE_HEIGHT)/4);
} else {
// otherwise create the polygon directly from the coords
poly = new Polygon();
for (int c = 0; c < coords.length; c += 2) {
// translate and scale the coords accordingly
int fx = ((x + coords[c]) * TILE_WIDTH) / 4;
int fy = ((y + coords[c+1]) * TILE_HEIGHT) / 4;
poly.addPoint(fx, fy);
}
}
polys.add(poly);
}
for (int i = 0; i < TILE_TYPES; i++) {
_tiles[i] = new VenisonTile(i+1, false, NORTH, i % 5, i / 5);
}
// create our arrays
_polys = new Polygon[polys.size()];
polys.toArray(_polys);
_colors = new Color[colors.size()];
colors.toArray(_colors);
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
// paint our polygons
for (int i = 0; i < _polys.length; i++) {
g.setColor(_colors[i]);
g.fillPolygon(_polys[i]);
}
// outline the tiles
g.setColor(Color.black);
for (int i = 0; i < 20; i++) {
int x = i % 5, y = i / 5;
g.drawRect(TILE_WIDTH * x, TILE_HEIGHT * y,
TILE_WIDTH, TILE_HEIGHT);
// paint our tiles
for (int i = 0; i < _tiles.length; i++) {
_tiles[i].paint((Graphics2D)g, 0, 0);
}
}
@@ -121,12 +54,5 @@ public class TileGeometryTest
frame.show();
}
protected Polygon[] _polys;
protected Color[] _colors;
protected static Color[] COLOR_MAP = {
Color.red, // CITY
Color.green, // GRASS
Color.black // ROAD
};
protected VenisonTile[] _tiles = new VenisonTile[TILE_TYPES];
}
@@ -1,11 +1,13 @@
//
// $Id: AtlantiBoard.java,v 1.6 2001/10/16 01:41:55 mdb Exp $
// $Id: AtlantiBoard.java,v 1.7 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Arrays;
import java.util.Iterator;
import com.samskivert.swing.Controller;
@@ -343,7 +345,12 @@ public class VenisonBoard
TestDSet set = new TestDSet();
set.addTile(new VenisonTile(CITY_TWO, false, WEST, 0, 0));
set.addTile(new VenisonTile(CITY_FOUR, false, NORTH, 0, 1));
set.addTile(new VenisonTile(CITY_TWO, false, WEST, -1, 1));
set.addTile(new VenisonTile(CITY_TWO, false, WEST, -1, -1));
set.addTile(new VenisonTile(CURVED_ROAD, false, WEST, 0, 2));
VenisonTile target =
new VenisonTile(DISCONNECTED_CITY_TWO, false, NORTH, 0, 1);
set.addTile(target);
set.addTile(new VenisonTile(CITY_THREE, false, WEST, 1, 1));
set.addTile(new VenisonTile(CITY_THREE_ROAD, false, EAST, 1, 2));
set.addTile(new VenisonTile(CITY_THREE, false, NORTH, -1, 0));
@@ -353,6 +360,15 @@ public class VenisonBoard
VenisonTile placing = new VenisonTile(CITY_TWO, false, NORTH, 0, 0);
board.setTileToBePlaced(placing);
// set a feature group to test propagation
VenisonTile[] tiles = new VenisonTile[set.size()];
Iterator iter = set.elements();
for (int i = 0; iter.hasNext(); i++) {
tiles[i] = (VenisonTile)iter.next();
}
Arrays.sort(tiles);
TileUtil.setFeatureGroup(tiles, target, 0, 1, 0);
frame.getContentPane().add(board, BorderLayout.CENTER);
frame.pack();
SwingUtil.centerWindow(frame);
@@ -1,5 +1,5 @@
//
// $Id: AtlantiTile.java,v 1.5 2001/10/16 01:41:55 mdb Exp $
// $Id: AtlantiTile.java,v 1.6 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
@@ -24,8 +24,12 @@ import com.threerings.presents.dobj.DSet;
* Represents a single tile in play on the Venison game board.
*/
public class VenisonTile
implements DSet.Element, TileCodes, Cloneable
implements DSet.Element, TileCodes, Cloneable, Comparable
{
/** The starting tile. */
public static final VenisonTile STARTING_TILE =
new VenisonTile(CITY_ONE_ROAD_STRAIGHT, false, NORTH, 0, 0);
/** The tile type. */
public int type;
@@ -38,6 +42,20 @@ public class VenisonTile
/** The tile's x and y coordinates. */
public int x, y;
/** An array of claim group values that correspond to the features of
* this tile. If a piecen has claimed a feature on this tile or that
* connects to this tile, it will be represented here by a non-zero
* claim group in the array slot that corresponds to the claimed
* feature. */
public int[] claims;
/** A reference to our static feature descriptions. */
public int[] features;
/** A reference to the piecen on this tile or null if no piecen has
* been placed on this tile. */
// public Piecen piecen;
/**
* Constructs a tile with all of the supplied tile information.
*/
@@ -49,6 +67,12 @@ public class VenisonTile
this.orientation = orientation;
this.x = x;
this.y = y;
// grab a reference to our feature information
features = TileUtil.TILE_FEATURES[type-1];
// create our claims array
claims = new int[features.length/2];
}
/**
@@ -68,6 +92,62 @@ public class VenisonTile
// nothing doing
}
/**
* Looks for a feature in this tile that matches the supplied feature
* edge mask and returns the index of that feature in this tile's
* {@link #claims} array.
*
* @return the index of the matching feature or -1 if no feature
* matched.
*/
public int getFeatureIndex (int featureMask)
{
// translate the feature mask into our orientation
featureMask = TileUtil.translateMask(featureMask, -orientation);
for (int i = 0; i < features.length; i += 2) {
int fmask = features[i+1];
if ((fmask & featureMask) != 0) {
return i/2;
}
}
// no match
return -1;
}
/**
* Looks for a feature in this tile that matches the supplied feature
* edge mask and returns the claim group to which that feature belongs
* (which may be zero).
*
* @return the claim group to which the feature that matches the
* supplied mask belongs, or zero if no feature matched the supplied
* mask.
*/
public int getFeatureGroup (int featureMask)
{
int fidx = getFeatureIndex(featureMask);
return fidx < 0 ? 0 : claims[fidx];
}
/**
* Sets the claim group for the feature with the specified index. This
* also updates the claim group for any piecen that was placed on that
* feature as well.
*
* @param featureIndex the index of the feature to update.
* @param claimGroup the claim group to associate with the feature.
*/
public void setFeatureGroup (int featureIndex, int claimGroup)
{
Log.info("Setting feature group [tile=" + this +
", fidx=" + featureIndex + ", cgroup=" + claimGroup + "].");
claims[featureIndex] = claimGroup;
// TBD: update the piecen
}
/**
* Paints this tile to the specified graphics context at its assigned
* location, accounting for the supplied x and y offsets of the
@@ -97,8 +177,13 @@ public class VenisonTile
// draw our shapes using the proper orientation
GeneralPath[] paths = _shapes[tidx][orientation];
IntTuple[] types = _types[tidx];
for (int i = 0; i < paths.length; i++) {
g.setColor(COLOR_MAP[_types[tidx][i].left]);
if (claims[types[i].right] != 0) {
g.setColor(CLAIMED_COLOR_MAP[types[i].left]);
} else {
g.setColor(COLOR_MAP[types[i].left]);
}
g.fill(paths[i]);
}
@@ -118,6 +203,27 @@ public class VenisonTile
return new VenisonTile(type, hasShield, orientation, x, y);
}
/**
* Used to order tiles (which is done by board position).
*/
public int compareTo (Object other)
{
// we will either be compared to another tile or to a coordinate
// object
if (other instanceof VenisonTile) {
VenisonTile tile = (VenisonTile)other;
return (tile.x == x) ? y - tile.y : x - tile.x;
} else if (other instanceof IntTuple) {
IntTuple coord = (IntTuple)other;
return (coord.left == x) ? y - coord.right : x - coord.left;
} else {
// who knows...
return -1;
}
}
// documentation inherited
public Object getKey ()
{
@@ -153,14 +259,12 @@ public class VenisonTile
*/
protected void createShapes ()
{
System.out.println("Creating shapes " + this + ".");
int tidx = type-1;
ArrayList polys = new ArrayList();
ArrayList types = new ArrayList();
// the first feature is the background color
Object[] features = (Object[])TileUtil.TILE_FEATURES[tidx];
Object[] features = (Object[])TileUtil.TILE_FEATURE_GEOMS[tidx];
IntTuple base = (IntTuple)features[0];
// add a polygon containing the whole tile
@@ -253,6 +357,15 @@ public class VenisonTile
protected static Color[] COLOR_MAP = {
Color.red, // CITY
Color.green, // GRASS
Color.black // ROAD
Color.black, // ROAD
Color.yellow // CLOISTER
};
/** Maps feature types to colors for claimed features. */
protected static Color[] CLAIMED_COLOR_MAP = {
Color.red.darker(), // CITY
Color.green.darker(), // GRASS
Color.black.brighter(), // ROAD
Color.yellow.darker(), // CLOISTER
};
}
@@ -1,5 +1,5 @@
//
// $Id: TileCodes.java,v 1.3 2001/10/16 01:41:55 mdb Exp $
// $Id: TileCodes.java,v 1.4 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
@@ -58,7 +58,7 @@ public interface TileCodes
public static final int CITY_ONE_ROAD_STRAIGHT = 13;
/** A cloister tile. */
public static final int CLOISTER = 14;
public static final int CLOISTER_PLAIN = 14;
/** A cloister tile with a road extending from the cloister. */
public static final int CLOISTER_ROAD = 15;
@@ -78,6 +78,7 @@ public interface TileCodes
/** The number of different tile types. */
public static final int TILE_TYPES = 19;
/** A tile orientation constant indicating the tile is in its default
* orientation. */
public static final int NORTH = 0;
@@ -98,6 +99,7 @@ public interface TileCodes
public static final String[] ORIENT_NAMES =
new String[] { "N", "E", "S", "W" };
/** The tile image width in pixels. */
public static int TILE_WIDTH = 90;
@@ -113,4 +115,44 @@ public interface TileCodes
/** A tile edge constant indicating a road edge. */
public static final int ROAD = 2;
/** A constant indicating a cloister. */
public static final int CLOISTER = 3;
/** Bit mask for a north connecting feature. */
public static final int NORTH_F = 0x1 << 0;
/** Bit mask for an east connecting feature. */
public static final int EAST_F = 0x1 << 1;
/** Bit mask for a south connecting feature. */
public static final int SOUTH_F = 0x1 << 2;
/** Bit mask for a west connecting feature. */
public static final int WEST_F = 0x1 << 3;
/** Bit mask for a north by northeast connecting feature. */
public static final int NNE_F = 0x1 << 4;
/** Bit mask for an east by northeast connecting feature. */
public static final int ENE_F = 0x1 << 5;
/** Bit mask for an east by southeast connecting feature. */
public static final int ESE_F = 0x1 << 6;
/** Bit mask for a south by southeast connecting feature. */
public static final int SSE_F = 0x1 << 7;
/** Bit mask for a south by southwest connecting feature. */
public static final int SSW_F = 0x1 << 8;
/** Bit mask for a west by southwest connecting feature. */
public static final int WSW_F = 0x1 << 9;
/** Bit mask for a west by northwest connecting feature. */
public static final int WNW_F = 0x1 << 10;
/** Bit mask for a north by northwest connecting feature. */
public static final int NNW_F = 0x1 << 11;
}
@@ -1,5 +1,5 @@
//
// $Id: AtlantiManager.java,v 1.6 2001/10/16 01:41:55 mdb Exp $
// $Id: AtlantiManager.java,v 1.7 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
@@ -57,7 +57,7 @@ public class VenisonManager
// clear out the tile set
_venobj.setTiles(new DSet(VenisonTile.class));
_venobj.addToTiles(TileUtil.STARTING_TILE);
_venobj.addToTiles(VenisonTile.STARTING_TILE);
}
protected void turnWillStart ()
@@ -101,8 +101,16 @@ public class VenisonManager
public void handleEvent (MessageEvent event)
{
VenisonTile tile = (VenisonTile)event.getArgs()[0];
// don't do no checking at present
_venobj.addToTiles(tile);
// make sure this is a valid placement
if (TileUtil.isValidPlacement(_venobj.tiles.elements(), tile)) {
// add the tile to the tiles set
_venobj.addToTiles(tile);
} else {
Log.warning("Received invalid placement " + event + ".");
}
// end the turn
endTurn();
}
@@ -1,10 +1,11 @@
//
// $Id: TileUtil.java,v 1.4 2001/10/16 01:41:55 mdb Exp $
// $Id: TileUtil.java,v 1.5 2001/10/16 09:31:46 mdb Exp $
package com.threerings.venison;
import java.awt.Polygon;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
@@ -16,10 +17,6 @@ import com.samskivert.util.IntTuple;
*/
public class TileUtil implements TileCodes
{
/** The starting tile. */
public static final VenisonTile STARTING_TILE =
new VenisonTile(CITY_ONE_ROAD_STRAIGHT, false, NORTH, 0, 0);
/**
* Returns a list containing the standard tile set for the Venison
* game. The list is a clone, so it can be bent, folded and modified
@@ -165,6 +162,212 @@ public class TileUtil implements TileCodes
return matchedAnEdge;
}
/**
* When a tile is placed on the board, this method should be called on
* it to propagate existing claims to the appropriate features on this
* tile. It will determine if any city features are connected to
* cities that are already claimed, and if any road features are
* connected to roads that are already claimed and if any grassland is
* connected to grassland that is claimed.
*
* <p> If, in the process of initializing the claims for this tile, we
* discover that this tile connects two previously disconnected
* claims, those claims will be joined. The affected tiles and piecens
* will have their claim groups updated.
*
* @param tiles a sorted array of the tiles on the board (which need
* not include the tile whose features are being configured).
* @param tile the tile whose features should be configured.
*/
public static void initClaims (VenisonTile[] tiles, VenisonTile tile)
{
// obtain our neighboring tiles
VenisonTile[] neighbors = new VenisonTile[4];
neighbors[NORTH] = findTile(tiles, tile.x, tile.y-1);
neighbors[EAST] = findTile(tiles, tile.x+1, tile.y);
neighbors[SOUTH] = findTile(tiles, tile.x, tile.y+1);
neighbors[WEST] = findTile(tiles, tile.x-1, tile.y);
// for each feature in the tile, determine whether or not the
// neighboring tile's matching feature is claimed
for (int i = 0; i < tile.features.length; i += 2) {
int ftype = tile.features[i];
int fmask = tile.features[i+1];
int cgroup = 0;
// iterate over all of the possible adjacency possibilities
for (int c = 0; c < ADJADCENCY_MAP.length; c += 3) {
int mask = ADJADCENCY_MAP[c];
int dir = ADJADCENCY_MAP[c+1];
int opp_mask = ADJADCENCY_MAP[c+2];
// if this feature doesn't have this edge, skip it
if ((fmask & mask) == 0) {
continue;
}
// translate the target direction accordingly
dir = (dir + tile.orientation) % 4;
// make sure we have a neighbor in the appropriate
// direction
if (neighbors[dir] == null) {
continue;
}
// it looks like we have a match, so translate the target
// stuff into our orientation
mask = translateMask(mask, tile.orientation);
opp_mask = translateMask(opp_mask, tile.orientation);
if (cgroup != 0) {
// if we've already been assigned to a group, we
// propagate our group to the opposing feature
int fidx = neighbors[dir].getFeatureIndex(opp_mask);
if (fidx >= 0) {
setFeatureGroup(tiles, neighbors[dir],
fidx, cgroup, mask);
} else {
Log.warning("Can't join-propagate feature " +
"[self=" + tile +
", target=" + neighbors[dir] +
", fidx=" + fidx + ", cgroup=" + cgroup +
", destEdge=" + opp_mask +
", srcEdge=" + mask + "].");
}
} else {
// otherwise, we inherit the group of the opposing
// feature
cgroup = neighbors[dir].getFeatureGroup(opp_mask);
}
}
// finally initialize the feature's claim group
tile.claims[i/2] = cgroup;
}
}
/**
* Sets the claim group for the specified feature in this tile and
* propagates that claim group to all connected features.
*
* @param tiles a sorted array of the tiles on the board.
* @param tile the tile that contains the feature whose claim group is
* being set.
* @param featureIndex the index of the feature.
* @param claimGroup the claim group value to set.
* @param entryEdgeMask the edge from which we are propagating this
* claim group (to avoid traversing back over that edge when
* propagating the group further).
*/
public static void setFeatureGroup (
VenisonTile[] tiles, VenisonTile tile, int featureIndex,
int claimGroup, int entryEdgeMask)
{
// set the claim group for this feature on this tile
tile.setFeatureGroup(featureIndex, claimGroup);
// now propagate this feature to connected features
int ftype = tile.features[featureIndex*2];
int fmask = tile.features[featureIndex*2+1];
// iterate over all of the possible adjacency possibilities
for (int c = 0; c < ADJADCENCY_MAP.length; c += 3) {
int mask = ADJADCENCY_MAP[c];
int dir = ADJADCENCY_MAP[c+1];
int opp_mask = ADJADCENCY_MAP[c+2];
VenisonTile neighbor = null;
// if this feature doesn't have this edge, skip it
if ((fmask & mask) == 0) {
continue;
}
// figure out if this would be the tile from which we
// propagated into our current tile and skip it if so
opp_mask = translateMask(opp_mask, tile.orientation);
if ((opp_mask & entryEdgeMask) != 0) {
continue;
}
// make sure we have a neighbor in this direction
dir = (dir + tile.orientation) % 4;
switch (dir) {
case NORTH: neighbor = findTile(tiles, tile.x, tile.y-1); break;
case EAST: neighbor = findTile(tiles, tile.x+1, tile.y); break;
case SOUTH: neighbor = findTile(tiles, tile.x, tile.y+1); break;
case WEST: neighbor = findTile(tiles, tile.x-1, tile.y); break;
}
if (neighbor == null) {
continue;
}
// it looks like we have a match, so translate the target mask
// into our orientation
mask = translateMask(mask, tile.orientation);
// propagate, propagate, propagate
int fidx = neighbor.getFeatureIndex(opp_mask);
if (fidx >= 0) {
setFeatureGroup(tiles, neighbor, fidx, claimGroup, mask);
} else {
Log.warning("Can't propagate feature [self=" + tile +
", target=" + neighbor + ", fidx=" + fidx +
", cgroup=" + claimGroup + ", srcEdge=" + mask +
", destEdge=" + opp_mask + "].");
}
}
}
/**
* Translates the feature edge mask into the orientation specified.
* For a forward translation, provide a positive valued orientation
* constant. For a backward translation, provide a negative valued
* orientation constant.
*
* @return the translated feature mask.
*/
public static int translateMask (int featureMask, int orientation)
{
int[] map = FEATURE_ORIENT_MAP[0];
if ((featureMask & (NNE_F|ESE_F|SSW_F|WNW_F)) != 0) {
map = FEATURE_ORIENT_MAP[1];
} else if ((featureMask & (ENE_F|SSE_F|WSW_F|NNW_F)) != 0) {
map = FEATURE_ORIENT_MAP[2];
}
return xlateMask(map, featureMask, orientation);
}
/** {@link #translateMask} helper function. */
protected static int xlateMask (
int[] map, int featureMask, int orientation)
{
int index = 0;
for (int i = 0; i < map.length; i++) {
if (map[i] == featureMask) {
return map[(i + 4 + orientation) % 4];
}
}
return featureMask;
}
/**
* Locates and returns the tile with the specified coordinates.
*
* @param tiles a sorted tiles array.
*
* @return the tile with the requested coordinates or null if no tile
* exists at those coordinates.
*/
protected static VenisonTile findTile (VenisonTile[] tiles, int x, int y)
{
IntTuple coord = new IntTuple(x, y);
int tidx = Arrays.binarySearch(tiles, coord);
return (tidx >= 0) ? tiles[tidx] : null;
}
/**
* Returns the edge type for specified edge of the specified tile
* type.
@@ -250,6 +453,304 @@ public class TileUtil implements TileCodes
list.add(tile);
}
/** Used to figure out which edges match up to which when comparing
* adjacent tiles. */
protected static final int[] EDGE_MAP = new int[] {
-1, NORTH, -1,
WEST, -1, EAST,
-1, SOUTH, -1
};
/** A mapping from feature edge masks to tile directions and
* corresponding feature edge masks. */
protected static final int[] ADJADCENCY_MAP = new int[] {
NORTH_F, NORTH, SOUTH_F,
EAST_F, EAST, WEST_F,
SOUTH_F, SOUTH, NORTH_F,
WEST_F, WEST, EAST_F,
NNW_F, NORTH, SSW_F,
NNE_F, NORTH, SSE_F,
ENE_F, EAST, WNW_F,
ESE_F, EAST, WSW_F,
SSE_F, SOUTH, NNE_F,
SSW_F, SOUTH, NNW_F,
WSW_F, WEST, ESE_F,
WNW_F, WEST, ENE_F,
};
/** Mapping table used to rotate feature facements. */
public static final int[][] FEATURE_ORIENT_MAP = new int[][] {
// orientations rotate through one of three four-cycles
{ NORTH_F, EAST_F, SOUTH_F, WEST_F },
{ NNE_F, ESE_F, SSW_F, WNW_F },
{ ENE_F, SSE_F, WSW_F, NNW_F },
};
/** A table indicating which tiles have which edges. */
protected static final int[] TILE_EDGES = new int[] {
-1, -1, -1, -1, // null tile
CITY, CITY, CITY, CITY, // CITY_FOUR
CITY, CITY, GRASS, CITY, // CITY_THREE
CITY, CITY, ROAD, CITY, // CITY_THREE_ROAD
CITY, GRASS, GRASS, CITY, // CITY_TWO
CITY, ROAD, ROAD, CITY, // CITY_TWO_ROAD
GRASS, CITY, GRASS, CITY, // CITY_TWO_ACROSS
CITY, CITY, GRASS, GRASS, // DISCONNECTED_CITY_TWO
GRASS, CITY, GRASS, CITY, // DISCONNECTED_CITY_TWO_ACROSS
CITY, GRASS, GRASS, GRASS, // CITY_ONE
CITY, ROAD, ROAD, GRASS, // CITY_ONE_ROAD_RIGHT
CITY, GRASS, ROAD, ROAD, // CITY_ONE_ROAD_LEFT
CITY, ROAD, ROAD, ROAD, // CITY_ONE_ROAD_TEE
CITY, ROAD, GRASS, ROAD, // CITY_ONE_ROAD_STRAIGHT
GRASS, GRASS, GRASS, GRASS, // CLOISTER_PLAIN
GRASS, GRASS, ROAD, GRASS, // CLOISTER_ROAD
ROAD, ROAD, ROAD, ROAD, // FOUR_WAY_ROAD
GRASS, ROAD, ROAD, ROAD, // THREE_WAY_ROAD
ROAD, GRASS, ROAD, GRASS, // STRAIGHT_ROAD
GRASS, GRASS, ROAD, ROAD, // CURVED_ROAD
};
/** A table describing the features of each tile and their edge
* connectedness. */
protected static final int[][] TILE_FEATURES = new int[][] {
// one must offset tile type by one when indexing into this array
{ CITY, NORTH_F|EAST_F|SOUTH_F|WEST_F }, // CITY_FOUR
{ CITY, NORTH_F|EAST_F|WEST_F, // CITY_THREE
GRASS, SOUTH_F },
{ CITY, NORTH_F|EAST_F|WEST_F, // CITY_THREE_ROAD
GRASS, SSW_F,
GRASS, SSE_F,
ROAD, SOUTH_F },
{ CITY, NORTH_F|WEST_F, // CITY_TWO
GRASS, EAST_F|SOUTH_F },
{ CITY, NORTH_F|WEST_F, // CITY_TWO_ROAD
GRASS, ENE_F|SSW_F,
GRASS, ESE_F|SSE_F,
ROAD, EAST_F|SOUTH_F },
{ CITY, WEST_F|EAST_F, // CITY_TWO_ACROSS
GRASS, NORTH_F,
GRASS, SOUTH_F },
{ GRASS, WEST_F|SOUTH_F, // DISCONNECTED_CITY_TWO
CITY, NORTH_F,
CITY, EAST_F },
{ GRASS, NORTH_F|SOUTH_F, // DISCONNECTED_CITY_TWO_ACROSS
CITY, WEST_F,
CITY, EAST_F },
{ GRASS, EAST_F|SOUTH_F|WEST_F, // CITY_ONE
CITY, NORTH_F },
{ GRASS, ENE_F|SSW_F|WEST_F, // CITY_ONE_ROAD_RIGHT
GRASS, ESE_F|SSE_F,
ROAD, EAST_F|SOUTH_F,
CITY, NORTH_F },
{ GRASS, EAST_F|SSE_F, WNW_F, // CITY_ONE_ROAD_LEFT
GRASS, SSW_F|WSW_F,
ROAD, SOUTH_F|WEST_F,
CITY, NORTH_F },
{ GRASS, ENE_F|WNW_F, // CITY_ONE_ROAD_TEE
GRASS, ESE_F|SSE_F,
GRASS, SSW_F|WSW_F,
ROAD, EAST_F,
ROAD, SOUTH_F,
ROAD, WEST_F,
CITY, NORTH_F },
{ GRASS, ENE_F|WNW_F, // CITY_ONE_ROAD_STRAIGHT
GRASS, ESE_F, SOUTH_F, WSW_F,
ROAD, EAST_F|WEST_F,
CITY, NORTH_F },
{ GRASS, NORTH_F|EAST_F|SOUTH_F|WEST_F, // CLOISTER_PLAIN
CLOISTER, 0},
{ GRASS, NORTH_F|EAST_F|WEST_F, // CLOISTER_ROAD
CLOISTER, 0,
ROAD, SOUTH_F },
{ GRASS, WNW_F|NNW_F, // FOUR_WAY_ROAD
GRASS, NNE_F|ENE_F,
GRASS, ESE_F|SSE_F,
GRASS, SSW_F|WSW_F,
ROAD, NORTH_F,
ROAD, EAST_F,
ROAD, SOUTH_F,
ROAD, WEST_F },
{ GRASS, WNW_F|NORTH_F|ENE_F, // THREE_WAY_ROAD
GRASS, ESE_F|SSE_F,
GRASS, SSW_F|WSW_F,
ROAD, EAST_F,
ROAD, SOUTH_F,
ROAD, WEST_F },
{ GRASS, NNE_F|EAST_F|SSE_F, // STRAIGHT_ROAD
GRASS, SSW_F|WEST_F|NNW_F,
ROAD, NORTH_F|SOUTH_F },
{ GRASS, WNW_F|NORTH_F|EAST_F|SSE_F, // CURVED_ROAD
GRASS, SSW_F|WSW_F,
ROAD, SOUTH_F|WEST_F },
};
/** A table describing the geometry of the features (cities, roads,
* etc.) of each tile. */
protected static final Object[] TILE_FEATURE_GEOMS = new Object[] {
// one must offset tile type by one when indexing into this array
new Object[] { new IntTuple(CITY, 0), }, // CITY_FOUR
new Object[] { new IntTuple(CITY, 0), // CITY_THREE
new IntTuple(GRASS, 1),
new int[] { 0, 4, 1, 3, 3, 3, 4, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_THREE_ROAD
new IntTuple(GRASS, 1),
new int[] { 0, 4, 1, 3, 2, 3, 2, 4 },
new IntTuple(GRASS, 2),
new int[] { 2, 4, 2, 3, 3, 3, 4, 4 },
new IntTuple(ROAD, 3),
new int[] { 2, 3, 2, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO
new IntTuple(GRASS, 1),
new int[] { 0, 4, 4, 0, 4, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ROAD
new IntTuple(GRASS, 1),
new int[] { 0, 4, 4, 0, 4, 2, 2, 4 },
new IntTuple(GRASS, 2),
new int[] { 2, 4, 4, 2, 4, 4 },
new IntTuple(ROAD, 3),
new int[] { 2, 4, 4, 2 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ACROSS
new IntTuple(GRASS, 1),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(GRASS, 2),
new int[] { 0, 4, 1, 3, 3, 3, 4, 4 }},
new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO
new IntTuple(CITY, 1),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(CITY, 2),
new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }},
new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO_ACROSS
new IntTuple(CITY, 1),
new int[] { 0, 0, 1, 1, 1, 3, 0, 4 },
new IntTuple(CITY, 2),
new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE
new IntTuple(CITY, 1),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_RIGHT
new IntTuple(GRASS, 1),
new int[] { 2, 2, 4, 2, 4, 4, 2, 4 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 4, 2 },
new IntTuple(CITY, 3),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_LEFT
new IntTuple(GRASS, 1),
new int[] { 0, 2, 2, 2, 2, 4, 0, 4 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 2),
new int[] { 0, 2, 2, 2 },
new IntTuple(CITY, 3),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_TEE
new IntTuple(GRASS, 1),
new int[] { 2, 2, 4, 2, 4, 4, 2, 4 },
new IntTuple(GRASS, 2),
new int[] { 0, 2, 2, 2, 2, 4, 0, 4 },
new IntTuple(ROAD, 3),
new int[] { 0, 2, 2, 2 },
new IntTuple(ROAD, 4),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 5),
new int[] { 2, 2, 2, 4 },
new IntTuple(CITY, 6),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_STRAIGHT
new IntTuple(GRASS, 1),
new int[] { 0, 2, 4, 2, 4, 4, 0, 4 },
new IntTuple(ROAD, 2),
new int[] { 0, 2, 4, 2 },
new IntTuple(CITY, 3),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CLOISTER_PLAIN
new IntTuple(CLOISTER, 1),
new int[] { 1, 1, 3, 1, 3, 3, 1, 3 }},
new Object[] { new IntTuple(GRASS, 0), // CLOISTER_ROAD
new IntTuple(CLOISTER, 1),
new int[] { 1, 1, 3, 1, 3, 3, 1, 3 },
new IntTuple(ROAD, 2),
new int[] { 2, 3, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // FOUR_WAY_ROAD
new IntTuple(GRASS, 1),
new int[] { 2, 0, 4, 0, 4, 2, 2, 2 },
new IntTuple(GRASS, 2),
new int[] { 2, 2, 4, 2, 4, 4, 2, 4 },
new IntTuple(GRASS, 3),
new int[] { 0, 2, 2, 2, 2, 4, 0, 4 },
new IntTuple(ROAD, 4),
new int[] { 2, 0, 2, 2 },
new IntTuple(ROAD, 5),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 6),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 7),
new int[] { 0, 2, 2, 2 }},
new Object[] { new IntTuple(GRASS, 0), // THREE_WAY_ROAD
new IntTuple(GRASS, 1),
new int[] { 2, 2, 4, 2, 4, 4, 2, 4 },
new IntTuple(GRASS, 2),
new int[] { 0, 2, 2, 2, 2, 4, 0, 4 },
new IntTuple(ROAD, 3),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 4),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 5),
new int[] { 0, 2, 2, 2 }},
new Object[] { new IntTuple(GRASS, 0), // STRAIGHT_ROAD
new IntTuple(GRASS, 1),
new int[] { 0, 2, 4, 2, 4, 4, 0, 4 },
new IntTuple(ROAD, 2),
new int[] { 2, 0, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // CURVED_ROAD
new IntTuple(GRASS, 1),
new int[] { 0, 2, 2, 2, 2, 4, 0, 4 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 2),
new int[] { 0, 2, 2, 2 }},
};
/** The standard tile set for a game of Venison. */
protected static ArrayList TILE_SET = new ArrayList();
@@ -279,7 +780,7 @@ public class TileUtil implements TileCodes
addTiles(3, TILE_SET, new VenisonTile(CITY_ONE_ROAD_TEE, false));
addTiles(3, TILE_SET, new VenisonTile(CITY_ONE_ROAD_STRAIGHT, false));
addTiles(4, TILE_SET, new VenisonTile(CLOISTER, false));
addTiles(4, TILE_SET, new VenisonTile(CLOISTER_PLAIN, false));
addTiles(2, TILE_SET, new VenisonTile(CLOISTER_ROAD, false));
addTiles(1, TILE_SET, new VenisonTile(FOUR_WAY_ROAD, false));
@@ -287,160 +788,4 @@ public class TileUtil implements TileCodes
addTiles(8, TILE_SET, new VenisonTile(STRAIGHT_ROAD, false));
addTiles(9, TILE_SET, new VenisonTile(CURVED_ROAD, false));
}
/** Used to figure out which edges match up to which when comparing
* adjacent tiles. */
protected static final int[] EDGE_MAP = new int[] {
-1, NORTH, -1,
WEST, -1, EAST,
-1, SOUTH, -1
};
/** A table indicating which tiles have which edges. */
protected static final int[] TILE_EDGES = new int[] {
-1, -1, -1, -1, // null tile
CITY, CITY, CITY, CITY, // CITY_FOUR
CITY, CITY, GRASS, CITY, // CITY_THREE
CITY, CITY, ROAD, CITY, // CITY_THREE_ROAD
CITY, GRASS, GRASS, CITY, // CITY_TWO
CITY, ROAD, ROAD, CITY, // CITY_TWO_ROAD
GRASS, CITY, GRASS, CITY, // CITY_TWO_ACROSS
CITY, CITY, GRASS, GRASS, // DISCONNECTED_CITY_TWO
GRASS, CITY, GRASS, CITY, // DISCONNECTED_CITY_TWO_ACROSS
CITY, GRASS, GRASS, GRASS, // CITY_ONE
CITY, ROAD, ROAD, GRASS, // CITY_ONE_ROAD_RIGHT
CITY, GRASS, ROAD, ROAD, // CITY_ONE_ROAD_LEFT
CITY, ROAD, ROAD, ROAD, // CITY_ONE_ROAD_TEE
CITY, ROAD, GRASS, ROAD, // CITY_ONE_ROAD_STRAIGHT
GRASS, GRASS, GRASS, GRASS, // CLOISTER
GRASS, GRASS, ROAD, GRASS, // CLOISTER_ROAD
ROAD, ROAD, ROAD, ROAD, // FOUR_WAY_ROAD
GRASS, ROAD, ROAD, ROAD, // THREE_WAY_ROAD
ROAD, GRASS, ROAD, GRASS, // STRAIGHT_ROAD
GRASS, GRASS, ROAD, ROAD, // CURVED_ROAD
};
/** A table describing the geometry of the features (cities, roads,
* etc.) of each tile. */
protected static final Object[] TILE_FEATURES = new Object[] {
// one must offset tile type by one when indexing into this array
new Object[] { new IntTuple(CITY, 0), }, // CITY_FOUR
new Object[] { new IntTuple(CITY, 0), // CITY_THREE
new IntTuple(GRASS, 0),
new int[] { 0, 4, 1, 3, 3, 3, 4, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_THREE_ROAD
new IntTuple(GRASS, 0),
new int[] { 0, 4, 1, 3, 2, 3, 2, 4 },
new IntTuple(GRASS, 1),
new int[] { 2, 4, 2, 3, 3, 3, 4, 4 },
new IntTuple(ROAD, 0),
new int[] { 2, 3, 2, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO
new IntTuple(GRASS, 0),
new int[] { 0, 4, 4, 0, 4, 4 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ROAD
new IntTuple(GRASS, 0),
new int[] { 0, 4, 4, 0, 4, 2, 2, 4 },
new IntTuple(GRASS, 0),
new int[] { 2, 4, 4, 2, 4, 4 },
new IntTuple(ROAD, 0),
new int[] { 2, 4, 4, 2 }},
new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ACROSS
new IntTuple(GRASS, 0),
new int[] { 0, 4, 1, 3, 3, 3, 4, 4 },
new IntTuple(GRASS, 1),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(CITY, 1),
new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }},
new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO_ACROSS
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 1, 3, 0, 4 },
new IntTuple(CITY, 1),
new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_RIGHT
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(ROAD, 0),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 0),
new int[] { 2, 2, 4, 2 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_LEFT
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(ROAD, 0),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 0),
new int[] { 0, 2, 2, 2 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_TEE
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(ROAD, 0),
new int[] { 0, 2, 2, 2 },
new IntTuple(ROAD, 1),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_STRAIGHT
new IntTuple(CITY, 0),
new int[] { 0, 0, 1, 1, 3, 1, 4, 0 },
new IntTuple(ROAD, 0),
new int[] { 0, 2, 4, 2 }},
new Object[] { new IntTuple(GRASS, 0), // CLOISTER
new IntTuple(CITY, 0),
new int[] { 1, 1, 3, 1, 3, 3, 1, 3 }},
new Object[] { new IntTuple(GRASS, 0), // CLOISTER_ROAD
new IntTuple(CITY, 0),
new int[] { 1, 1, 3, 1, 3, 3, 1, 3 },
new IntTuple(ROAD, 0),
new int[] { 2, 3, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // FOUR_WAY_ROAD
new IntTuple(ROAD, 0),
new int[] { 2, 0, 2, 2 },
new IntTuple(ROAD, 1),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 3),
new int[] { 0, 2, 2, 2 }},
new Object[] { new IntTuple(GRASS, 0), // THREE_WAY_ROAD
new IntTuple(ROAD, 0),
new int[] { 0, 2, 2, 2 },
new IntTuple(ROAD, 1),
new int[] { 2, 2, 4, 2 },
new IntTuple(ROAD, 2),
new int[] { 2, 2, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // STRAIGHT_ROAD
new IntTuple(ROAD, 0),
new int[] { 2, 0, 2, 4 }},
new Object[] { new IntTuple(GRASS, 0), // CURVED_ROAD
new IntTuple(ROAD, 0),
new int[] { 2, 2, 2, 4 },
new IntTuple(ROAD, 0),
new int[] { 0, 2, 2, 2 }},
};
}