Search in sources :

Example 11 with SOCBoard

use of soc.game.SOCBoard 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)

Example 12 with SOCBoard

use of soc.game.SOCBoard in project JSettlers2 by jdmonin.

the class SOCDisplaylessPlayerClient method handleBOARDLAYOUT2.

/**
 * handle the "board layout" message, new format
 * @param games  Games the client is playing, for method reuse by SOCPlayerClient
 * @param mes  the message
 * @since 1.1.08
 * @return True if game was found and layout understood, false otherwise
 */
public static boolean handleBOARDLAYOUT2(Map<String, SOCGame> games, SOCBoardLayout2 mes) {
    SOCGame ga = games.get(mes.getGame());
    if (ga == null)
        return false;
    SOCBoard bd = ga.getBoard();
    final int bef = mes.getBoardEncodingFormat();
    if (bef == SOCBoard.BOARD_ENCODING_LARGE) {
        // v3
        ((SOCBoardLarge) bd).setLandHexLayout(mes.getIntArrayPart("LH"));
        ga.setPlayersLandHexCoordinates();
        int hex = mes.getIntPart("RH");
        if (hex != 0)
            bd.setRobberHex(hex, false);
        hex = mes.getIntPart("PH");
        if (hex != 0)
            ((SOCBoardLarge) bd).setPirateHex(hex, false);
        int[] portLayout = mes.getIntArrayPart("PL");
        if (portLayout != null)
            bd.setPortsLayout(portLayout);
        int[] x = mes.getIntArrayPart("PX");
        if (x != null)
            ((SOCBoardLarge) bd).setPlayerExcludedLandAreas(x);
        x = mes.getIntArrayPart("RX");
        if (x != null)
            ((SOCBoardLarge) bd).setRobberExcludedLandAreas(x);
        x = mes.getIntArrayPart("CV");
        if (x != null)
            ((SOCBoardLarge) bd).setVillageAndClothLayout(x);
        x = mes.getIntArrayPart("LS");
        if (x != null)
            ((SOCBoardLarge) bd).addLoneLegalSettlements(ga, x);
        HashMap<String, int[]> others = mes.getAddedParts();
        if (others != null)
            ((SOCBoardLarge) bd).setAddedLayoutParts(others);
    } else if (bef <= SOCBoard.BOARD_ENCODING_6PLAYER) {
        // v1 or v2
        bd.setHexLayout(mes.getIntArrayPart("HL"));
        bd.setNumberLayout(mes.getIntArrayPart("NL"));
        bd.setRobberHex(mes.getIntPart("RH"), false);
        int[] portLayout = mes.getIntArrayPart("PL");
        if (portLayout != null)
            bd.setPortsLayout(portLayout);
    } else {
        // Should not occur: Server has sent an unrecognized format
        System.err.println("Cannot recognize game encoding v" + bef + " for game " + ga.getName());
        return false;
    }
    ga.updateAtBoardLayout();
    return true;
}
Also used : SOCBoardLarge(soc.game.SOCBoardLarge) SOCBoard(soc.game.SOCBoard) SOCGame(soc.game.SOCGame)

Example 13 with SOCBoard

use of soc.game.SOCBoard in project JSettlers2 by jdmonin.

the class SOCPlayerTracker method updateLRPotential.

/**
 * update the potential LR value of a possible road or ship
 * by placing dummy roads/ships and calculating LR (longest road).
 * If <tt>level</tt> &gt; 0, add the new roads or ships adjacent
 * to <tt>dummy</tt> and recurse.
 *
 * @param posRoad   the possible road or ship
 * @param dummy     the dummy player
 * @param lrLength  the current LR length
 * @param level     how many levels of recursion, or 0 to not recurse
 */
