Search in sources :

Example 26 with SOCResourceSet

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

the class SOCRobotBrain method buildOrGetResourceByTradeOrCard.

/**
 * Either ask to build a planned piece, or use trading or development cards to get resources to build it.
 * Examines {@link #buildingPlan} for the next piece wanted.
 * Sets {@link #whatWeWantToBuild} by calling {@link #buildRequestPlannedPiece()}
 * or using a Road Building dev card.
 *<P>
 * If we need resources and we can't get them through the robber,
 * the {@link SOCDevCardConstants#ROADS Road Building} or
 * {@link SOCDevCardConstants#MONO Monopoly} or
 * {@link SOCDevCardConstants#DISC Discovery} development cards,
 * then trades with the bank ({@link #tradeToTarget2(SOCResourceSet)})
 * or with other players ({@link #makeOffer(SOCPossiblePiece)}).
 *<P>
 * Call when these conditions are all true:
 * <UL>
 *<LI> {@link #ourTurn}
 *<LI> {@link #planBuilding()} already called
 *<LI> ! {@link #buildingPlan}.empty()
 *<LI> gameState {@link SOCGame#PLAY1} or {@link SOCGame#SPECIAL_BUILDING}
 *<LI> <tt>waitingFor...</tt> flags all false ({@link #waitingForGameState}, etc)
 *     except possibly {@link #waitingForSpecialBuild}
 *<LI> <tt>expect...</tt> flags all false ({@link #expectPLACING_ROAD}, etc)
 *<LI> ! {@link #waitingForOurTurn}
 *<LI> ! ({@link #expectROLL_OR_CARD} && (counter < 4000))
 *</UL>
 *<P>
 * May set any of these flags:
 * <UL>
 *<LI> {@link #waitingForGameState}, and {@link #expectWAITING_FOR_DISCOVERY} or {@link #expectWAITING_FOR_MONOPOLY}
 *<LI> {@link #waitingForTradeMsg} or {@link #waitingForTradeResponse} or {@link #doneTrading}
 *<LI> {@link #waitingForDevCard}, or {@link #waitingForGameState} and {@link #expectPLACING_SETTLEMENT} (etc).
 *<LI> {@link #waitingForPickSpecialItem}
 *<LI> Scenario actions such as {@link #waitingForSC_PIRI_FortressRequest}
 *</UL>
 *<P>
 * In a future iteration of the run() loop with the expected {@code PLACING_} state, the
 * bot will build {@link #whatWeWantToBuild} by calling {@link #placeIfExpectPlacing()}.
 *
 * @since 1.1.08
 * @throws IllegalStateException  if {@link #buildingPlan}{@link Stack#isEmpty() .isEmpty()}
 */
