Initial code to compute scores and to handle incremental scoring.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@364 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: AtlantiBoard.java,v 1.8 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: AtlantiBoard.java,v 1.9 2001/10/17 04:34:14 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
@@ -47,6 +47,14 @@ public class VenisonBoard
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the piecen color to use when creating new piecens.
|
||||
*/
|
||||
public void setNewPiecenColor (int color)
|
||||
{
|
||||
_newPiecenColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tiles to be displayed by this board. Any previous tiles
|
||||
* are forgotten and the new tiles are initialized according to their
|
||||
@@ -141,6 +149,30 @@ public class VenisonBoard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a piecen is removed (after scoring it), this method should be
|
||||
* called to update the board display.
|
||||
*/
|
||||
public void clearPiecen (Object key)
|
||||
{
|
||||
// locate the tile associated with this piecen key
|
||||
int tsize = _tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
VenisonTile tile = (VenisonTile)_tiles.get(i);
|
||||
if (tile.getKey().equals(key)) {
|
||||
// clear the piecen out of the tile
|
||||
tile.clearPiecen();
|
||||
// and repaint
|
||||
repaint();
|
||||
// and get on out
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.warning("Requested to clear piecen for which we could " +
|
||||
"find no associated tile! [key=" + key + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tile to be placed on the board. The tile will be displayed
|
||||
* in the square under the mouse cursor where it can be legally placed
|
||||
@@ -264,7 +296,7 @@ public class VenisonBoard
|
||||
if (_placedTile.claims[fidx] == 0) {
|
||||
if (_placedTile.piecen == null ||
|
||||
_placedTile.piecen.featureIndex != fidx) {
|
||||
Piecen p = new Piecen(Piecen.BLUE, 0, 0, fidx);
|
||||
Piecen p = new Piecen(_newPiecenColor, 0, 0, fidx);
|
||||
_placedTile.setPiecen(p, null);
|
||||
changed = true;
|
||||
}
|
||||
@@ -493,16 +525,17 @@ public class VenisonBoard
|
||||
VenisonBoard board = new VenisonBoard();
|
||||
|
||||
TestDSet set = new TestDSet();
|
||||
set.addTile(new VenisonTile(CITY_TWO, false, WEST, 0, 0));
|
||||
set.addTile(new VenisonTile(CITY_TWO, true, WEST, 0, 0));
|
||||
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));
|
||||
set.addTile(new VenisonTile(CITY_ONE, false, SOUTH, -1, -1));
|
||||
VenisonTile zero = new VenisonTile(CURVED_ROAD, false, WEST, 0, 2);
|
||||
set.addTile(zero);
|
||||
VenisonTile one = new VenisonTile(TWO_CITY_TWO, false, NORTH, 0, 1);
|
||||
set.addTile(one);
|
||||
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));
|
||||
VenisonTile two = new VenisonTile(CITY_FOUR, false, NORTH, -2, 0);
|
||||
VenisonTile two = new VenisonTile(CITY_ONE, false, EAST, -2, 0);
|
||||
set.addTile(two);
|
||||
board.setTiles(set);
|
||||
|
||||
@@ -514,8 +547,18 @@ public class VenisonBoard
|
||||
CollectionUtil.addAll(tiles, set.elements());
|
||||
Collections.sort(tiles);
|
||||
|
||||
zero.setPiecen(new Piecen(Piecen.GREEN, 0, 0, 2), tiles);
|
||||
one.setPiecen(new Piecen(Piecen.BLUE, 0, 0, 0), tiles);
|
||||
two.setPiecen(new Piecen(Piecen.BLUE, 0, 0, 0), tiles);
|
||||
two.setPiecen(new Piecen(Piecen.RED, 0, 0, 1), tiles);
|
||||
|
||||
Log.info("Incomplete road: " +
|
||||
TileUtil.computeFeatureScore(tiles, zero, 2));
|
||||
|
||||
Log.info("Completed city: " +
|
||||
TileUtil.computeFeatureScore(tiles, two, 1));
|
||||
|
||||
Log.info("Incomplete city: " +
|
||||
TileUtil.computeFeatureScore(tiles, one, 2));
|
||||
|
||||
frame.getContentPane().add(board, BorderLayout.CENTER);
|
||||
frame.pack();
|
||||
@@ -556,6 +599,9 @@ public class VenisonBoard
|
||||
* placements based on the current position of the placing tile. */
|
||||
protected boolean[] _validOrients;
|
||||
|
||||
/** The color to use when creating new piecens. */
|
||||
protected int _newPiecenColor = Piecen.BLUE;
|
||||
|
||||
/** Our render offset in pixels. */
|
||||
protected int _tx, _ty;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package com.threerings.venison;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import com.samskivert.util.ListUtil;
|
||||
|
||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
@@ -53,6 +54,13 @@ public class VenisonController
|
||||
// get a casted reference to our game object
|
||||
_venobj = (VenisonObject)plobj;
|
||||
|
||||
// find out what our index is and use that as our piecen color
|
||||
int oidx = ListUtil.indexOfEqual(_venobj.players, _self.username);
|
||||
if (oidx != -1) {
|
||||
// use our player index as the piecen color directly
|
||||
_panel.board.setNewPiecenColor(oidx);
|
||||
}
|
||||
|
||||
// grab the tiles and piecens from the game object and configure
|
||||
// the board with them
|
||||
_panel.board.setTiles(_venobj.tiles);
|
||||
@@ -67,10 +75,8 @@ public class VenisonController
|
||||
{
|
||||
super.turnDidChange(turnHolder);
|
||||
|
||||
// if it's our turn, set the tile to be placed. otherwise clear it
|
||||
// out
|
||||
// if it's our turn, set the tile to be placed
|
||||
if (turnHolder.equals(_self.username)) {
|
||||
Log.info("Setting tile to be placed: " + _venobj.currentTile);
|
||||
_panel.board.setTileToBePlaced(_venobj.currentTile);
|
||||
}
|
||||
}
|
||||
@@ -113,6 +119,11 @@ public class VenisonController
|
||||
// documentation inherited
|
||||
public void elementRemoved (ElementRemovedEvent event)
|
||||
{
|
||||
if (event.getName().equals(VenisonObject.PIECENS)) {
|
||||
// a piecen was removed, update the board
|
||||
Log.info("Clearing piecen " + event.getKey() + ".");
|
||||
_panel.board.clearPiecen(event.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
//
|
||||
// $Id: AtlantiObject.java,v 1.6 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: AtlantiObject.java,v 1.7 2001/10/17 04:34:14 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.parlor.turn.TurnGameObject;
|
||||
|
||||
@@ -20,6 +21,9 @@ public class VenisonObject extends TurnGameObject
|
||||
/** The field name of the <code>piecens</code> field. */
|
||||
public static final String PIECENS = "piecens";
|
||||
|
||||
/** The field name of the <code>scores</code> field. */
|
||||
public static final String SCORES = "scores";
|
||||
|
||||
/** A set containing all of the tiles that are in play in this
|
||||
* game. */
|
||||
public DSet tiles = new DSet(VenisonTile.class);
|
||||
@@ -32,6 +36,9 @@ public class VenisonObject extends TurnGameObject
|
||||
* board. */
|
||||
public DSet piecens = new DSet(Piecen.class);
|
||||
|
||||
/** The scores for each player. */
|
||||
public int[] scores;
|
||||
|
||||
/**
|
||||
* Requests that the <code>tiles</code> field be set to the specified
|
||||
* value.
|
||||
@@ -113,6 +120,15 @@ public class VenisonObject extends TurnGameObject
|
||||
requestElementUpdate(PIECENS, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>scores</code> field be set to the specified
|
||||
* value.
|
||||
*/
|
||||
public void setScores (int[] value)
|
||||
{
|
||||
requestAttributeChange(SCORES, value);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuffer buf)
|
||||
{
|
||||
@@ -120,5 +136,6 @@ public class VenisonObject extends TurnGameObject
|
||||
buf.append(", tiles=").append(tiles);
|
||||
buf.append(", currentTile=").append(currentTile);
|
||||
buf.append(", piecens=").append(piecens);
|
||||
buf.append(", scores=").append(StringUtil.toString(scores));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: Feature.java,v 1.1 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: Feature.java,v 1.2 2001/10/17 04:34:13 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
@@ -334,9 +334,13 @@ public class Feature
|
||||
return poly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this feature.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=" + type + ", edgeMask=" + edgeMask + "]";
|
||||
return "[type=" + FeatureUtil.typeToString(type) +
|
||||
", edgeMask=" + FeatureUtil.edgeMaskToString(edgeMask) + "]";
|
||||
}
|
||||
|
||||
/** Maps feature types to colors. */
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
//
|
||||
// $Id: AtlantiManager.java,v 1.8 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: AtlantiManager.java,v 1.9 2001/10/17 04:34:14 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
|
||||
@@ -61,6 +65,12 @@ public class VenisonManager
|
||||
// clear out our board tiles
|
||||
_tiles.clear();
|
||||
|
||||
// create a claim group vector
|
||||
_claimGroupVector = new int[_players.length];
|
||||
|
||||
// clear out the scores
|
||||
_venobj.setScores(new int[_players.length]);
|
||||
|
||||
// clear out the tile and piecen set
|
||||
_venobj.setTiles(new DSet(VenisonTile.class));
|
||||
_venobj.setPiecens(new DSet(Piecen.class));
|
||||
@@ -105,6 +115,110 @@ public class VenisonManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the placement of this tile has completed
|
||||
* features that were previously incomplete.
|
||||
*/
|
||||
protected void scoreCompletedFeatures (VenisonTile tile)
|
||||
{
|
||||
// potentially score all features on the tile
|
||||
for (int i = 0; i < tile.features.length; i++) {
|
||||
// we only need to worry about ROAD and CITY features because
|
||||
// those are the only features on this tile that we might have
|
||||
// completed
|
||||
Feature f = tile.features[i];
|
||||
if (f.type != TileCodes.CITY && f.type != TileCodes.ROAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// see if any piecens are even on a feature in this group
|
||||
int cgroup = tile.claims[i];
|
||||
int[] cgv = getClaimGroupVector(cgroup);
|
||||
if (cgv == null) {
|
||||
// if not, we don't have anything to score
|
||||
Log.info("Not scoring unclaimed feature " +
|
||||
"[ttype=" + tile.type + ", feat=" + f +
|
||||
", cgroup=" + cgroup + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// we do have something to score, so we compute the score for
|
||||
// this feature
|
||||
int score = TileUtil.computeFeatureScore(_tiles, tile, i);
|
||||
|
||||
// if the score is positive, it's a completed feature, so we
|
||||
// dole out the points and clear the associated piecens
|
||||
if (score > 0) {
|
||||
Log.info("Scoring feature [ttype=" + tile.type +
|
||||
", feature=" + f + ", score=" + score + "].");
|
||||
|
||||
// adjust the scores
|
||||
for (int p = 0; p < cgv.length; p++) {
|
||||
_venobj.scores[p] += (score * cgv[p]);
|
||||
}
|
||||
|
||||
// broadcast the new scores
|
||||
_venobj.setScores(_venobj.scores);
|
||||
Log.info("New scores: " + StringUtil.toString(_venobj.scores));
|
||||
|
||||
// and free up the scored piecens
|
||||
Iterator iter = _venobj.piecens.elements();
|
||||
while (iter.hasNext()) {
|
||||
Piecen p = (Piecen)iter.next();
|
||||
if (p.claimGroup == cgroup) {
|
||||
Log.info("Removing piecen " + p + ".");
|
||||
_venobj.removeFromPiecens(p.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.info("Not scoring incomplete feature " +
|
||||
"[ttype=" + tile.type + ", feat=" + f +
|
||||
", score=" + score + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int array with zeros and ones in the appropriate places
|
||||
* so that a score can be multiplied by a player's position in the
|
||||
* vector to determine whether or not they receive any points for the
|
||||
* scoring of a particular claim group.
|
||||
*
|
||||
* <p> Note that this function returns a static (to this instance)
|
||||
* vector, so it cannot be called again without overwriting values
|
||||
* returned previously.
|
||||
*
|
||||
* @return an array for the specified claim group or null if no
|
||||
* players have a piecen claiming the specified claim group.
|
||||
*/
|
||||
protected int[] getClaimGroupVector (int claimGroup)
|
||||
{
|
||||
// clear out the vector
|
||||
Arrays.fill(_claimGroupVector, 0);
|
||||
|
||||
// iterate over the piecens
|
||||
int max = 0;
|
||||
Iterator iter = _venobj.piecens.elements();
|
||||
while (iter.hasNext()) {
|
||||
Piecen piecen = (Piecen)iter.next();
|
||||
if (piecen.claimGroup == claimGroup) {
|
||||
// color == player index... somewhat sketchy
|
||||
if (++_claimGroupVector[piecen.color] > max) {
|
||||
// keep track of the highest scorer
|
||||
max = _claimGroupVector[piecen.color];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now cut out everyone with scores less than the highest score
|
||||
for (int i = 0; i < _claimGroupVector.length; i++) {
|
||||
_claimGroupVector[i] = (_claimGroupVector[i] < max) ? 0 : 1;
|
||||
}
|
||||
|
||||
return (max == 0) ? null : _claimGroupVector;
|
||||
}
|
||||
|
||||
/** Handles place tile requests. */
|
||||
protected class PlaceTileHandler implements MessageHandler
|
||||
{
|
||||
@@ -114,17 +228,22 @@ public class VenisonManager
|
||||
|
||||
// make sure this is a valid placement
|
||||
if (TileUtil.isValidPlacement(_tiles, tile)) {
|
||||
// add the tile to the lsit
|
||||
// add the tile to the list and resort it
|
||||
_tiles.add(tile);
|
||||
Collections.sort(_tiles);
|
||||
|
||||
// inherit its claim groups
|
||||
TileUtil.inheritClaims(_tiles, tile);
|
||||
|
||||
Log.info("Placed tile " + tile + ".");
|
||||
|
||||
// add the tile to the tiles set
|
||||
_venobj.addToTiles(tile);
|
||||
|
||||
// placing a piece may have completed road or city
|
||||
// features. if it did, we score them now
|
||||
scoreCompletedFeatures(tile);
|
||||
|
||||
Log.info("Placed tile " + tile + ".");
|
||||
|
||||
} else {
|
||||
Log.warning("Received invalid placement " + event + ".");
|
||||
}
|
||||
@@ -182,4 +301,7 @@ public class VenisonManager
|
||||
|
||||
/** A sorted list of the tiles that have been placed on the board. */
|
||||
protected List _tiles = new ArrayList();
|
||||
|
||||
/** Used to score features groups. */
|
||||
protected int[] _claimGroupVector;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: FeatureUtil.java,v 1.1 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: FeatureUtil.java,v 1.2 2001/10/17 04:34:13 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
@@ -86,6 +86,39 @@ public class FeatureUtil implements TileCodes
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the supplied type code.
|
||||
*/
|
||||
public static String typeToString (int type)
|
||||
{
|
||||
return TYPE_CODES[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the supplied edge mask.
|
||||
*/
|
||||
public static String edgeMaskToString (int edgeMask)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if ((edgeMask & NORTH_F) != 0) buf.append("NORTH_F|");
|
||||
if ((edgeMask & EAST_F) != 0) buf.append("EAST_F|");
|
||||
if ((edgeMask & SOUTH_F) != 0) buf.append("SOUTH_F|");
|
||||
if ((edgeMask & WEST_F) != 0) buf.append("WEST_F|");
|
||||
if ((edgeMask & NNW_F) != 0) buf.append("NNW_F|");
|
||||
if ((edgeMask & NNE_F) != 0) buf.append("NNE_F|");
|
||||
if ((edgeMask & SSW_F) != 0) buf.append("SSW_F|");
|
||||
if ((edgeMask & SSE_F) != 0) buf.append("SSE_F|");
|
||||
if ((edgeMask & WNW_F) != 0) buf.append("WNW_F|");
|
||||
if ((edgeMask & WSW_F) != 0) buf.append("WSW_F|");
|
||||
if ((edgeMask & ENE_F) != 0) buf.append("ENE_F|");
|
||||
if ((edgeMask & ESE_F) != 0) buf.append("ESE_F|");
|
||||
// strip off the trailing bar if there is one
|
||||
if (buf.length() > 0) {
|
||||
buf.deleteCharAt(buf.length()-1);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the feature edge mask into the orientation specified.
|
||||
* For a forward translation, provide a positive valued orientation
|
||||
@@ -300,6 +333,10 @@ public class FeatureUtil implements TileCodes
|
||||
{ ENE_F, SSE_F, WSW_F, NNW_F },
|
||||
};
|
||||
|
||||
/** String representations of the feature type codes. */
|
||||
protected static final String[] TYPE_CODES = {
|
||||
"CITY", "GRASS", "ROAD", "CLOISTER" };
|
||||
|
||||
/** A table of features that are used on more than one tile. */
|
||||
protected static Feature[] _reusedFeatures;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TileUtil.java,v 1.7 2001/10/17 02:19:54 mdb Exp $
|
||||
// $Id: TileUtil.java,v 1.8 2001/10/17 04:34:13 mdb Exp $
|
||||
|
||||
package com.threerings.venison;
|
||||
|
||||
@@ -384,6 +384,153 @@ public class TileUtil implements TileCodes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the score for the specified feature and returns it. If the
|
||||
* feature is complete (has no unconnected edges), the score will be
|
||||
* positive. If it is incomplete, the score will be negative.
|
||||
*
|
||||
* @param tiles a sorted list of the tiles on the board.
|
||||
* @param tile the tile that contains the feature whose score should
|
||||
* be computed.
|
||||
* @param featureIndex the index of the feature in the containing
|
||||
* tile.
|
||||
*
|
||||
* @return a positive score for a completed feature group, a negative
|
||||
* score for a partial feature group.
|
||||
*/
|
||||
public static int computeFeatureScore (
|
||||
List tiles, VenisonTile tile, int featureIndex)
|
||||
{
|
||||
// determine what kind of feature it is
|
||||
Feature feature = tile.features[featureIndex];
|
||||
|
||||
switch (feature.type) {
|
||||
case ROAD:
|
||||
return computeFeatureScore(tiles, tile, feature, new ArrayList());
|
||||
|
||||
case CITY: {
|
||||
int score =
|
||||
computeFeatureScore(tiles, tile, feature, new ArrayList());
|
||||
// cities receive a 2x multiplier if they are larger than size
|
||||
// two and are completed
|
||||
return (score > 2) ? score*2 : score;
|
||||
}
|
||||
|
||||
case CLOISTER:
|
||||
// cloister's score specially
|
||||
return computeCloisterScore(tiles, tile);
|
||||
|
||||
default:
|
||||
case GRASS:
|
||||
// grass doesn't score
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for {@link
|
||||
* #computeFeatureScore(List,VenisonTile,int)}.
|
||||
*/
|
||||
protected static int computeFeatureScore (
|
||||
List tiles, VenisonTile tile, Feature feature, List seen)
|
||||
{
|
||||
// if we've already counted this tile, bail
|
||||
if (seen.contains(tile)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// otherwise add this tile to the seen list
|
||||
seen.add(tile);
|
||||
|
||||
// cities have a base score of one but get a one point bonus if
|
||||
// they have a shield on them
|
||||
int score = (feature.type == CITY && tile.hasShield) ? 2 : 1;
|
||||
boolean missedNeighbor = false;
|
||||
|
||||
// now figure out what connected features there are, if any
|
||||
int ftype = feature.type;
|
||||
int fmask = feature.edgeMask;
|
||||
|
||||
// iterate over all of the possible adjacency possibilities
|
||||
for (int c = 0; c < FeatureUtil.ADJACENCY_MAP.length; c += 3) {
|
||||
int mask = FeatureUtil.ADJACENCY_MAP[c];
|
||||
int dir = FeatureUtil.ADJACENCY_MAP[c+1];
|
||||
int opp_mask = FeatureUtil.ADJACENCY_MAP[c+2];
|
||||
VenisonTile neighbor = null;
|
||||
|
||||
// if this feature doesn't have this edge, skip it
|
||||
if ((fmask & mask) == 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) {
|
||||
// if we don't have a neighbor in a direction that we
|
||||
// need, we're an incomplete feature. alas
|
||||
missedNeighbor = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// translate the target mask into our orientation
|
||||
mask = FeatureUtil.translateMask(mask, tile.orientation);
|
||||
opp_mask = FeatureUtil.translateMask(opp_mask, tile.orientation);
|
||||
|
||||
// propagate, propagate, propagate
|
||||
int fidx = neighbor.getFeatureIndex(opp_mask);
|
||||
if (fidx < 0) {
|
||||
Log.warning("Tile mismatch while scoring [self=" + tile +
|
||||
", target=" + neighbor + ", fidx=" + fidx +
|
||||
", srcEdge=" + mask +
|
||||
", destEdge=" + opp_mask + "].");
|
||||
|
||||
} else {
|
||||
// add the score for this neighbor
|
||||
int nscore = computeFeatureScore(
|
||||
tiles, neighbor, neighbor.features[fidx], seen);
|
||||
// if our neighbor returned a negative score, we convert
|
||||
// it back to positive and make a note to make it negative
|
||||
// at the end
|
||||
if (nscore < 0) {
|
||||
score += -nscore;
|
||||
missedNeighbor = true;
|
||||
} else {
|
||||
score += nscore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missedNeighbor ? -score : score;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for {@link
|
||||
* #computeFeatureScore(List,VenisonTile,int)}.
|
||||
*/
|
||||
protected static int computeCloisterScore (List tiles, VenisonTile tile)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
// all we need to know are how many neighbors this guy has (we
|
||||
// count ourselves as well, just for code simplicity)
|
||||
for (int dx = -1; dx < 1; dx++) {
|
||||
for (int dy = -1; dy < 1; dy++) {
|
||||
if (findTile(tiles, tile.x + dx, tile.y + dy) != null) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// incomplete cloisters return a negative score
|
||||
return (score == 9) ? 9 : -score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and returns the tile with the specified coordinates.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user