Search in sources :

Example 1 with Pair

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());
    }
}
Also used : Stack(java.util.Stack) SOCResourceSet(soc.game.SOCResourceSet) ArrayList(java.util.ArrayList) List(java.util.List) Queue(soc.util.Queue) Pair(soc.util.Pair)

Example 2 with Pair

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;
}
Also used : NodeLenVis(soc.util.NodeLenVis) SOCBoard(soc.game.SOCBoard) SOCPlayingPiece(soc.game.SOCPlayingPiece) ArrayList(java.util.ArrayList) Stack(java.util.Stack) ArrayList(java.util.ArrayList) List(java.util.List) SOCLRPathData(soc.game.SOCLRPathData) Vector(java.util.Vector) Pair(soc.util.Pair)

Aggregations

ArrayList (java.util.ArrayList)2 List (java.util.List)2 Stack (java.util.Stack)2 Pair (soc.util.Pair)2 Vector (java.util.Vector)1 SOCBoard (soc.game.SOCBoard)1 SOCLRPathData (soc.game.SOCLRPathData)1 SOCPlayingPiece (soc.game.SOCPlayingPiece)1 SOCResourceSet (soc.game.SOCResourceSet)1 NodeLenVis (soc.util.NodeLenVis)1 Queue (soc.util.Queue)1