use of soc.util.NodeLenVis in project JSettlers2 by jdmonin.
the class SOCPlayer method calcLongestRoad2.
/**
* Calculates the longest road / longest trade route for this player
*
* @return the length of the longest road for this player
*/
public int calcLongestRoad2() {
// Date startTime = new Date();
//
// clear the lr paths vector so that we have an accurate
// representation. if someone cut our longest path in two
// we won't catch it unless we clear the vector
//
// D.ebugPrintln("CLEARING PATH DATA");
lrPaths.removeAllElements();
/**
* we're doing a depth first search of all possible road paths.
* For similar code, see soc.robot.SOCRobotDM.recalcLongestRoadETAAux.
* Both methods rely on a stack holding NodeLenVis (pop to curNode in loop);
* they differ in actual element type within the stack because they are
* gathering slightly different results (length or a stack of edges).
*/
SOCBoard board = game.getBoard();
Stack<NodeLenVis<IntPair>> pending = new Stack<NodeLenVis<IntPair>>();
int longest = 0;
for (Integer rn : roadNodes) {
final int pathStartNodeCoord = rn.intValue();
pending.push(new NodeLenVis<IntPair>(pathStartNodeCoord, 0, new Vector<IntPair>()));
while (!pending.isEmpty()) {
NodeLenVis<IntPair> curNode = pending.pop();
final int coord = curNode.node;
final int len = curNode.len;
Vector<IntPair> visited = curNode.vis;
boolean pathEnd = false;
final SOCPlayingPiece settlementAtNodeCoord;
/**
* check for road blocks
*/
if (len > 0) {
settlementAtNodeCoord = board.settlementAtNode(coord);
if ((settlementAtNodeCoord != null) && (settlementAtNodeCoord.getPlayerNumber() != playerNumber)) {
pathEnd = true;
// D.ebugPrintln("^^^ path end at "+Integer.toHexString(coord));
}
} else {
settlementAtNodeCoord = null;
}
if (!pathEnd) {
/**
* Check if this road path continues to adjacent connected nodes.
*/
// may be set false in loop
pathEnd = true;
final int[] adjacNodes = board.getAdjacentNodesToNode_arr(coord);
for (int ni = adjacNodes.length - 1; ni >= 0; --ni) {
final int j = adjacNodes[ni];
if (j == -9)
continue;
if (isConnectedByRoad(coord, j)) {
// sea board: road/ship from node to j
final SOCRoad roadFromNode;
if (game.hasSeaBoard) {
// Check for road<->ship transitions,
// which require a settlement/city at node.
// If len==0, inboundRoad is null because we're just starting.
roadFromNode = getRoadOrShip(board.getEdgeBetweenAdjacentNodes(coord, j));
if (len > 0) {
if (// shouldn't happen
roadFromNode == null)
continue;
if ((roadFromNode.isRoadNotShip() != curNode.inboundRoad.isRoadNotShip()) && (settlementAtNodeCoord == null)) {
// Requires settlement/city to connect road to ship
continue;
}
}
} else {
roadFromNode = null;
}
IntPair pair = new IntPair(coord, j);
boolean match = false;
for (IntPair vis : visited) {
if (vis.equals(pair)) {
match = true;
break;
}
}
if (!match) {
Vector<IntPair> newVis = new Vector<IntPair>(visited);
newVis.addElement(pair);
pending.push(new NodeLenVis<IntPair>(j, len + 1, newVis, roadFromNode));
pathEnd = false;
}
}
}
// foreach(adjacNodes)
}
if (pathEnd) {
if (len > longest) {
longest = len;
}
//
// we want to store the longest path for a single set of nodes
// check to make sure that we don't save two paths that share a node
//
boolean intersection;
boolean addNewPath = true;
Vector<SOCLRPathData> trash = new Vector<SOCLRPathData>();
for (SOCLRPathData oldPathData : lrPaths) {
// D.ebugPrintln("oldPathData = " + oldPathData);
Vector<IntPair> nodePairs = oldPathData.getNodePairs();
intersection = false;
for (IntPair vis : visited) {
for (IntPair np : nodePairs) {
if (np.equals(vis)) {
// D.ebugPrintln("oldPathData.nodePairs.contains(vis)");
intersection = true;
break;
}
}
if (intersection) {
break;
}
}
if (intersection) {
//
if (oldPathData.getLength() < len) {
// D.ebugPrintln("REMOVING OLDPATHDATA");
trash.addElement(oldPathData);
} else {
addNewPath = false;
// D.ebugPrintln("NOT ADDING NEW PATH");
}
}
}
if (!trash.isEmpty()) {
for (SOCLRPathData oldPathData : trash) {
lrPaths.removeElement(oldPathData);
}
}
if (addNewPath) {
SOCLRPathData newPathData = new SOCLRPathData(pathStartNodeCoord, coord, len, visited);
// D.ebugPrintln("ADDING PATH: " + newPathData);
lrPaths.addElement(newPathData);
}
}
}
}
longestRoadLength = longest;
// System.out.println("LONGEST FOR "+name+" IS "+longest+" TIME = "+elapsed+"ms");
return longest;
}
use of soc.util.NodeLenVis in project JSettlers2 by jdmonin.
the class SOCRobotDM method recalcLongestRoadETAAux.
/**
* Does a depth first search of legal possible road edges from the end point of the longest
* path connecting a graph of nodes, and returns which roads or how many roads
* would need to be built to take longest road.
*<P>
* Do not call if {@link SOCGameOption#K_SC_0RVP} is set, because
* this method needs {@link SOCPlayer#getLRPaths()} which will be empty.
*<P>
* Combined implementation for use by SOCRobotDM and {@link SOCPlayerTracker}.
*
* @param pl Calculate this player's longest road;
* typically SOCRobotDM.ourPlayerData or SOCPlayerTracker.player
* @param wantsStack If true, return the Stack; otherwise, return numRoads.
* @param startNode the path endpoint, such as from
* {@link SOCPlayer#getLRPaths()}.(i){@link SOCLRPathData#getBeginning() .getBeginning()}
* or {@link SOCLRPathData#getEnd() .getEnd()}
* @param pathLength the length of that path
* @param lrLength length of longest road in the game
* @param searchDepth how many roads out to search
*
* @return if <tt>wantsStack</tt>: a {@link Stack} containing the path of roads with the last one
* (farthest from <tt>startNode</tt>) on top, or <tt>null</tt> if it can't be done.
* If ! <tt>wantsStack</tt>: Integer: the number of roads needed, or 500 if it can't be done
*/
static Object recalcLongestRoadETAAux(SOCPlayer pl, final boolean wantsStack, final int startNode, final int pathLength, final int lrLength, final int searchDepth) {
// D.ebugPrintln("=== recalcLongestRoadETAAux("+Integer.toHexString(startNode)+","+pathLength+","+lrLength+","+searchDepth+")");
//
// We're doing a depth first search of all possible road paths.
// For similar code, see SOCPlayer.calcLongestRoad2
// Both methods rely on a stack holding NodeLenVis (pop to curNode in loop);
// they differ in actual element type within the stack because they are
// gathering slightly different results (length or a stack of edges).
//
int longest = 0;
int numRoads = 500;
Pair<NodeLenVis<Integer>, List<Integer>> bestPathNode = null;
final SOCBoard board = pl.getGame().getBoard();
Stack<Pair<NodeLenVis<Integer>, List<Integer>>> pending = new Stack<Pair<NodeLenVis<Integer>, List<Integer>>>();
// Holds as-yet unvisited nodes:
// Pair members are <NodeLenVis, null or node-coordinate list of all parents (from DFS traversal order)>.
// Lists have most-distant node at beginning (item 0), and most-immediate at end of list (n-1).
// That list is used at the end to build the returned Stack which is the road path needed.
pending.push(new Pair<NodeLenVis<Integer>, List<Integer>>(new NodeLenVis<Integer>(startNode, pathLength, new Vector<Integer>()), null));
while (!pending.empty()) {
final Pair<NodeLenVis<Integer>, List<Integer>> dataPair = pending.pop();
final NodeLenVis<Integer> curNode = dataPair.getA();
// D.ebugPrintln("curNode = "+curNode);
final int coord = curNode.node;
int len = curNode.len;
final Vector<Integer> visited = curNode.vis;
boolean pathEnd = false;
//
if (len > 0) {
final int pn = pl.getPlayerNumber();
SOCPlayingPiece p = board.settlementAtNode(coord);
if ((p != null) && (p.getPlayerNumber() != pn)) {
pathEnd = true;
// D.ebugPrintln("^^^ path end at "+Integer.toHexString(coord));
}
}
if (!pathEnd) {
//
// check if we've connected to another road graph of this player
//
Iterator<SOCLRPathData> lrPathsIter = pl.getLRPaths().iterator();
while (lrPathsIter.hasNext()) {
SOCLRPathData pathData = lrPathsIter.next();
if ((startNode != pathData.getBeginning()) && (startNode != pathData.getEnd()) && ((coord == pathData.getBeginning()) || (coord == pathData.getEnd()))) {
pathEnd = true;
len += pathData.getLength();
break;
}
}
}
if (!pathEnd) {
//
if ((len - pathLength) >= searchDepth) {
pathEnd = true;
}
// D.ebugPrintln("Reached search depth");
}
if (!pathEnd) {
/**
* For each of the 3 adjacent edges of coord's node,
* check for unvisited legal road possibilities.
* When they are found, push that edge's far-end node
* onto the pending stack.
*/
pathEnd = true;
for (int dir = 0; dir < 3; ++dir) {
int j = board.getAdjacentEdgeToNode(coord, dir);
if (pl.isLegalRoad(j)) {
final Integer edge = new Integer(j);
boolean match = false;
for (Enumeration<Integer> ev = visited.elements(); ev.hasMoreElements(); ) {
Integer vis = ev.nextElement();
if (vis.equals(edge)) {
match = true;
break;
}
}
if (!match) {
Vector<Integer> newVis = new Vector<Integer>(visited);
newVis.addElement(edge);
List<Integer> nodeParentList = dataPair.getB();
if (nodeParentList == null)
nodeParentList = new ArrayList<Integer>();
else
// clone before we add to it
nodeParentList = new ArrayList<Integer>(nodeParentList);
// curNode's coord will be parent to new pending element
nodeParentList.add(coord);
// edge's other node
j = board.getAdjacentNodeToNode(coord, dir);
pending.push(new Pair<NodeLenVis<Integer>, List<Integer>>(new NodeLenVis<Integer>(j, len + 1, newVis), nodeParentList));
pathEnd = false;
}
}
}
}
if (pathEnd) {
if (len > longest) {
longest = len;
numRoads = curNode.len - pathLength;
bestPathNode = dataPair;
} else if ((len == longest) && (curNode.len < numRoads)) {
numRoads = curNode.len - pathLength;
bestPathNode = dataPair;
}
}
}
if (!wantsStack) {
// As used by SOCPlayerTracker.
int rv;
if (longest > lrLength)
rv = numRoads;
else
rv = 500;
// <-- Early return: ! wantsStack ---
return new Integer(rv);
}
if ((longest > lrLength) && (bestPathNode != null)) {
// D.ebugPrintln("Converting nodes to road coords.");
//
// Return the path in a stack, with the last road (the one from bestPathNode) on top.
// Convert pairs of node coords to edge coords for roads.
// List is ordered from farthest parent at 0 to bestPathNode's parent at (n-1),
// so iterate same way to build the stack.
//
Stack<SOCPossibleRoad> path = new Stack<SOCPossibleRoad>();
int coordC, coordP;
List<Integer> nodeList = bestPathNode.getB();
if ((nodeList == null) || nodeList.isEmpty())
// <--- early return, no node list: should not happen ---
return null;
// append bestPathNode
nodeList.add(new Integer(bestPathNode.getA().node));
final int L = nodeList.size();
// root ancestor
coordP = nodeList.get(0);
for (int i = 1; i < L; ++i) {
coordC = nodeList.get(i);
path.push(new SOCPossibleRoad(pl, board.getEdgeBetweenAdjacentNodes(coordC, coordP), null));
coordP = coordC;
}
return path;
}
return null;
}
Aggregations