private void buildOrGetResourceByTradeOrCard() throws IllegalStateException {
    if (buildingPlan.isEmpty())
        throw new IllegalStateException("buildingPlan empty when called");
    /**
     * If we're in SPECIAL_BUILDING (not PLAY1),
     * can't trade or play development cards.
     */
    final boolean gameStatePLAY1 = (game.getGameState() == SOCGame.PLAY1);
    /**
     * check to see if this is a Road Building plan
     */
    boolean roadBuildingPlan = false;
    if (gameStatePLAY1 && (!ourPlayerData.hasPlayedDevCard()) && (ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD) >= 2) && ourPlayerData.getInventory().hasPlayable(SOCDevCardConstants.ROADS) && (rejectedPlayDevCardType != SOCDevCardConstants.ROADS)) {
        // D.ebugPrintln("** Checking for Road Building Plan **");
        SOCPossiblePiece topPiece = buildingPlan.pop();
        // D.ebugPrintln("$ POPPED "+topPiece);
        if ((topPiece != null) && (topPiece instanceof SOCPossibleRoad)) {
            SOCPossiblePiece secondPiece = (buildingPlan.isEmpty()) ? null : buildingPlan.peek();
            // D.ebugPrintln("secondPiece="+secondPiece);
            if ((secondPiece != null) && (secondPiece instanceof SOCPossibleRoad)) {
                roadBuildingPlan = true;
                // builds ships only if the 2 possible pieces are non-coastal ships
                if ((topPiece instanceof SOCPossibleShip) && (!((SOCPossibleShip) topPiece).isCoastalRoadAndShip) && (secondPiece instanceof SOCPossibleShip) && (!((SOCPossibleShip) secondPiece).isCoastalRoadAndShip))
                    whatWeWantToBuild = new SOCShip(ourPlayerData, topPiece.getCoordinates(), null);
                else
                    whatWeWantToBuild = new SOCRoad(ourPlayerData, topPiece.getCoordinates(), null);
                if (!whatWeWantToBuild.equals(whatWeFailedToBuild)) {
                    waitingForGameState = true;
                    counter = 0;
                    expectPLACING_FREE_ROAD1 = true;
                    // D.ebugPrintln("!! PLAYING ROAD BUILDING CARD");
                    client.playDevCard(game, SOCDevCardConstants.ROADS);
                } else {
                    // We already tried to build this.
                    roadBuildingPlan = false;
                    cancelWrongPiecePlacementLocal(whatWeWantToBuild);
                // cancel sets whatWeWantToBuild = null;
                }
            } else {
                // D.ebugPrintln("$ PUSHING "+topPiece);
                buildingPlan.push(topPiece);
            }
        } else {
            // D.ebugPrintln("$ PUSHING "+topPiece);
            buildingPlan.push(topPiece);
        }
    }
    if (roadBuildingPlan) {
        // <---- Early return: Road Building dev card ----
        return;
    }
    // /
    // / figure out what resources we need
    // /
    SOCPossiblePiece targetPiece = buildingPlan.peek();
    // may be null
    SOCResourceSet targetResources = targetPiece.getResourcesToBuild();
    // D.ebugPrintln("^^^ targetPiece = "+targetPiece);
    // D.ebugPrintln("^^^ ourResources = "+ourPlayerData.getResources());
    negotiator.setTargetPiece(ourPlayerNumber, targetPiece);
    // /
    if (gameStatePLAY1 && (!ourPlayerData.hasPlayedDevCard()) && ourPlayerData.getInventory().hasPlayable(SOCDevCardConstants.DISC) && (rejectedPlayDevCardType != SOCDevCardConstants.DISC)) {
        if (chooseFreeResourcesIfNeeded(targetResources, 2, false)) {
            // /
            // / play the card
            // /
            expectWAITING_FOR_DISCOVERY = true;
            waitingForGameState = true;
            counter = 0;
            client.playDevCard(game, SOCDevCardConstants.DISC);
            pause(1500);
        }
    }
    if (!expectWAITING_FOR_DISCOVERY) {
        // /
        if (gameStatePLAY1 && (!ourPlayerData.hasPlayedDevCard()) && ourPlayerData.getInventory().hasPlayable(SOCDevCardConstants.MONO) && (rejectedPlayDevCardType != SOCDevCardConstants.MONO) && monopolyStrategy.decidePlayMonopoly()) {
            // /
            // / play the card
            // /
            expectWAITING_FOR_MONOPOLY = true;
            waitingForGameState = true;
            counter = 0;
            client.playDevCard(game, SOCDevCardConstants.MONO);
            pause(1500);
        }
        if (!expectWAITING_FOR_MONOPOLY) {
            if (gameStatePLAY1 && (!doneTrading) && (!ourPlayerData.getResources().contains(targetResources))) {
                waitingForTradeResponse = false;
                if (robotParameters.getTradeFlag() == 1) {
                    makeOffer(targetPiece);
                // makeOffer will set waitingForTradeResponse or doneTrading.
                }
            }
            if (gameStatePLAY1 && !waitingForTradeResponse) {
                /**
                 * trade with the bank/ports
                 */
                if (tradeToTarget2(targetResources)) {
                    counter = 0;
                    waitingForTradeMsg = true;
                    pause(1500);
                }
            }
            // /
            if ((!(waitingForTradeMsg || waitingForTradeResponse)) && ourPlayerData.getResources().contains(targetResources)) {
                // Remember that targetPiece == buildingPlan.peek().
                // Calls buildingPlan.pop().
                // Checks against whatWeFailedToBuild to see if server has rejected this already.
                // Calls client.buyDevCard or client.buildRequest.
                // Sets waitingForDevCard, or waitingForGameState and expectPLACING_SETTLEMENT (etc).
                // Sets waitingForPickSpecialItem if target piece is SOCPossiblePickSpecialItem.
                buildRequestPlannedPiece();
            }
        }
    }
}
Also used : SOCShip(soc.game.SOCShip) SOCResourceSet(soc.game.SOCResourceSet) SOCRoad(soc.game.SOCRoad)

Example 27 with SOCResourceSet

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

the class SOCRobotBrain method handlePLAYERELEMENT.

