use of soc.util.Pair in project JSettlers2 by jdmonin.
the class SOCRobotDM method scoreSettlementsForDumb.
/**
* For each possible settlement in our {@link SOCPlayerTracker},
* update its {@link SOCPossiblePiece#getETA() getETA()} and
* its {@link SOCPossibleSettlement#getRoadPath() getRoadPath()}.
*<P>
* Each {@link SOCPossibleSettlement#getRoadPath()} is calculated
* here by finding the shortest path among its {@link SOCPossibleSettlement#getNecessaryRoads()}.
*<P>
* Calculates ETA by using our current {@link SOCBuildingSpeedEstimate} on the resources
* needed to buy the settlement plus roads/ships for its shortest path's length.
*
* @param settlementETA ETA for building a settlement from now if it doesn't require any roads or ships
* @param ourBSE Current building speed estimate, from our {@code SOCPlayer#getNumbers()}
*
* @see #scorePossibleSettlements(int, int)
*/
protected void scoreSettlementsForDumb(final int settlementETA, SOCBuildingSpeedEstimate ourBSE) {
D.ebugPrintln("-- scoreSettlementsForDumb --");
Queue<Pair<SOCPossibleRoad, List<SOCPossibleRoad>>> queue = new Queue<Pair<SOCPossibleRoad, List<SOCPossibleRoad>>>();
Iterator<SOCPossibleSettlement> posSetsIter = ourPlayerTracker.getPossibleSettlements().values().iterator();
while (posSetsIter.hasNext()) {
SOCPossibleSettlement posSet = posSetsIter.next();
if (D.ebugOn) {
D.ebugPrintln("Estimate speedup of stlmt at " + game.getBoard().nodeCoordToString(posSet.getCoordinates()));
D.ebugPrintln("*** speedup total = " + posSet.getSpeedupTotal());
}
// /
// / find the shortest path to this settlement
// /
final List<SOCPossibleRoad> necRoadList = posSet.getNecessaryRoads();
if (!necRoadList.isEmpty()) {
// will use for BFS if needed:
queue.clear();
for (SOCPossibleRoad necRoad : necRoadList) {
if (D.ebugOn)
D.ebugPrintln("-- queuing necessary road at " + game.getBoard().edgeCoordToString(necRoad.getCoordinates()));
queue.put(new Pair<SOCPossibleRoad, List<SOCPossibleRoad>>(necRoad, null));
}
//
// Do a BFS of the necessary road paths looking for the shortest one.
//
boolean pathTooLong = false;
for (int maxIter = 50; maxIter > 0 && !queue.empty(); --maxIter) {
Pair<SOCPossibleRoad, List<SOCPossibleRoad>> dataPair = queue.get();
SOCPossibleRoad curRoad = dataPair.getA();
final List<SOCPossibleRoad> possRoadsToCur = dataPair.getB();
if (D.ebugOn)
D.ebugPrintln("-- current road at " + game.getBoard().edgeCoordToString(curRoad.getCoordinates()));
final List<SOCPossibleRoad> necRoads = curRoad.getNecessaryRoads();
if (necRoads.isEmpty()) {
//
// we have a path
//
D.ebugPrintln("Found a path!");
Stack<SOCPossibleRoad> path = new Stack<SOCPossibleRoad>();
path.push(curRoad);
if (D.ebugOn)
D.ebugPrintln("possRoadsToCur = " + possRoadsToCur);
if (possRoadsToCur != null)
// push to path, iterating from nearest to curRoad until most distant
for (int i = possRoadsToCur.size() - 1; i >= 0; --i) path.push(possRoadsToCur.get(i));
posSet.setRoadPath(path);
queue.clear();
D.ebugPrintln("Done setting path.");
} else {
final List<SOCPossibleRoad> possRoadsAndCur = (possRoadsToCur != null) ? new ArrayList<SOCPossibleRoad>(possRoadsToCur) : new ArrayList<SOCPossibleRoad>();
possRoadsAndCur.add(curRoad);
if (queue.size() + necRoads.size() > 40) {
// Too many necessary, or dupes led to loop. Bug in necessary road construction?
System.err.println("rDM.scoreSettlementsForDumb: Necessary Road Path too long for road/ship 0x" + Integer.toHexString(curRoad.getCoordinates()) + " for settle 0x" + Integer.toHexString(posSet.getCoordinates()));
pathTooLong = true;
queue.clear();
break;
}
for (SOCPossibleRoad necRoad2 : necRoads) {
if (D.ebugOn)
D.ebugPrintln("-- queuing necessary road at " + game.getBoard().edgeCoordToString(necRoad2.getCoordinates()));
queue.put(new Pair<SOCPossibleRoad, List<SOCPossibleRoad>>(necRoad2, possRoadsAndCur));
}
}
}
if (!queue.empty()) {
System.err.println("rDM.scoreSettlementsForDumb: Necessary Road Path length unresolved for settle 0x" + Integer.toHexString(posSet.getCoordinates()));
pathTooLong = true;
}
D.ebugPrintln("Done searching for path.");
//
if (pathTooLong) {
posSet.setETA(500);
} else {
SOCResourceSet targetResources = new SOCResourceSet();
targetResources.add(SOCSettlement.COST);
Stack<SOCPossibleRoad> path = posSet.getRoadPath();
if (path != null) {
final int pathLength = path.size();
final SOCPossiblePiece pathFirst = (pathLength > 0) ? path.peek() : null;
SOCResourceSet rtype = ((pathFirst != null) && (pathFirst instanceof SOCPossibleShip) && // TODO better coastal ETA scoring
!((SOCPossibleShip) pathFirst).isCoastalRoadAndShip) ? SOCShip.COST : SOCRoad.COST;
for (int i = 0; i < pathLength; i++) targetResources.add(rtype);
}
posSet.setETA(ourBSE.calculateRollsFast(ourPlayerData.getResources(), targetResources, 100, ourPlayerData.getPortFlags()));
}
} else {
//
// no roads are necessary
//
posSet.setRoadPath(null);
posSet.setETA(settlementETA);
}
D.ebugPrintln("Settlement ETA = " + posSet.getETA());
}
}
use of soc.util.Pair 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