public void updateLRPotential(SOCPossibleRoad posRoad, SOCPlayer dummy, SOCRoad dummyRoad, final int lrLength, final int level) {
    // D.ebugPrintln("$$$ updateLRPotential for road at "+Integer.toHexString(posRoad.getCoordinates())+" level="+level);
    // 
    // if we've reached the bottom level of recursion,
    // or if there are no more roads to place from this one.
    // then calc potential LR value
    // 
    SOCBoard board = game.getBoard();
    boolean noMoreExpansion;
    if (level <= 0) {
        noMoreExpansion = true;
    } else {
        noMoreExpansion = false;
        Enumeration<Integer> adjEdgeEnum = board.getAdjacentEdgesToEdge(dummyRoad.getCoordinates()).elements();
        while (adjEdgeEnum.hasMoreElements()) {
            final int adjEdge = adjEdgeEnum.nextElement().intValue();
            if ((dummyRoad.isRoadNotShip() && dummy.isPotentialRoad(adjEdge)) || ((!dummyRoad.isRoadNotShip()) && dummy.isPotentialShip(adjEdge))) {
                noMoreExpansion = false;
                break;
            }
        }
    }
    if (noMoreExpansion) {
        // 
        // only update the potential LR if it's bigger than the
        // current value
        // 
        int newPotentialLRValue = dummy.calcLongestRoad2() - lrLength;
        // D.ebugPrintln("$$$ newPotentialLRValue = "+newPotentialLRValue);
        if (newPotentialLRValue > posRoad.getLRPotential()) {
            posRoad.setLRPotential(newPotentialLRValue);
        }
    } else {
        // 
        // we need to add new roads/ships adjacent to dummyRoad, and recurse
        // 
        Enumeration<Integer> adjEdgeEnum = board.getAdjacentEdgesToEdge(dummyRoad.getCoordinates()).elements();
        while (adjEdgeEnum.hasMoreElements()) {
            final int adjEdge = adjEdgeEnum.nextElement().intValue();
            if ((dummyRoad.isRoadNotShip() && dummy.isPotentialRoad(adjEdge)) || ((!dummyRoad.isRoadNotShip()) && dummy.isPotentialShip(adjEdge))) {
                SOCRoad newDummyRoad;
                if (dummyRoad.isRoadNotShip())
                    newDummyRoad = new SOCRoad(dummy, adjEdge, board);
                else
                    newDummyRoad = new SOCShip(dummy, adjEdge, board);
                dummy.putPiece(newDummyRoad, true);
                updateLRPotential(posRoad, dummy, newDummyRoad, lrLength, level - 1);
                dummy.removePiece(newDummyRoad, null);
            }
        }
    }
}
Also used : SOCBoard(soc.game.SOCBoard) SOCShip(soc.game.SOCShip) SOCRoad(soc.game.SOCRoad)

Example 14 with SOCBoard

use of soc.game.SOCBoard in project JSettlers2 by jdmonin.

the class SOCPlayerTracker method expandRoadOrShip.

/**
 * Expand a possible road or ship, to see what placements it makes possible.
 *<UL>
 *<LI> Creates {@code dummyRoad}: A copy of {@code targetRoad} owned by {@code dummy}
 *<LI> Calls {@link SOCPlayer#putPiece(SOCPlayingPiece, boolean) dummy.putPiece(dummyRoad, true)}
 *<LI> Adds to or updates {@link #possibleSettlements} at <tt>targetRoad</tt>'s nodes, if potential
 *<LI> If {@code level > 0}: Calls itself recursively to go more levels out from the current pieces,
 *   adding/updating {@link #possibleRoads} and {@link #possibleSettlements}
 *<LI> Calls {@link SOCPlayer#removePiece(SOCPlayingPiece, SOCPlayingPiece) dummy.removePiece(dummyRoad, null)}
 *</UL>
 *<P>
 * <b>Scenario {@code _SC_PIRI}</b>: Ships in this scenario never expand east (never away from the
 * pirate fortress). Scenario rules require the route to be as short as possible. Even if another (human)
 * player might want to do so, they couldn't interfere with the bot's own route, so we don't track
 * that possibility.
 *
 * @param targetRoad   the possible road
 * @param player    the player who owns the original road
 * @param dummy     the dummy player used to see what's legal; created by caller copying {@code player}
 * @param trackers  player trackers
 * @param level     how many levels (additional pieces) to expand;
 *                  0 to only check <tt>targetRoad</tt> for potential settlements
 *                  and not expand past it for new roads, ships, or further settlements.
 *                  If {@code level > 0} but {@code dummy} has no more roads or ships
 *                  (depending on {@link SOCPossibleRoad#isRoadNotShip() targetRoad.isRoadNotShip()}),
 *                  acts as if {@code level == 0}.
 */