/**
 * Handle a player information update from a {@link SOCPlayerElement} or {@link SOCPlayerElements} message:
 * Update a player's amount of a resource or a building type.
 *<P>
 * If this during the {@link SOCGame#ROLL_OR_CARD} state, then update the
 * {@link SOCRobotNegotiator}'s is-selling flags.
 *<P>
 * If our player is losing a resource needed for the {@link #buildingPlan},
 * clear the plan if this is for the Special Building Phase (on the 6-player board).
 * In normal game play, we clear the building plan at the start of each turn.
 *<P>
 * Otherwise, only the game data is updated, nothing brain-specific.
 *
 * @param pl   Player to update; some elements take null. If null and {@code pn != -1}, will find {@code pl}
 *     using {@link SOCGame#getPlayer(int) game.getPlayer(pn)}.
 * @param pn   Player number from message (sometimes -1 for none or all)
 * @param action   {@link SOCPlayerElement#SET}, {@link SOCPlayerElement#GAIN GAIN},
 *     or {@link SOCPlayerElement#LOSE LOSE}
 * @param etype  Element type, such as {@link SOCPlayerElement#SETTLEMENTS} or {@link SOCPlayerElement#NUMKNIGHTS}
 * @param amount  The new value to set, or the delta to gain/lose
 * @since 2.0.00
 */
private void handlePLAYERELEMENT(SOCPlayer pl, final int pn, final int action, final int etype, final int amount) {
    if ((pl == null) && (pn != -1))
        pl = game.getPlayer(pn);
    switch(etype) {
        case SOCPlayerElement.ROADS:
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_numPieces(pl, action, SOCPlayingPiece.ROAD, amount);
            break;
        case SOCPlayerElement.SETTLEMENTS:
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_numPieces(pl, action, SOCPlayingPiece.SETTLEMENT, amount);
            break;
        case SOCPlayerElement.CITIES:
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_numPieces(pl, action, SOCPlayingPiece.CITY, amount);
            break;
        case SOCPlayerElement.SHIPS:
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_numPieces(pl, action, SOCPlayingPiece.SHIP, amount);
            break;
        case SOCPlayerElement.NUMKNIGHTS:
            // PLAYERELEMENT(NUMKNIGHTS) is sent after a Soldier card is played.
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_numKnights(game, pl, action, amount);
            break;
        case SOCPlayerElement.CLAY:
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.CLAY, "CLAY", amount);
            break;
        case SOCPlayerElement.ORE:
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.ORE, "ORE", amount);
            break;
        case SOCPlayerElement.SHEEP:
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.SHEEP, "SHEEP", amount);
            break;
        case SOCPlayerElement.WHEAT:
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.WHEAT, "WHEAT", amount);
            break;
        case SOCPlayerElement.WOOD:
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.WOOD, "WOOD", amount);
            break;
        case SOCPlayerElement.UNKNOWN:
            /**
             * Note: if losing unknown resources, we first
             * convert player's known resources to unknown resources,
             * then remove mes's unknown resources from player.
             */
            handlePLAYERELEMENT_numRsrc(pl, action, SOCResourceConstants.UNKNOWN, "UNKNOWN", amount);
            break;
        case SOCPlayerElement.RESOURCE_COUNT:
            if (amount != pl.getResources().getTotal()) {
                SOCResourceSet rsrcs = pl.getResources();
                if (D.ebugOn) {
                    client.sendText(game, ">>> RESOURCE COUNT ERROR FOR PLAYER " + pl.getPlayerNumber() + ": " + amount + " != " + rsrcs.getTotal());
                }
                // 
                if (pl.getPlayerNumber() != ourPlayerNumber) {
                    rsrcs.clear();
                    rsrcs.setAmount(amount, SOCResourceConstants.UNKNOWN);
                }
            }
            break;
        case SOCPlayerElement.SCENARIO_WARSHIP_COUNT:
            if (expectPLACING_ROBBER && (action == SOCPlayerElement.GAIN)) {
                // warship card successfully played; clear the flag fields
                expectPLACING_ROBBER = false;
                waitingForGameState = false;
            }
        default:
            // handle ASK_SPECIAL_BUILD, NUM_PICK_GOLD_HEX_RESOURCES, SCENARIO_CLOTH_COUNT, etc;
            // those are all self-contained informational fields that don't need any reaction from a bot.
            SOCDisplaylessPlayerClient.handlePLAYERELEMENT_simple(game, pl, pn, action, etype, amount, ourPlayerName);
            break;
    }
    // /
    if (game.getGameState() == SOCGame.ROLL_OR_CARD) {
        negotiator.resetIsSelling();
    }
}
Also used : SOCResourceSet(soc.game.SOCResourceSet)

Example 28 with SOCResourceSet

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

the class SOCRobotBrain method handleMAKEOFFER.

/**
 * Handle a MAKEOFFER for this game.
 * if another player makes an offer, that's the
 * same as a rejection, but still wants to deal.
 * Call {@link #considerOffer(SOCTradeOffer)}, and if
 * we accept, clear our {@link #buildingPlan} so we'll replan it.
 * Ignore our own MAKEOFFERs echoed from server.
 * @since 1.1.08
 */
private void handleMAKEOFFER(SOCMakeOffer mes) {
    SOCTradeOffer offer = mes.getOffer();
    game.getPlayer(offer.getFrom()).setCurrentOffer(offer);
    if ((offer.getFrom() == ourPlayerNumber)) {
        // <---- Ignore our own offers ----
        return;
    }
    // /
    // / record that this player wants to sell me the stuff
    // /
    SOCResourceSet giveSet = offer.getGiveSet();
    for (int rsrcType = SOCResourceConstants.CLAY; rsrcType <= SOCResourceConstants.WOOD; rsrcType++) {
        if (giveSet.contains(rsrcType)) {
            D.ebugPrintln("%%% player " + offer.getFrom() + " wants to sell " + rsrcType);
            negotiator.markAsWantsAnotherOffer(offer.getFrom(), rsrcType);
        }
    }
    // /
    // / record that this player is not selling the resources
    // / he is asking for
    // /
    SOCResourceSet getSet = offer.getGetSet();
    for (int rsrcType = SOCResourceConstants.CLAY; rsrcType <= SOCResourceConstants.WOOD; rsrcType++) {
        if (getSet.contains(rsrcType)) {
            D.ebugPrintln("%%% player " + offer.getFrom() + " wants to buy " + rsrcType + " and therefore does not want to sell it");
            negotiator.markAsNotSelling(offer.getFrom(), rsrcType);
        }
    }
    if (waitingForTradeResponse) {
        offerRejections[offer.getFrom()] = true;
        boolean everyoneRejected = true;
        D.ebugPrintln("ourPlayerData.getCurrentOffer() = " + ourPlayerData.getCurrentOffer());
        if (ourPlayerData.getCurrentOffer() != null) {
            boolean[] offeredTo = ourPlayerData.getCurrentOffer().getTo();
            for (int i = 0; i < game.maxPlayers; i++) {
                D.ebugPrintln("offerRejections[" + i + "]=" + offerRejections[i]);
                if (offeredTo[i] && !offerRejections[i])
                    everyoneRejected = false;
            }
        }
        D.ebugPrintln("everyoneRejected=" + everyoneRejected);
        if (everyoneRejected) {
            negotiator.addToOffersMade(ourPlayerData.getCurrentOffer());
            client.clearOffer(game);
            waitingForTradeResponse = false;
        }
    }
    // /
    // / consider the offer
    // /
    int ourResponseToOffer = considerOffer(offer);
    D.ebugPrintln("%%% ourResponseToOffer = " + ourResponseToOffer);
    if (ourResponseToOffer < 0)
        // <--- Early return: SOCRobotNegotiator.IGNORE_OFFER ---
        return;
    int delayLength = Math.abs(rand.nextInt() % 500) + 3500;
    if (gameIs6Player && !waitingForTradeResponse) {
        // usually, pause is half-length in 6-player
        delayLength *= 2;
    }
    pause(delayLength);
    switch(ourResponseToOffer) {
        case SOCRobotNegotiator.ACCEPT_OFFER:
            client.acceptOffer(game, offer.getFrom());
            // /
            // / clear our building plan, so that we replan
            // /
            buildingPlan.clear();
            negotiator.setTargetPiece(ourPlayerNumber, null);
            break;
        case SOCRobotNegotiator.REJECT_OFFER:
            if (!waitingForTradeResponse)
                client.rejectOffer(game);
            break;
        case SOCRobotNegotiator.COUNTER_OFFER:
            if (!makeCounterOffer(offer))
                client.rejectOffer(game);
            break;
    }
}
Also used : SOCTradeOffer(soc.game.SOCTradeOffer) SOCResourceSet(soc.game.SOCResourceSet)

Example 29 with SOCResourceSet