public void expandRoadOrShip(final SOCPossibleRoad targetRoad, final SOCPlayer player, final SOCPlayer dummy, HashMap<Integer, SOCPlayerTracker> trackers, final int level) {
    // D.ebugPrintln("$$$ expandRoad at "+Integer.toHexString(targetRoad.getCoordinates())+" level="+level);
    final SOCBoard board = game.getBoard();
    final int tgtRoadEdge = targetRoad.getCoordinates();
    final boolean isRoadNotShip = targetRoad.isRoadNotShip();
    final SOCRoad dummyRoad;
    if (isRoadNotShip || ((targetRoad instanceof SOCPossibleShip) && ((SOCPossibleShip) targetRoad).isCoastalRoadAndShip))
        dummyRoad = new SOCRoad(dummy, tgtRoadEdge, board);
    else
        // TODO better handling for coastal roads/ships
        dummyRoad = new SOCShip(dummy, tgtRoadEdge, board);
    dummy.putPiece(dummyRoad, true);
    // 
    for (Integer adjNode : board.getAdjacentNodesToEdge(tgtRoadEdge)) {
        if (dummy.canPlaceSettlement(adjNode.intValue())) {
            // 
            // see if possible settlement is already in the list
            // 
            // D.ebugPrintln("$$$ seeing if "+Integer.toHexString(adjNode.intValue())+" is already in the list");
            SOCPossibleSettlement posSet = possibleSettlements.get(adjNode);
            if (posSet != null) {
                // 
                if (!(posSet.getNecessaryRoads().isEmpty() || posSet.getNecessaryRoads().contains(targetRoad))) {
                    // 
                    // add target road to settlement's nr list and this settlement to the road's np list
                    // 
                    // D.ebugPrintln("$$$ adding road "+Integer.toHexString(targetRoad.getCoordinates())+" to the settlement "+Integer.toHexString(posSet.getCoordinates()));
                    posSet.addNecessaryRoad(targetRoad);
                    targetRoad.addNewPossibility(posSet);
                    // 
                    if ((targetRoad.getNumberOfNecessaryRoads() + 1) < posSet.getNumberOfNecessaryRoads()) {
                        posSet.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + 1);
                    }
                }
            } else {
                // 
                // else, add new possible settlement
                // 
                // D.ebugPrintln("$$$ adding new possible settlement at "+Integer.toHexString(adjNode.intValue()));
                List<SOCPossibleRoad> nr = new ArrayList<SOCPossibleRoad>();
                nr.add(targetRoad);
                SOCPossibleSettlement newPosSet = new SOCPossibleSettlement(player, adjNode.intValue(), nr);
                newPosSet.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + 1);
                possibleSettlements.put(adjNode, newPosSet);
                targetRoad.addNewPossibility(newPosSet);
                updateSettlementConflicts(newPosSet, trackers);
            }
        }
    }
    if ((level > 0) && (0 < dummy.getNumPieces(isRoadNotShip ? SOCPlayingPiece.ROAD : SOCPlayingPiece.SHIP))) {
        // 
        // check for new possible roads or ships.
        // The above getNumPieces check ignores any possible ship <-> road transition at a coastal settlement.
        // 
        ArrayList<SOCPossibleRoad> newPossibleRoads = new ArrayList<SOCPossibleRoad>();
        ArrayList<SOCPossibleRoad> roadsToExpand = new ArrayList<SOCPossibleRoad>();
        // ships in _SC_PIRI never expand east
        final boolean isShipInSC_PIRI = (!isRoadNotShip) && game.isGameOptionSet(SOCGameOption.K_SC_PIRI);
        // D.ebugPrintln("$$$ checking roads adjacent to "+Integer.toHexString(targetRoad.getCoordinates()));
        // 
        // check adjacent edges to road or ship
        // 
        Enumeration<Integer> adjEdgesEnum = board.getAdjacentEdgesToEdge(tgtRoadEdge).elements();
        while (adjEdgesEnum.hasMoreElements()) {
            Integer adjEdge = adjEdgesEnum.nextElement();
            final int edge = adjEdge.intValue();
            if (isShipInSC_PIRI) {
                final int tgtEdgeCol = tgtRoadEdge & 0xFF, adjEdgeCol = edge & 0xFF;
                if (// adjacent goes north/south from eastern node of diagonal target edge
                (adjEdgeCol > tgtEdgeCol) || ((adjEdgeCol == tgtEdgeCol) && ((tgtRoadEdge & 0x100) != 0))) // adjacent goes northeast/southeast from vertical target edge (tgtRoadEdge is on odd row)
                {
                    // <--- Ignore this eastern adjacent edge ---
                    continue;
                }
            }
            // D.ebugPrintln("$$$ edge "+Integer.toHexString(adjEdge.intValue())+" is legal:"+dummy.isPotentialRoad(adjEdge.intValue()));
            // 
            // see if edge is a potential road
            // or ship to continue this route
            // 
            boolean edgeIsPotentialRoute = (isRoadNotShip) ? dummy.isPotentialRoad(edge) : dummy.isPotentialShip(edge);
            // If true, this edge transitions
            // between ships <-> roads, at a
            // coastal settlement
            boolean edgeRequiresCoastalSettlement = false;
            if ((!edgeIsPotentialRoute) && game.hasSeaBoard) {
                // Determine if can transition ship <-> road
                // at a coastal settlement
                final int nodeBetween = ((SOCBoardLarge) board).getNodeBetweenAdjacentEdges(tgtRoadEdge, edge);
                if (dummy.canPlaceSettlement(nodeBetween)) {
                    // check opposite type at transition
                    edgeIsPotentialRoute = (isRoadNotShip) ? dummy.isPotentialShip(edge) : dummy.isPotentialRoad(edge);
                    if (edgeIsPotentialRoute)
                        edgeRequiresCoastalSettlement = true;
                }
            }
            if (edgeIsPotentialRoute) {
                // Add 1 to road distance, unless
                // it requires a coastal settlement
                // (extra effort to build that)
                final int incrDistance = edgeRequiresCoastalSettlement ? 3 : 1;
                // 
                // see if possible road is already in the list
                // 
                SOCPossibleRoad pr = possibleRoads.get(adjEdge);
                if (pr != null) {
                    // For now, can't differ along a coastal route.
                    if (edgeRequiresCoastalSettlement && (isRoadNotShip != pr.isRoadNotShip())) {
                        // <--- road vs ship mismatch ---
                        continue;
                    }
                    // 
                    // if so, and it needs 1 or more roads other than this one,
                    // 
                    // D.ebugPrintln("$$$ pr "+Integer.toHexString(pr.getCoordinates())+" already in list");
                    List<SOCPossibleRoad> nr = pr.getNecessaryRoads();
                    if (!(nr.isEmpty() || nr.contains(targetRoad))) {
                        // 
                        // add the target road to its nr list and the new road to the target road's np list
                        // 
                        // D.ebugPrintln("$$$    adding "+Integer.toHexString(targetRoad.getCoordinates())+" to nr list");
                        nr.add(targetRoad);
                        targetRoad.addNewPossibility(pr);
                        // 
                        if ((targetRoad.getNumberOfNecessaryRoads() + incrDistance) < pr.getNumberOfNecessaryRoads()) {
                            pr.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + incrDistance);
                        }
                    }
                    if (!pr.hasBeenExpanded()) {
                        roadsToExpand.add(pr);
                        pr.setExpandedFlag();
                    }
                } else {
                    // 
                    // else, add new possible road or ship
                    // 
                    // D.ebugPrintln("$$$ adding new pr at "+Integer.toHexString(adjEdge.intValue()));
                    ArrayList<SOCPossibleRoad> neededRoads = new ArrayList<SOCPossibleRoad>();
                    neededRoads.add(targetRoad);
                    SOCPossibleRoad newPR;
                    boolean isRoad = isRoadNotShip;
                    if (edgeRequiresCoastalSettlement)
                        isRoad = !isRoad;
                    // use coastal road/ship type (isCoastalRoadAndShip) only if the road/ship
                    // being expanded is coastal, or if we can require a coastal settlement to
                    // switch from road-only or ship-only
                    final boolean isCoastal = dummy.isPotentialRoad(edge) && dummy.isPotentialShip(edge) && (edgeRequiresCoastalSettlement || ((targetRoad instanceof SOCPossibleShip) && ((SOCPossibleShip) targetRoad).isCoastalRoadAndShip));
                    if (isRoad && !isCoastal) {
                        newPR = new SOCPossibleRoad(player, edge, neededRoads);
                    } else {
                        newPR = new SOCPossibleShip(player, edge, isCoastal, neededRoads);
                        System.err.println("L1072: " + toString() + ": new PossibleShip(" + isCoastal + ") at 0x" + Integer.toHexString(edge));
                    }
                    newPR.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + incrDistance);
                    targetRoad.addNewPossibility(newPR);
                    newPossibleRoads.add(newPR);
                    roadsToExpand.add(newPR);
                    newPR.setExpandedFlag();
                }
            }
        }
        // 
        for (SOCPossibleRoad newPR : newPossibleRoads) {
            possibleRoads.put(Integer.valueOf(newPR.getCoordinates()), newPR);
        }
        // 
        for (SOCPossibleRoad expandPR : roadsToExpand) {
            expandRoadOrShip(expandPR, player, dummy, trackers, level - 1);
        }
    }
    // 
    // remove the dummy road
    // 
    dummy.removePiece(dummyRoad, null);
}
Also used : SOCBoardLarge(soc.game.SOCBoardLarge) SOCBoard(soc.game.SOCBoard) SOCShip(soc.game.SOCShip) ArrayList(java.util.ArrayList) SOCRoad(soc.game.SOCRoad)