use of soc.game.SOCResourceSet 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 30 with SOCResourceSet

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

the class SOCRobotDM method dumbFastGameStrategy.

/**
 * Plan building for the dumbFastGameStrategy ({@link #FAST_STRATEGY}).
 * uses rules to determine what to build next
 * and update {@link #buildingPlan}.
 *<P>
 * For example, if {@link #favoriteSettlement} is chosen,
 * it's chosen from {@link #ourPlayerTracker}{@link SOCPlayerTracker#getPossibleSettlements() .getPossibleSettlements()}.
 *
 *<H4>Outline:</H4>
 * Possible cities and settlements are looked at first.
 * Find the city with best {@link SOCPossibleCity#getSpeedupTotal()}, then check each possible
 * settlement's {@link SOCPossiblePiece#getETA()} against the city's ETA to possibly choose one to build.
 * (If one is chosen, its {@link SOCPossibleSettlement#getNecessaryRoads()}
 * will also be chosen here.)  Then, Knights or Dev Cards.
 * Only then would roads or ships be looked at, for Longest Route
 * (and only if we're at 5 VP or more).
 *<P>
 * This method never directly checks
 * {@code ourPlayerTracker}{@link SOCPlayerTracker#getPossibleRoads() .getPossibleRoads()}, instead
 * it adds the roads or ships from {@link SOCPossibleSettlement#getNecessaryRoads()} to {@link #buildingPlan}
 * when a possible settlement is picked to build.
 *<P>
 * Some scenarios require special moves or certain actions to win the game.  If we're playing in
 * such a scenario, after calculating {@link #favoriteSettlement}, {@link #favoriteCity}, etc, calls
 * {@link #scenarioGameStrategyPlan(float, float, boolean, boolean, SOCBuildingSpeedEstimate, int, boolean)}.
 * See that method for the list of scenarios which need such planning.
 *
 * @param buildingETAs  the ETAs for building each piece type
 * @see #smartGameStrategy(int[])
 */
protected void dumbFastGameStrategy(final int[] buildingETAs) {
    D.ebugPrintln("***** dumbFastGameStrategy *****");
    // If this game is on the 6-player board, check whether we're planning for
    // the Special Building Phase.  Can't buy cards or trade in that phase.
    final boolean forSpecialBuildingPhase = game.isSpecialBuilding() || (game.getCurrentPlayerNumber() != ourPlayerNumber);
    int bestETA = 500;
    SOCBuildingSpeedEstimate ourBSE = new SOCBuildingSpeedEstimate(ourPlayerData.getNumbers());
    if (ourPlayerData.getTotalVP() < 5) {
        // 
        if (ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) {
            Iterator<SOCPossibleCity> posCitiesIter = ourPlayerTracker.getPossibleCities().values().iterator();
            while (posCitiesIter.hasNext()) {
                SOCPossibleCity posCity = posCitiesIter.next();
                D.ebugPrintln("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
                D.ebugPrintln("Speedup = " + posCity.getSpeedupTotal());
                D.ebugPrintln("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
                if ((brain != null) && brain.getDRecorder().isOn()) {
                    brain.getDRecorder().startRecording("CITY" + posCity.getCoordinates());
                    brain.getDRecorder().record("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
                    brain.getDRecorder().record("Speedup = " + posCity.getSpeedupTotal());
                    brain.getDRecorder().record("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
                    brain.getDRecorder().stopRecording();
                }
                if ((favoriteCity == null) || (posCity.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
                    favoriteCity = posCity;
                    bestETA = buildingETAs[SOCBuildingSpeedEstimate.CITY];
                }
            }
        }
        // 
        // score the possible settlements
        // 
        scoreSettlementsForDumb(buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT], ourBSE);
        // 
        // pick something to build
        // 
        Iterator<SOCPossibleSettlement> posSetsIter = ourPlayerTracker.getPossibleSettlements().values().iterator();
        while (posSetsIter.hasNext()) {
            SOCPossibleSettlement posSet = posSetsIter.next();
            if ((brain != null) && brain.getDRecorder().isOn()) {
                brain.getDRecorder().startRecording("SETTLEMENT" + posSet.getCoordinates());
                brain.getDRecorder().record("Estimate speedup of stlmt at " + game.getBoard().nodeCoordToString(posSet.getCoordinates()));
                brain.getDRecorder().record("Speedup = " + posSet.getSpeedupTotal());
                brain.getDRecorder().record("ETA = " + posSet.getETA());
                Stack<SOCPossibleRoad> roadPath = posSet.getRoadPath();
                if (roadPath != null) {
                    brain.getDRecorder().record("Path:");
                    Iterator<SOCPossibleRoad> rpIter = roadPath.iterator();
                    while (rpIter.hasNext()) {
                        SOCPossibleRoad posRoad = rpIter.next();
                        brain.getDRecorder().record("Road at " + game.getBoard().edgeCoordToString(posRoad.getCoordinates()));
                    }
                }
                brain.getDRecorder().stopRecording();
            }
            if (posSet.getETA() < bestETA) {
                bestETA = posSet.getETA();
                favoriteSettlement = posSet;
            } else if (posSet.getETA() == bestETA) {
                if (favoriteSettlement == null) {
                    if ((favoriteCity == null) || (posSet.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
                        favoriteSettlement = posSet;
                    }
                } else {
                    if (posSet.getSpeedupTotal() > favoriteSettlement.getSpeedupTotal()) {
                        favoriteSettlement = posSet;
                    }
                }
            }
        }
        if (favoriteSettlement != null) {
            // 
            // we want to build a settlement
            // 
            D.ebugPrintln("Picked favorite settlement at " + game.getBoard().nodeCoordToString(favoriteSettlement.getCoordinates()));
            buildingPlan.push(favoriteSettlement);
            if (!favoriteSettlement.getNecessaryRoads().isEmpty()) {
                // 
                // we need to build roads first
                // 
                Stack<SOCPossibleRoad> roadPath = favoriteSettlement.getRoadPath();
                while (!roadPath.empty()) {
                    buildingPlan.push(roadPath.pop());
                }
            }
        } else if (favoriteCity != null) {
            // 
            // we want to build a city
            // 
            D.ebugPrintln("Picked favorite city at " + game.getBoard().nodeCoordToString(favoriteCity.getCoordinates()));
            buildingPlan.push(favoriteCity);
        } else {
            // 
            if ((game.getNumDevCards() > 0) && !forSpecialBuildingPhase) {
                // 
                // buy a card if there are any left
                // 
                D.ebugPrintln("Buy a card");
                SOCPossibleCard posCard = new SOCPossibleCard(ourPlayerData, buildingETAs[SOCBuildingSpeedEstimate.CARD]);
                buildingPlan.push(posCard);
            }
        }
    } else {
        // 
        // we have more than 4 points
        // 
        int choice = -1;
        // 
        // consider Largest Army
        // 
        D.ebugPrintln("Calculating Largest Army ETA");
        int laETA = 500;
        int laSize = 0;
        SOCPlayer laPlayer = game.getPlayerWithLargestArmy();
        if (laPlayer == null) {
            // /
            // / no one has largest army
            // /
            laSize = 3;
        } else if (laPlayer.getPlayerNumber() == ourPlayerNumber) {
            // /
            // / we have largest army
            // /
            D.ebugPrintln("We have largest army");
        } else {
            laSize = laPlayer.getNumKnights() + 1;
        }
        // /
        // / figure out how many knights we need to buy
        // /
        int knightsToBuy = 0;
        if ((ourPlayerData.getNumKnights() + // OLD + NEW knights
        ourPlayerData.getInventory().getAmount(SOCDevCardConstants.KNIGHT)) < laSize) {
            knightsToBuy = laSize - (ourPlayerData.getNumKnights() + ourPlayerData.getInventory().getAmount(SOCInventory.OLD, SOCDevCardConstants.KNIGHT));
        }
        D.ebugPrintln("knightsToBuy = " + knightsToBuy);
        if (ourPlayerData.getGame().getNumDevCards() >= knightsToBuy) {
            // /
            // / figure out how long it takes to buy this many knights
            // /
            SOCResourceSet targetResources = new SOCResourceSet();
            for (int i = 0; i < knightsToBuy; i++) {
                targetResources.add(SOCDevCard.COST);
            }
            laETA = ourBSE.calculateRollsFast(ourPlayerData.getResources(), targetResources, 100, ourPlayerData.getPortFlags());
        } else {
        // /
        // / not enough dev cards left
        // /
        }
        if ((laETA < bestETA) && !forSpecialBuildingPhase) {
            bestETA = laETA;
            choice = LA_CHOICE;
        }
        D.ebugPrintln("laETA = " + laETA);
        // 
        // consider Longest Road
        // 
        D.ebugPrintln("Calculating Longest Road ETA");
        int lrETA = 500;
        Stack<?> bestLRPath = null;
        int lrLength;
        SOCPlayer lrPlayer = game.getPlayerWithLongestRoad();
        if ((lrPlayer != null) && (lrPlayer.getPlayerNumber() == ourPlayerNumber)) {
            // /
            // / we have longest road
            // /
            D.ebugPrintln("We have longest road");
        } else if (!game.isGameOptionSet(SOCGameOption.K_SC_0RVP)) {
            if (lrPlayer == null) {
                // /
                // / no one has longest road
                // /
                lrLength = Math.max(4, ourPlayerData.getLongestRoadLength());
            } else {
                lrLength = lrPlayer.getLongestRoadLength();
            }
            Iterator<SOCLRPathData> lrPathsIter = ourPlayerData.getLRPaths().iterator();
            int depth;
            while (lrPathsIter.hasNext()) {
                Stack<?> path;
                SOCLRPathData pathData = lrPathsIter.next();
                depth = Math.min(((lrLength + 1) - pathData.getLength()), ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD));
                path = (Stack<?>) recalcLongestRoadETAAux(ourPlayerData, true, pathData.getBeginning(), pathData.getLength(), lrLength, depth);
                if ((path != null) && ((bestLRPath == null) || (path.size() < bestLRPath.size()))) {
                    bestLRPath = path;
                }
                path = (Stack<?>) recalcLongestRoadETAAux(ourPlayerData, true, pathData.getEnd(), pathData.getLength(), lrLength, depth);
                if ((path != null) && ((bestLRPath == null) || (path.size() < bestLRPath.size()))) {
                    bestLRPath = path;
                }
            }
            if (bestLRPath != null) {
                // 
                // calculate LR eta
                // 
                D.ebugPrintln("Number of roads: " + bestLRPath.size());
                SOCResourceSet targetResources = new SOCResourceSet();
                for (int i = 0; i < bestLRPath.size(); i++) {
                    targetResources.add(SOCRoad.COST);
                }
                lrETA = ourBSE.calculateRollsFast(ourPlayerData.getResources(), targetResources, 100, ourPlayerData.getPortFlags());
            }
        }
        if (lrETA < bestETA) {
            bestETA = lrETA;
            choice = LR_CHOICE;
        }
        D.ebugPrintln("lrETA = " + lrETA);
        // 
        if ((ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) && (buildingETAs[SOCBuildingSpeedEstimate.CITY] <= bestETA)) {
            Iterator<SOCPossibleCity> posCitiesIter = ourPlayerTracker.getPossibleCities().values().iterator();
            while (posCitiesIter.hasNext()) {
                SOCPossibleCity posCity = posCitiesIter.next();
                if ((brain != null) && brain.getDRecorder().isOn()) {
                    brain.getDRecorder().startRecording("CITY" + posCity.getCoordinates());
                    brain.getDRecorder().record("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
                    brain.getDRecorder().record("Speedup = " + posCity.getSpeedupTotal());
                    brain.getDRecorder().record("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
                    brain.getDRecorder().stopRecording();
                }
                if ((favoriteCity == null) || (posCity.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
                    favoriteCity = posCity;
                    bestETA = buildingETAs[SOCBuildingSpeedEstimate.CITY];
                    choice = CITY_CHOICE;
                }
            }
        }
        // 
        if (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) > 0) {
            scoreSettlementsForDumb(buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT], ourBSE);
            Iterator<SOCPossibleSettlement> posSetsIter = ourPlayerTracker.getPossibleSettlements().values().iterator();
            while (posSetsIter.hasNext()) {
                SOCPossibleSettlement posSet = posSetsIter.next();
                if ((brain != null) && brain.getDRecorder().isOn()) {
                    brain.getDRecorder().startRecording("SETTLEMENT" + posSet.getCoordinates());
                    brain.getDRecorder().record("Estimate speedup of stlmt at " + game.getBoard().nodeCoordToString(posSet.getCoordinates()));
                    brain.getDRecorder().record("Speedup = " + posSet.getSpeedupTotal());
                    brain.getDRecorder().record("ETA = " + posSet.getETA());
                    Stack<SOCPossibleRoad> roadPath = posSet.getRoadPath();
                    if (roadPath != null) {
                        brain.getDRecorder().record("Path:");
                        Iterator<SOCPossibleRoad> rpIter = roadPath.iterator();
                        while (rpIter.hasNext()) {
                            SOCPossibleRoad posRoad = rpIter.next();
                            brain.getDRecorder().record("Road at " + game.getBoard().edgeCoordToString(posRoad.getCoordinates()));
                        }
                    }
                    brain.getDRecorder().stopRecording();
                }
                if ((posSet.getRoadPath() == null) || (ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD) >= posSet.getRoadPath().size())) {
                    if (posSet.getETA() < bestETA) {
                        bestETA = posSet.getETA();
                        favoriteSettlement = posSet;
                        choice = SETTLEMENT_CHOICE;
                    } else if (posSet.getETA() == bestETA) {
                        if (favoriteSettlement == null) {
                            if ((favoriteCity == null) || (posSet.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
                                favoriteSettlement = posSet;
                                choice = SETTLEMENT_CHOICE;
                            }
                        } else {
                            if (posSet.getSpeedupTotal() > favoriteSettlement.getSpeedupTotal()) {
                                favoriteSettlement = posSet;
                            }
                        }
                    }
                }
            }
        }
        if (game.isGameOptionSet(SOCGameOption.K_SC_PIRI) || game.isGameOptionSet(SOCGameOption.K_SC_WOND)) {
            if (scenarioGameStrategyPlan(bestETA, -1f, false, (choice == LA_CHOICE), ourBSE, 0, forSpecialBuildingPhase))
                // <--- Early return: Scenario-specific buildingPlan was pushed ---
                return;
        }
        // 
        switch(choice) {
            case LA_CHOICE:
                D.ebugPrintln("Picked LA");
                if (!forSpecialBuildingPhase) {
                    for (int i = 0; i < knightsToBuy; i++) {
                        SOCPossibleCard posCard = new SOCPossibleCard(ourPlayerData, 1);
                        buildingPlan.push(posCard);
                    }
                }
                break;
            case LR_CHOICE:
                D.ebugPrintln("Picked LR");
                while (!bestLRPath.empty()) {
                    SOCPossibleRoad pr = (SOCPossibleRoad) bestLRPath.pop();
                    D.ebugPrintln("LR road at " + game.getBoard().edgeCoordToString(pr.getCoordinates()));
                    buildingPlan.push(pr);
                }
                break;
            case CITY_CHOICE:
                D.ebugPrintln("Picked favorite city at " + game.getBoard().nodeCoordToString(favoriteCity.getCoordinates()));
                buildingPlan.push(favoriteCity);
                break;
            case SETTLEMENT_CHOICE:
                D.ebugPrintln("Picked favorite settlement at " + game.getBoard().nodeCoordToString(favoriteSettlement.getCoordinates()));
                buildingPlan.push(favoriteSettlement);
                if (!favoriteSettlement.getNecessaryRoads().isEmpty()) {
                    // 
                    // we need to build roads first
                    // 
                    Stack<SOCPossibleRoad> roadPath = favoriteSettlement.getRoadPath();
                    while (!roadPath.empty()) {
                        SOCPossibleRoad pr = roadPath.pop();
                        D.ebugPrintln("Nec road at " + game.getBoard().edgeCoordToString(pr.getCoordinates()));
                        buildingPlan.push(pr);
                    }
                }
        }
    }
}
Also used : Stack(java.util.Stack) Iterator(java.util.Iterator) SOCPlayer(soc.game.SOCPlayer) SOCResourceSet(soc.game.SOCResourceSet) SOCLRPathData(soc.game.SOCLRPathData)

Aggregations

SOCResourceSet (soc.game.SOCResourceSet)54 Test (org.junit.Test)14 SOCTradeOffer (soc.game.SOCTradeOffer)10 SOCPlayer (soc.game.SOCPlayer)8 Stack (java.util.Stack)4 SOCShip (soc.game.SOCShip)3 ArrayList (java.util.ArrayList)2 StringTokenizer (java.util.StringTokenizer)2 SOCBoardLarge (soc.game.SOCBoardLarge)2 SOCGame (soc.game.SOCGame)2 SOCRoad (soc.game.SOCRoad)2 Queue (soc.util.Queue)2 Hashtable (java.util.Hashtable)1 Iterator (java.util.Iterator)1 List (java.util.List)1 MissingResourceException (java.util.MissingResourceException)1 Vector (java.util.Vector)1 SOCInventoryItem (soc.game.SOCInventoryItem)1 SOCLRPathData (soc.game.SOCLRPathData)1 SOCSpecialItem (soc.game.SOCSpecialItem)1