Example 15 with SOCBoard

use of soc.game.SOCBoard in project JSettlers2 by jdmonin.

the class RobberStrategy method getBestRobberHex.

/**
 * Determine the best hex to move the robber.
 */
public static int getBestRobberHex(SOCGame game, SOCPlayer ourPlayerData, HashMap<Integer, SOCPlayerTracker> playerTrackers, Random rand) {
    log.debug("%%% MOVEROBBER");
    final int[] hexes = game.getBoard().getLandHexCoords();
    final int prevRobberHex = game.getBoard().getRobberHex();
    /**
     * decide which player we want to thwart
     */
    int[] winGameETAs = new int[game.maxPlayers];
    for (int i = game.maxPlayers - 1; i >= 0; --i) winGameETAs[i] = 100;
    Iterator<SOCPlayerTracker> trackersIter = playerTrackers.values().iterator();
    while (trackersIter.hasNext()) {
        SOCPlayerTracker tracker = trackersIter.next();
        final int trackerPN = tracker.getPlayer().getPlayerNumber();
        log.debug("%%%%%%%%% TRACKER FOR PLAYER " + trackerPN);
        try {
            tracker.recalcWinGameETA();
            winGameETAs[trackerPN] = tracker.getWinGameETA();
            log.debug("winGameETA = " + tracker.getWinGameETA());
        } catch (NullPointerException e) {
            log.debug("Null Pointer Exception calculating winGameETA");
            winGameETAs[trackerPN] = 500;
        }
    }
    final int ourPlayerNumber = ourPlayerData.getPlayerNumber();
    int victimNum = -1;
    for (int pnum = 0; pnum < game.maxPlayers; pnum++) {
        if (game.isSeatVacant(pnum))
            continue;
        if ((victimNum < 0) && (pnum != ourPlayerNumber)) {
            // The first pick
            log.debug("Picking a robber victim: pnum=" + pnum);
            victimNum = pnum;
        } else if ((pnum != ourPlayerNumber) && (winGameETAs[pnum] < winGameETAs[victimNum])) {
            // A better pick
            log.debug("Picking a better robber victim: pnum=" + pnum);
            victimNum = pnum;
        }
    }
    // Postcondition: victimNum != -1 due to "First pick" in loop.
    /**
     * figure out the best way to thwart that player
     */
    SOCPlayer victim = game.getPlayer(victimNum);
    SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate();
    int bestHex = prevRobberHex;
    int worstSpeed = 0;
    // can't move robber to desert
    final boolean skipDeserts = game.isGameOptionSet("RD");
    SOCBoard gboard = (skipDeserts ? game.getBoard() : null);
    for (int i = 0; i < hexes.length; i++) {
        /**
         * only check hexes that we're not touching,
         * and not the robber hex, and possibly not desert hexes
         */
        if ((hexes[i] != prevRobberHex) && ourPlayerData.getNumbers().hasNoResourcesForHex(hexes[i]) && !(skipDeserts && (gboard.getHexTypeFromCoord(hexes[i]) == SOCBoard.DESERT_HEX))) {
            estimate.recalculateEstimates(victim.getNumbers(), hexes[i]);
            int[] speeds = estimate.getEstimatesFromNothingFast(victim.getPortFlags());
            int totalSpeed = 0;
            for (int j = SOCBuildingSpeedEstimate.MIN; j < SOCBuildingSpeedEstimate.MAXPLUSONE; j++) {
                totalSpeed += speeds[j];
            }
            log.debug("total Speed = " + totalSpeed);
            if (totalSpeed > worstSpeed) {
                bestHex = hexes[i];
                worstSpeed = totalSpeed;
                log.debug("bestHex = " + Integer.toHexString(bestHex));
                log.debug("worstSpeed = " + worstSpeed);
            }
        }
    }
    log.debug("%%% bestHex = " + Integer.toHexString(bestHex));
    /**
     * Pick a spot at random if we can't decide.
     * Don't pick deserts if the game option is set.
     * Don't pick one of our hexes if at all possible.
     * It's not likely we'll need to pick one of our hexes
     * (we try 30 times to avoid it), so there isn't code here
     * to pick the 'least bad' one.
     * (TODO) consider that: It would be late in the game
     *       if the board's that crowded with pieces.
     *       Use similar algorithm as picking for opponent,
     *       but apply it worst vs best.
     */
    if (bestHex == prevRobberHex) {
        int numRand = 0;
        while ((bestHex == prevRobberHex) || (skipDeserts && (gboard.getHexTypeFromCoord(bestHex) == SOCBoard.DESERT_HEX)) || ((numRand < 30) && ourPlayerData.getNumbers().hasNoResourcesForHex(bestHex))) {
            bestHex = hexes[Math.abs(rand.nextInt()) % hexes.length];
            log.debug("%%% random pick = " + Integer.toHexString(bestHex));
            ++numRand;
        }
    }
    return bestHex;
}
Also used : SOCBoard(soc.game.SOCBoard) SOCPlayer(soc.game.SOCPlayer)

Aggregations

SOCBoard (soc.game.SOCBoard)16 ArrayList (java.util.ArrayList)6 SOCBoardLarge (soc.game.SOCBoardLarge)6 SOCRoad (soc.game.SOCRoad)5 SOCPlayer (soc.game.SOCPlayer)4 SOCShip (soc.game.SOCShip)4 SOCGame (soc.game.SOCGame)3 List (java.util.List)2 Stack (java.util.Stack)2 Vector (java.util.Vector)2 SOCLRPathData (soc.game.SOCLRPathData)2 TreeMap (java.util.TreeMap)1 SOCCity (soc.game.SOCCity)1 SOCFortress (soc.game.SOCFortress)1 SOCPlayerNumbers (soc.game.SOCPlayerNumbers)1 SOCPlayingPiece (soc.game.SOCPlayingPiece)1 SOCSettlement (soc.game.SOCSettlement)1 NodeLenVis (soc.util.NodeLenVis)1 Pair (soc.util.Pair)1