Search in sources :

Example 1 with SOCBoardLarge

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

the class SOCGameMessageHandler method handleROLLDICE.

// / Roll dice and pick resources ///
/**
 * handle "roll dice" message.
 *
 * @param c  the connection that sent the message
 * @param mes  the message
 * @since 1.0.0
 */
private void handleROLLDICE(SOCGame ga, Connection c, final SOCRollDice mes) {
    final String gn = ga.getName();
    ga.takeMonitor();
    try {
        final String plName = c.getData();
        final SOCPlayer pl = ga.getPlayer(plName);
        if ((pl != null) && ga.canRollDice(pl.getPlayerNumber())) {
            /**
             * Roll dice, distribute resources in game
             */
            SOCGame.RollResult roll = ga.rollDice();
            /**
             * Send roll results and then text to client.
             * Note that only the total is sent, not the 2 individual dice.
             * (Only the _SC_PIRI scenario cares about them indivdually, and
             * in that case it prints the result when needed.)
             *
             * If a 7 is rolled, sendGameState will also say who must discard
             * (in a GAMETEXTMSG).
             * If a gold hex is rolled, sendGameState will also say who
             * must pick resources to gain (in a GAMETEXTMSG).
             */
            srv.messageToGame(gn, new SOCDiceResult(gn, ga.getCurrentDice()));
            if (ga.clientVersionLowest < SOCGameTextMsg.VERSION_FOR_DICE_RESULT_INSTEAD) {
                // backwards-compat: this text message is redundant to v2.0.00 and newer clients
                // because they print the roll results from SOCDiceResult.  Use SOCGameTextMsg
                // because pre-2.0.00 clients don't understand SOCGameServerText messages.
                srv.messageToGameForVersions(ga, 0, SOCGameTextMsg.VERSION_FOR_DICE_RESULT_INSTEAD - 1, new SOCGameTextMsg(gn, SOCGameTextMsg.SERVERNAME, // I18N
                plName + " rolled a " + roll.diceA + " and a " + roll.diceB + "."), true);
            }
            // For 7, give visual feedback before sending discard request
            handler.sendGameState(ga);
            if (ga.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
                // pirate moves on every roll
                srv.messageToGame(gn, new SOCMoveRobber(gn, ga.getCurrentPlayerNumber(), -(((SOCBoardLarge) ga.getBoard()).getPirateHex())));
                if (roll.sc_piri_fleetAttackVictim != null) {
                    final SOCResourceSet loot = roll.sc_piri_fleetAttackRsrcs;
                    final int lootTotal = (loot != null) ? loot.getTotal() : 0;
                    if (lootTotal != 0) {
                        // use same resource-loss messages sent in handleDISCARD
                        final boolean won = (loot.contains(SOCResourceConstants.GOLD_LOCAL));
                        SOCPlayer vic = roll.sc_piri_fleetAttackVictim;
                        final String vicName = vic.getName();
                        final Connection vCon = srv.getConnection(vicName);
                        final int vpn = vic.getPlayerNumber();
                        final int strength = (roll.diceA < roll.diceB) ? roll.diceA : roll.diceB;
                        if (won) {
                            srv.messageToGameKeyed(ga, true, "action.rolled.sc_piri.player.won.pick.free", vicName, strength);
                        // "{0} won against the pirate fleet (strength {1}) and will pick a free resource."
                        } else {
                            /**
                             * tell the victim client that the player lost the resources
                             */
                            handler.reportRsrcGainLoss(gn, loot, true, true, vpn, -1, null, vCon);
                            srv.messageToPlayerKeyedSpecial(vCon, ga, "action.rolled.sc_piri.you.lost.rsrcs.to.fleet", loot, strength);
                            // "You lost {0,rsrcs} to the pirate fleet (strength {1,number})."
                            /**
                             * tell everyone else that the player lost unknown resources
                             */
                            srv.messageToGameExcept(gn, vCon, new SOCPlayerElement(gn, vpn, SOCPlayerElement.LOSE, SOCPlayerElement.UNKNOWN, lootTotal), true);
                            srv.messageToGameKeyedSpecialExcept(ga, true, vCon, "action.rolled.sc_piri.player.lost.rsrcs.to.fleet", vicName, lootTotal, strength);
                        // "Joe lost 1 resource to pirate fleet attack (strength 3)." or
                        // "Joe lost 3 resources to pirate fleet attack (strength 3)."
                        }
                    }
                }
            }
            /**
             * if the roll is not 7, tell players what they got
             * (if 7, sendGameState already told them what they lost).
             */
            if (ga.getCurrentDice() != 7) {
                boolean noPlayersGained = true;
                /**
                 * Clients v2.0.00 and newer get an i18n-neutral SOCDiceResultResources message.
                 * Older clients get a string such as "Joe gets 3 sheep. Mike gets 1 clay."
                 */
                String rollRsrcTxtOldCli = null;
                SOCDiceResultResources rollRsrcMsgNewCli = null;
                if (ga.clientVersionHighest >= SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES) {
                    rollRsrcMsgNewCli = SOCDiceResultResources.buildForGame(ga);
                    noPlayersGained = (rollRsrcMsgNewCli == null);
                }
                if (ga.clientVersionLowest < SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES) {
                    // Build a string to announce to v1.x.xx clients
                    StringBuffer gainsText = new StringBuffer();
                    // for string spacing; might be false due to loop for new clients in game
                    noPlayersGained = true;
                    for (int pn = 0; pn < ga.maxPlayers; ++pn) {
                        if (!ga.isSeatVacant(pn)) {
                            SOCPlayer pp = ga.getPlayer(pn);
                            SOCResourceSet rsrcs = pp.getRolledResources();
                            if (rsrcs.getKnownTotal() != 0) {
                                if (noPlayersGained)
                                    noPlayersGained = false;
                                else
                                    gainsText.append(" ");
                                gainsText.append(c.getLocalizedSpecial(ga, "_nolocaliz.roll.gets.resources", pp.getName(), rsrcs));
                                // "{0} gets {1,rsrcs}."
                                // get it from any connection's StringManager, because that string is never localized
                                // Announce SOCPlayerElement.GAIN messages
                                handler.reportRsrcGainLoss(gn, rsrcs, false, false, pn, -1, null, null);
                            }
                        }
                    }
                    if (!noPlayersGained)
                        rollRsrcTxtOldCli = gainsText.toString();
                }
                if (noPlayersGained) {
                    String key;
                    if (roll.cloth == null)
                        // "No player gets anything."
                        key = "action.rolled.no.player.gets.anything";
                    else
                        // "No player gets resources."
                        key = "action.rolled.no.player.gets.resources";
                    // debug_printPieceDiceNumbers(ga, message);
                    srv.messageToGameKeyed(ga, true, key);
                } else {
                    if (rollRsrcTxtOldCli == null)
                        srv.messageToGame(gn, rollRsrcMsgNewCli);
                    else if (rollRsrcMsgNewCli == null)
                        srv.messageToGame(gn, rollRsrcTxtOldCli);
                    else {
                        // neither is null: we have old and new clients
                        srv.messageToGameForVersions(ga, 0, (SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES - 1), new SOCGameTextMsg(gn, SOCGameTextMsg.SERVERNAME, rollRsrcTxtOldCli), true);
                        srv.messageToGameForVersions(ga, SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES, Integer.MAX_VALUE, rollRsrcMsgNewCli, true);
                    }
                    // 
                    for (int pn = 0; pn < ga.maxPlayers; ++pn) {
                        final SOCPlayer pp = ga.getPlayer(pn);
                        Connection playerCon = srv.getConnection(pp.getName());
                        if (playerCon == null)
                            continue;
                        if (pp.getRolledResources().getKnownTotal() == 0)
                            // skip if player didn't gain; before v2.0.00 each player in game got these
                            continue;
                        // send CLAY, ORE, SHEEP, WHEAT, WOOD even if player's amount is 0
                        final SOCResourceSet resources = pp.getResources();
                        final int[] counts = resources.getAmounts(false);
                        if (playerCon.getVersion() >= SOCPlayerElements.MIN_VERSION)
                            srv.messageToPlayer(playerCon, new SOCPlayerElements(gn, pn, SOCPlayerElement.SET, SOCGameHandler.ELEM_RESOURCES, counts));
                        else
                            for (int i = 0; i < counts.length; ++i) srv.messageToPlayer(playerCon, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCGameHandler.ELEM_RESOURCES[i], counts[i]));
                        if (ga.clientVersionLowest < SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES)
                            srv.messageToGame(gn, new SOCResourceCount(gn, pn, resources.getTotal()));
                    // else, already-sent SOCDiceResultResources included players' new resource totals
                    // we'll send gold picks text, PLAYERELEMENT, and SIMPLEREQUEST(PROMPT_PICK_RESOURCES)
                    // after the per-player loop
                    }
                }
                if (roll.cloth != null) {
                    // Send village cloth trade distribution
                    final int coord = roll.cloth[1];
                    final SOCBoardLarge board = (SOCBoardLarge) (ga.getBoard());
                    SOCVillage vi = board.getVillageAtNode(coord);
                    if (vi != null)
                        srv.messageToGame(gn, new SOCPieceValue(gn, coord, vi.getCloth(), 0));
                    if (roll.cloth[0] > 0)
                        // some taken from board general supply
                        srv.messageToGame(gn, new SOCPlayerElement(gn, -1, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, board.getCloth()));
                    // name of first player to receive cloth
                    String clplName = null;
                    // names of all players receiving cloth, if more than one
                    ArrayList<String> clpls = null;
                    for (int i = 2; i < roll.cloth.length; ++i) {
                        if (roll.cloth[i] == 0)
                            // this player didn't receive cloth
                            continue;
                        final int pn = i - 2;
                        final SOCPlayer clpl = ga.getPlayer(pn);
                        srv.messageToGame(gn, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, clpl.getCloth()));
                        if (clplName == null) {
                            // first pl to receive cloth
                            clplName = clpl.getName();
                        } else {
                            // second or further player
                            if (clpls == null) {
                                clpls = new ArrayList<String>();
                                clpls.add(clplName);
                            }
                            clpls.add(clpl.getName());
                        }
                    }
                    if (clpls == null)
                        srv.messageToGameKeyed(ga, true, "action.rolled.sc_clvi.received.cloth.1", clplName);
                    else
                        // "{0} received 1 cloth from a village."
                        srv.messageToGameKeyedSpecial(ga, true, "action.rolled.sc_clvi.received.cloth.n", clpls);
                // "{0,list} each received 1 cloth from a village."
                }
                if (ga.getGameState() == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE)
                    // gold picks text, PLAYERELEMENT, and SIMPLEREQUEST(PROMPT_PICK_RESOURCES)s
                    handler.sendGameState_sendGoldPickAnnounceText(ga, gn, null, roll);
            /*
                       if (D.ebugOn) {
                       for (int i=0; i < SOCGame.MAXPLAYERS; i++) {
                       SOCResourceSet rsrcs = ga.getPlayer(i).getResources();
                       String resourceMessage = "PLAYER "+i+" RESOURCES: ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.CLAY)+" ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.ORE)+" ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.SHEEP)+" ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.WHEAT)+" ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.WOOD)+" ";
                       resourceMessage += rsrcs.getAmount(SOCResourceConstants.UNKNOWN)+" ";
                       messageToGame(gn, new SOCGameTextMsg(gn, SERVERNAME, resourceMessage));
                       }
                       }
                     */
            } else {
                /**
                 * player rolled 7
                 * If anyone needs to discard, prompt them.
                 */
                if (ga.getGameState() == SOCGame.WAITING_FOR_DISCARDS) {
                    handler.sendGameState_sendDiscardRequests(ga, gn);
                } else if (ga.getGameState() == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE) {
                    // Used in _SC_PIRI, when 7 is rolled and a player wins against the pirate fleet
                    for (int pn = 0; pn < ga.maxPlayers; ++pn) {
                        final SOCPlayer pp = ga.getPlayer(pn);
                        final int numPick = pp.getNeedToPickGoldHexResources();
                        if ((!ga.isSeatVacant(pn)) && (numPick > 0)) {
                            Connection con = srv.getConnection(pp.getName());
                            if (con != null) {
                                srv.messageToGame(gn, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCPlayerElement.NUM_PICK_GOLD_HEX_RESOURCES, numPick));
                                con.put(SOCSimpleRequest.toCmd(gn, pn, SOCSimpleRequest.PROMPT_PICK_RESOURCES, numPick, 0));
                            }
                        }
                    }
                }
            }
        } else {
            srv.messageToPlayer(c, gn, "You can't roll right now.");
        }
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception caught at handleROLLDICE" + e);
    }
    ga.releaseMonitor();
}
Also used : SOCVillage(soc.game.SOCVillage) SOCBoardLarge(soc.game.SOCBoardLarge) Connection(soc.server.genericServer.Connection) SOCPlayer(soc.game.SOCPlayer) SOCResourceSet(soc.game.SOCResourceSet) SOCGame(soc.game.SOCGame)

Example 2 with SOCBoardLarge

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

the class SOCRobotBrain method run.

/**
 * Here is the run method.  Just keep receiving game events
 * through {@link #gameEventQ} and deal with each one.
 * Remember that we're sent a {@link SOCTimingPing} event once per second,
 * incrementing {@link #counter}.  That allows the bot to wait a certain
 * time for other players before it decides whether to do something.
 *<P>
 * Nearly all bot actions start in this method; the overview of bot structures
 * is in the {@link SOCRobotBrain class javadoc} for prominence.
 * See comments within <tt>run()</tt> for minor details.
 *<P>
 * The brain thread will run until {@link #kill()} has been called or its pinger stops,
 * or it receives a {@link SOCMessage#ROBOTDISMISS} request to exit the game.
 */
@Override
public void run() {
    // Thread name for debug
    try {
        Thread.currentThread().setName("robotBrain-" + client.getNickname() + "-" + game.getName());
    } catch (Throwable th) {
    }
    if (pinger != null) {
        pinger.start();
        while (alive) {
            try {
                // Sleeps until message received
                final SOCMessage mes = gameEventQ.get();
                final int mesType;
                if (mes != null) {
                    // Debug aid: When looking at message contents or setting a per-message breakpoint,
                    // skip the pings; note (mesType != SOCMessage.TIMINGPING) here.
                    mesType = mes.getType();
                    if (mesType != SOCMessage.TIMINGPING)
                        turnEventsCurrent.addElement(mes);
                    if (D.ebugOn)
                        D.ebugPrintln("mes - " + mes);
                } else {
                    mesType = -1;
                }
                if (waitingForTradeMsg && (counter > 10)) {
                    waitingForTradeMsg = false;
                    counter = 0;
                }
                if (waitingForTradeResponse && (counter > 100)) {
                    // Remember other players' responses, call client.clearOffer,
                    // clear waitingForTradeResponse and counter.
                    tradeStopWaitingClearOffer();
                }
                if (waitingForGameState && (counter > 10000)) {
                    // D.ebugPrintln("counter = "+counter);
                    // D.ebugPrintln("RESEND");
                    counter = 0;
                    client.resend();
                }
                if (mesType == SOCMessage.GAMESTATE) {
                    handleGAMESTATE(((SOCGameState) mes).getState());
                // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                } else if (mesType == SOCMessage.STARTGAME) {
                    handleGAMESTATE(((SOCStartGame) mes).getGameState());
                // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                } else if (mesType == SOCMessage.TURN) {
                    // Start of a new player's turn.
                    // Update game and reset most of our state fields.
                    // See also below: if ((mesType == SOCMessage.TURN) && ourTurn).
                    handleGAMESTATE(((SOCTurn) mes).getGameState());
                    // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                    game.setCurrentPlayerNumber(((SOCTurn) mes).getPlayerNumber());
                    game.updateAtTurn();
                    // 
                    // remove any expected states
                    // 
                    expectROLL_OR_CARD = false;
                    expectPLAY1 = false;
                    expectPLACING_ROAD = false;
                    expectPLACING_SETTLEMENT = false;
                    expectPLACING_CITY = false;
                    expectPLACING_SHIP = false;
                    expectPLACING_ROBBER = false;
                    expectPLACING_FREE_ROAD1 = false;
                    expectPLACING_FREE_ROAD2 = false;
                    expectPLACING_INV_ITEM = false;
                    expectDICERESULT = false;
                    expectDISCARD = false;
                    expectMOVEROBBER = false;
                    expectWAITING_FOR_DISCOVERY = false;
                    expectWAITING_FOR_MONOPOLY = false;
                    // 
                    if (robotParameters.getTradeFlag() == 1) {
                        doneTrading = false;
                    } else {
                        doneTrading = true;
                    }
                    waitingForTradeMsg = false;
                    waitingForTradeResponse = false;
                    negotiator.resetIsSelling();
                    negotiator.resetOffersMade();
                    waitingForPickSpecialItem = null;
                    waitingForSC_PIRI_FortressRequest = false;
                    // 
                    // check or reset any special-building-phase decisions
                    // 
                    decidedIfSpecialBuild = false;
                    if (game.getGameState() == SOCGame.SPECIAL_BUILDING) {
                        if (waitingForSpecialBuild && !buildingPlan.isEmpty()) {
                        // Keep the building plan.
                        // Will ask during loop body to build.
                        } else {
                        // We have no plan, but will call planBuilding()
                        // during the loop body.  If buildingPlan still empty,
                        // bottom of loop will end our Special Building turn,
                        // just as it would in gamestate PLAY1.  Otherwise,
                        // will ask to build after planBuilding.
                        }
                    } else {
                        // 
                        // reset any plans we had
                        // 
                        buildingPlan.clear();
                    }
                    negotiator.resetTargetPieces();
                    // 
                    // swap the message-history queues
                    // 
                    {
                        Vector<SOCMessage> oldPrev = turnEventsPrev;
                        turnEventsPrev = turnEventsCurrent;
                        oldPrev.clear();
                        turnEventsCurrent = oldPrev;
                    }
                    turnExceptionCount = 0;
                }
                if (game.getCurrentPlayerNumber() == ourPlayerNumber) {
                    ourTurn = true;
                    waitingForSpecialBuild = false;
                } else {
                    ourTurn = false;
                }
                if ((mesType == SOCMessage.TURN) && ourTurn) {
                    waitingForOurTurn = false;
                    // Clear some per-turn variables.
                    // For others, see above: if (mesType == SOCMessage.TURN)
                    whatWeFailedToBuild = null;
                    failedBuildingAttempts = 0;
                    rejectedPlayDevCardType = -1;
                    rejectedPlayInvItem = null;
                }
                /**
                 * Handle some message types early.
                 *
                 * When reading the main flow of this method, skip past here;
                 * search for "it's time to decide to build or take other normal actions".
                 */
                switch(mesType) {
                    case SOCMessage.PLAYERELEMENT:
                        // If this during the ROLL_OR_CARD state, also updates the
                        // negotiator's is-selling flags.
                        // If our player is losing a resource needed for the 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.
                        handlePLAYERELEMENT((SOCPlayerElement) mes);
                        break;
                    case SOCMessage.PLAYERELEMENTS:
                        // Multiple PLAYERELEMENT updates;
                        // see comment above for actions taken.
                        handlePLAYERELEMENTS((SOCPlayerElements) mes);
                        break;
                    case SOCMessage.RESOURCECOUNT:
                        handlePLAYERELEMENT(null, ((SOCResourceCount) mes).getPlayerNumber(), SOCPlayerElement.SET, SOCPlayerElement.RESOURCE_COUNT, ((SOCResourceCount) mes).getCount());
                        break;
                    case SOCMessage.DICERESULT:
                        game.setCurrentDice(((SOCDiceResult) mes).getResult());
                        break;
                    case SOCMessage.PUTPIECE:
                        handlePUTPIECE_updateGameData((SOCPutPiece) mes);
                        // For initial roads, also tracks their initial settlement in SOCPlayerTracker.
                        break;
                    case SOCMessage.MOVEPIECE:
                        {
                            SOCMovePiece mpm = (SOCMovePiece) mes;
                            SOCShip sh = new SOCShip(game.getPlayer(mpm.getPlayerNumber()), mpm.getFromCoord(), null);
                            game.moveShip(sh, mpm.getToCoord());
                        }
                        break;
                    case SOCMessage.CANCELBUILDREQUEST:
                        handleCANCELBUILDREQUEST((SOCCancelBuildRequest) mes);
                        break;
                    case SOCMessage.MOVEROBBER:
                        {
                            // 
                            // Note: Don't call ga.moveRobber() because that will call the
                            // functions to do the stealing.  We just want to set where
                            // the robber moved, without seeing if something was stolen.
                            // MOVEROBBER will be followed by PLAYERELEMENT messages to
                            // report the gain/loss of resources.
                            // 
                            moveRobberOnSeven = false;
                            final int newHex = ((SOCMoveRobber) mes).getCoordinates();
                            if (newHex >= 0)
                                game.getBoard().setRobberHex(newHex, true);
                            else
                                ((SOCBoardLarge) game.getBoard()).setPirateHex(-newHex, true);
                        }
                        break;
                    case SOCMessage.MAKEOFFER:
                        if (robotParameters.getTradeFlag() == 1)
                            handleMAKEOFFER((SOCMakeOffer) mes);
                        break;
                    case SOCMessage.CLEAROFFER:
                        if (robotParameters.getTradeFlag() == 1) {
                            final int pn = ((SOCClearOffer) mes).getPlayerNumber();
                            if (pn != -1) {
                                game.getPlayer(pn).setCurrentOffer(null);
                            } else {
                                for (int i = 0; i < game.maxPlayers; ++i) game.getPlayer(i).setCurrentOffer(null);
                            }
                        }
                        break;
                    case SOCMessage.ACCEPTOFFER:
                        if (waitingForTradeResponse && (robotParameters.getTradeFlag() == 1)) {
                            if ((ourPlayerNumber == (((SOCAcceptOffer) mes).getOfferingNumber())) || (ourPlayerNumber == ((SOCAcceptOffer) mes).getAcceptingNumber())) {
                                waitingForTradeResponse = false;
                            }
                        }
                        break;
                    case SOCMessage.REJECTOFFER:
                        if (robotParameters.getTradeFlag() == 1)
                            handleREJECTOFFER((SOCRejectOffer) mes);
                        break;
                    case SOCMessage.DEVCARDACTION:
                        {
                            SOCDevCardAction dcMes = (SOCDevCardAction) mes;
                            if (dcMes.getAction() != SOCDevCardAction.CANNOT_PLAY) {
                                handleDEVCARDACTION(dcMes);
                            } else {
                                // rejected by server, can't play our requested card
                                rejectedPlayDevCardType = dcMes.getCardType();
                                waitingForGameState = false;
                                expectPLACING_FREE_ROAD1 = false;
                                expectWAITING_FOR_DISCOVERY = false;
                                expectWAITING_FOR_MONOPOLY = false;
                                expectPLACING_ROBBER = false;
                            }
                        }
                        break;
                    case SOCMessage.SIMPLEREQUEST:
                        if (ourTurn && waitingForSC_PIRI_FortressRequest) {
                            final SOCSimpleRequest rqMes = (SOCSimpleRequest) mes;
                            if ((rqMes.getRequestType() == SOCSimpleRequest.SC_PIRI_FORT_ATTACK) && (rqMes.getPlayerNumber() == -1)) {
                                // Attack request was denied: End our turn now.
                                // Reset method sets waitingForGameState, which will bypass
                                // any further actions in the run() loop body.
                                waitingForSC_PIRI_FortressRequest = false;
                                resetFieldsAtEndTurn();
                                client.endTurn(game);
                            }
                        // else, from another player; we can ignore it
                        }
                        break;
                    case SOCMessage.SIMPLEACTION:
                        switch(((SOCSimpleAction) mes).getActionType()) {
                            case SOCSimpleAction.SC_PIRI_FORT_ATTACK_RESULT:
                                if (ourTurn && waitingForSC_PIRI_FortressRequest) {
                                    // Our player has won or lost an attack on a pirate fortress.
                                    // When we receive this message, other messages have already
                                    // been sent to update related game state. End our turn now.
                                    // Reset method sets waitingForGameState, which will bypass
                                    // any further actions in the run() loop body.
                                    waitingForSC_PIRI_FortressRequest = false;
                                    resetFieldsAtEndTurn();
                                // client.endTurn not needed; making the attack implies sending endTurn
                                }
                                break;
                        }
                        break;
                    case SOCMessage.INVENTORYITEMACTION:
                        if (((SOCInventoryItemAction) mes).action == SOCInventoryItemAction.CANNOT_PLAY) {
                            final List<SOCInventoryItem> itms = ourPlayerData.getInventory().getByStateAndType(SOCInventory.PLAYABLE, ((SOCInventoryItemAction) mes).itemType);
                            if (itms != null)
                                // any item of same type# is similar enough here
                                rejectedPlayInvItem = itms.get(0);
                            waitingForGameState = false;
                            // in case was rejected placement (SC_FTRI gift port, etc)
                            expectPLACING_INV_ITEM = false;
                        }
                        break;
                }
                // switch(mesType)
                debugInfo();
                if ((game.getGameState() == SOCGame.ROLL_OR_CARD) && !waitingForGameState) {
                    rollOrPlayKnightOrExpectDice();
                // On our turn, ask client to roll dice or play a knight;
                // on other turns, update flags to expect dice result.
                // Clears expectROLL_OR_CARD to false.
                // Sets either expectDICERESULT, or expectPLACING_ROBBER and waitingForGameState.
                }
                if (ourTurn && (game.getGameState() == SOCGame.WAITING_FOR_ROBBER_OR_PIRATE) && !waitingForGameState) {
                    // TODO handle moving the pirate too
                    // For now, always decide to move the robber.
                    // Once we move the robber, will also need to deal with state WAITING_FOR_ROB_CLOTH_OR_RESOURCE.
                    expectPLACING_ROBBER = true;
                    waitingForGameState = true;
                    counter = 0;
                    client.choosePlayer(game, SOCChoosePlayer.CHOICE_MOVE_ROBBER);
                    pause(200);
                } else if ((game.getGameState() == SOCGame.PLACING_ROBBER) && !waitingForGameState) {
                    expectPLACING_ROBBER = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!((expectROLL_OR_CARD || expectPLAY1) && (counter < 4000))) {
                            if (moveRobberOnSeven) {
                                // robber moved because 7 rolled on dice
                                moveRobberOnSeven = false;
                                waitingForGameState = true;
                                counter = 0;
                                expectPLAY1 = true;
                            } else {
                                waitingForGameState = true;
                                counter = 0;
                                if (oldGameState == SOCGame.ROLL_OR_CARD) {
                                    // robber moved from playing knight card before dice roll
                                    expectROLL_OR_CARD = true;
                                } else if (oldGameState == SOCGame.PLAY1) {
                                    // robber moved from playing knight card after dice roll
                                    expectPLAY1 = true;
                                }
                            }
                            counter = 0;
                            moveRobber();
                        }
                    }
                }
                if ((game.getGameState() == SOCGame.WAITING_FOR_DISCOVERY) && !waitingForGameState) {
                    expectWAITING_FOR_DISCOVERY = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectPLAY1) && (counter < 4000)) {
                            waitingForGameState = true;
                            expectPLAY1 = true;
                            counter = 0;
                            client.pickResources(game, resourceChoices);
                            pause(1500);
                        }
                    }
                }
                if ((game.getGameState() == SOCGame.WAITING_FOR_MONOPOLY) && !waitingForGameState) {
                    expectWAITING_FOR_MONOPOLY = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectPLAY1) && (counter < 4000)) {
                            waitingForGameState = true;
                            expectPLAY1 = true;
                            counter = 0;
                            client.pickResourceType(game, monopolyStrategy.getMonopolyChoice());
                            pause(1500);
                        }
                    }
                }
                if (ourTurn && (!waitingForOurTurn) && (game.getGameState() == SOCGame.PLACING_INV_ITEM) && (!waitingForGameState)) {
                    // choose and send a placement location
                    planAndPlaceInvItem();
                }
                if (waitingForTradeMsg && (mesType == SOCMessage.BANKTRADE) && (((SOCBankTrade) mes).getPlayerNumber() == ourPlayerNumber)) {
                    // 
                    // This is the bank/port trade confirmation announcement we've been waiting for
                    // 
                    waitingForTradeMsg = false;
                }
                if (waitingForDevCard && (mesType == SOCMessage.SIMPLEACTION) && (((SOCSimpleAction) mes).getPlayerNumber() == ourPlayerNumber) && (((SOCSimpleAction) mes).getActionType() == SOCSimpleAction.DEVCARD_BOUGHT)) {
                    // 
                    // This is the "dev card bought" message we've been waiting for
                    // 
                    waitingForDevCard = false;
                }
                /**
                 * Planning: If our turn and not waiting for something,
                 * it's time to decide to build or take other normal actions.
                 */
                if (((game.getGameState() == SOCGame.PLAY1) || (game.getGameState() == SOCGame.SPECIAL_BUILDING)) && !(waitingForGameState || waitingForTradeMsg || waitingForTradeResponse || waitingForDevCard || expectPLACING_ROAD || expectPLACING_SETTLEMENT || expectPLACING_CITY || expectPLACING_SHIP || expectPLACING_FREE_ROAD1 || expectPLACING_FREE_ROAD2 || expectPLACING_ROBBER || expectWAITING_FOR_DISCOVERY || expectWAITING_FOR_MONOPOLY || waitingForSC_PIRI_FortressRequest || (waitingForPickSpecialItem != null))) {
                    expectPLAY1 = false;
                    // during other players' turns.
                    if ((!ourTurn) && waitingForOurTurn && gameIs6Player && (!decidedIfSpecialBuild) && (!expectPLACING_ROBBER)) {
                        decidedIfSpecialBuild = true;
                        if (buildingPlan.empty() && (ourPlayerData.getResources().getTotal() > 1) && (failedBuildingAttempts < MAX_DENIED_BUILDING_PER_TURN)) {
                            planBuilding();
                            if (!buildingPlan.empty()) {
                                // If we have the resources right now, ask to Special Build
                                final SOCPossiblePiece targetPiece = buildingPlan.peek();
                                final SOCResourceSet targetResources = targetPiece.getResourcesToBuild();
                                if ((ourPlayerData.getResources().contains(targetResources))) {
                                    // Ask server for the Special Building Phase.
                                    // (TODO) if FAST_STRATEGY: Maybe randomly don't ask, to lower opponent difficulty?
                                    waitingForSpecialBuild = true;
                                    client.buildRequest(game, -1);
                                    pause(100);
                                }
                            }
                        }
                    }
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectROLL_OR_CARD && (counter < 4000))) {
                            counter = 0;
                            // D.ebugPrintln("DOING PLAY1");
                            if (D.ebugOn) {
                                client.sendText(game, "================================");
                                // for each player in game:
                                // sendText and debug-prn game.getPlayer(i).getResources()
                                printResources();
                            }
                            /**
                             * if we haven't played a dev card yet,
                             * and we have a knight, and we can get
                             * largest army, play the knight.
                             * If we're in SPECIAL_BUILDING (not PLAY1),
                             * can't trade or play development cards.
                             *
                             * In scenario _SC_PIRI (which has no robber and
                             * no largest army), play one whenever we have
                             * it, someone else has resources, and we can
                             * convert a ship to a warship.
                             */
                            if ((game.getGameState() == SOCGame.PLAY1) && !ourPlayerData.hasPlayedDevCard()) {
                                // might set expectPLACING_ROBBER and waitingForGameState
                                playKnightCardIfShould();
                            }
                            /**
                             * make a plan if we don't have one,
                             * and if we haven't given up building
                             * attempts this turn.
                             */
                            if ((!expectPLACING_ROBBER) && buildingPlan.empty() && (ourPlayerData.getResources().getTotal() > 1) && (failedBuildingAttempts < MAX_DENIED_BUILDING_PER_TURN)) {
                                planBuilding();
                            /*
                                         * planBuilding takes these actions, sets buildingPlan and other fields
                                         * (see its javadoc):
                                         *
                                        decisionMaker.planStuff(robotParameters.getStrategyType());

                                        if (! buildingPlan.empty())
                                        {
                                            lastTarget = (SOCPossiblePiece) buildingPlan.peek();
                                            negotiator.setTargetPiece(ourPlayerNumber, buildingPlan.peek());
                                        }
                                         */
                            }
                            // D.ebugPrintln("DONE PLANNING");
                            if ((!expectPLACING_ROBBER) && (!buildingPlan.empty())) {
                                // Time to build something.
                                // Either ask to build a piece, or use trading or development
                                // cards to get resources to build it.  See javadoc for flags set
                                // (expectPLACING_ROAD, etc).  In a future iteration of the run loop
                                // with the expected PLACING_ state, we'll build whatWeWantToBuild
                                // in placeIfExpectPlacing().
                                buildOrGetResourceByTradeOrCard();
                            }
                            /**
                             * see if we're done with our turn
                             */
                            if (!(expectPLACING_SETTLEMENT || expectPLACING_FREE_ROAD1 || expectPLACING_FREE_ROAD2 || expectPLACING_ROAD || expectPLACING_CITY || expectPLACING_SHIP || expectWAITING_FOR_DISCOVERY || expectWAITING_FOR_MONOPOLY || expectPLACING_ROBBER || waitingForTradeMsg || waitingForTradeResponse || waitingForDevCard || waitingForGameState || (waitingForPickSpecialItem != null))) {
                                // Any last things for turn from game's scenario?
                                boolean scenActionTaken = false;
                                if (game.isGameOptionSet(SOCGameOption.K_SC_FTRI) || game.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
                                    // possibly attack pirate fortress
                                    // or place a gift port for better bank trades
                                    scenActionTaken = considerScenarioTurnFinalActions();
                                }
                                if (!scenActionTaken) {
                                    resetFieldsAtEndTurn();
                                    /*
                                             * These state fields are reset:
                                             *
                                            waitingForGameState = true;
                                            counter = 0;
                                            expectROLL_OR_CARD = true;
                                            waitingForOurTurn = true;

                                            doneTrading = (robotParameters.getTradeFlag() != 1);

                                            //D.ebugPrintln("!!! ENDING TURN !!!");
                                            negotiator.resetIsSelling();
                                            negotiator.resetOffersMade();
                                            buildingPlan.clear();
                                            negotiator.resetTargetPieces();
                                             */
                                    pause(1500);
                                    client.endTurn(game);
                                }
                            }
                        }
                    }
                }
                /**
                 * Placement: Make various putPiece calls; server has told us it's OK to buy them.
                 * Call client.putPiece.
                 * Works when it's our turn and we have an expect flag set
                 * (such as expectPLACING_SETTLEMENT, in these game states:
                 * START1A - START2B or - START3B
                 * PLACING_SETTLEMENT, PLACING_ROAD, PLACING_CITY
                 * PLACING_FREE_ROAD1, PLACING_FREE_ROAD2
                 */
                if (!waitingForGameState) {
                    placeIfExpectPlacing();
                }
                /**
                 * Handle various message types here at bottom of loop.
                 */
                switch(mesType) {
                    case SOCMessage.PUTPIECE:
                        /**
                         * this is for player tracking
                         *
                         * For initial placement of our own pieces, also checks
                         * and clears expectPUTPIECE_FROM_START1A,
                         * and sets expectSTART1B, etc.  The final initial putpiece
                         * clears expectPUTPIECE_FROM_START2B and sets expectROLL_OR_CARD.
                         */
                        {
                            final SOCPutPiece mpp = (SOCPutPiece) mes;
                            final int pn = mpp.getPlayerNumber();
                            final int coord = mpp.getCoordinates();
                            final int pieceType = mpp.getPieceType();
                            handlePUTPIECE_updateTrackers(pn, coord, pieceType);
                        }
                        break;
                    case SOCMessage.MOVEPIECE:
                        /**
                         * this is for player tracking of moved ships
                         */
                        {
                            final SOCMovePiece mpp = (SOCMovePiece) mes;
                            final int pn = mpp.getPlayerNumber();
                            final int coord = mpp.getToCoord();
                            final int pieceType = mpp.getPieceType();
                            // TODO what about getFromCoord()?
                            handlePUTPIECE_updateTrackers(pn, coord, pieceType);
                        }
                        break;
                    case SOCMessage.DICERESULT:
                        if (expectDICERESULT) {
                            expectDICERESULT = false;
                            if (((SOCDiceResult) mes).getResult() == 7) {
                                final boolean robWithoutRobber = game.isGameOptionSet(SOCGameOption.K_SC_PIRI);
                                if (!robWithoutRobber)
                                    moveRobberOnSeven = true;
                                if (ourPlayerData.getResources().getTotal() > 7)
                                    expectDISCARD = true;
                                else if (ourTurn) {
                                    if (!robWithoutRobber)
                                        expectPLACING_ROBBER = true;
                                    else
                                        expectPLAY1 = true;
                                }
                            } else {
                                expectPLAY1 = true;
                            }
                        }
                        break;
                    case SOCMessage.SIMPLEREQUEST:
                        // These messages can almost always be ignored by bots.
                        // Some request types are handled at the top of the loop body;
                        // search for SOCMessage.SIMPLEREQUEST
                        {
                            final SOCSimpleRequest rqMes = (SOCSimpleRequest) mes;
                            switch(rqMes.getRequestType()) {
                                case SOCSimpleRequest.PROMPT_PICK_RESOURCES:
                                    // gold hex
                                    counter = 0;
                                    pickFreeResources(rqMes.getValue1());
                                    waitingForGameState = true;
                                    if (game.isInitialPlacement()) {
                                        if (game.isGameOptionSet(SOCGameOption.K_SC_3IP))
                                            expectSTART3B = true;
                                        else
                                            expectSTART2B = true;
                                    } else {
                                        expectPLAY1 = true;
                                    }
                                    break;
                            }
                        }
                        break;
                    case SOCMessage.DISCARDREQUEST:
                        expectDISCARD = false;
                        // {
                        if ((game.getCurrentDice() == 7) && ourTurn) {
                            if (!game.isGameOptionSet(SOCGameOption.K_SC_PIRI))
                                expectPLACING_ROBBER = true;
                            else
                                expectPLAY1 = true;
                        } else {
                            expectPLAY1 = true;
                        }
                        counter = 0;
                        client.discard(game, DiscardStrategy.discard(((SOCDiscardRequest) mes).getNumberOfDiscards(), buildingPlan, rand, ourPlayerData, robotParameters, decisionMaker, negotiator));
                        // }
                        break;
                    case SOCMessage.CHOOSEPLAYERREQUEST:
                        {
                            final int choicePl = RobberStrategy.chooseRobberVictim(((SOCChoosePlayerRequest) mes).getChoices(), game, playerTrackers);
                            counter = 0;
                            client.choosePlayer(game, choicePl);
                        }
                        break;
                    case SOCMessage.CHOOSEPLAYER:
                        {
                            final int vpn = ((SOCChoosePlayer) mes).getChoice();
                            // Cloth is more valuable.
                            // TODO decide when we should choose resources instead
                            client.choosePlayer(game, -(vpn + 1));
                        }
                        break;
                    case SOCMessage.SETSPECIALITEM:
                        if (waitingForPickSpecialItem != null) {
                            final SOCSetSpecialItem siMes = (SOCSetSpecialItem) mes;
                            if (siMes.typeKey.equals(waitingForPickSpecialItem)) {
                                switch(siMes.op) {
                                    case SOCSetSpecialItem.OP_PICK:
                                        waitingForPickSpecialItem = null;
                                        // Any specific action needed? Not for SC_WOND.
                                        break;
                                    case SOCSetSpecialItem.OP_DECLINE:
                                        waitingForPickSpecialItem = null;
                                        // TODO how to prevent asking again? (similar to whatWeFailedtoBuild)
                                        break;
                                }
                            }
                        }
                        break;
                    case SOCMessage.ROBOTDISMISS:
                        if ((!expectDISCARD) && (!expectPLACING_ROBBER)) {
                            client.leaveGame(game, "dismiss msg", false, false);
                            alive = false;
                        }
                        break;
                    case SOCMessage.TIMINGPING:
                        // Once-per-second message from the pinger thread
                        counter++;
                        break;
                }
                if (ourTurn && (counter > 15000)) {
                    // We've been waiting too long, must be a bug: Leave the game.
                    // This is a fallback, server has SOCForceEndTurnThread which
                    // should have already taken action.
                    // Before v1.1.20, would leave game even during other (human) players' turns.
                    client.leaveGame(game, "counter 15000", true, false);
                    alive = false;
                }
                if ((failedBuildingAttempts > (2 * MAX_DENIED_BUILDING_PER_TURN)) && game.isInitialPlacement()) {
                    // Apparently can't decide where we can initially place:
                    // Leave the game.
                    client.leaveGame(game, "failedBuildingAttempts at start", true, false);
                    alive = false;
                }
                /*
                       if (D.ebugOn) {
                       if (mes != null) {
                       debugInfo();
                       D.ebugPrintln("~~~~~~~~~~~~~~~~");
                       }
                       }
                     */
                yield();
            } catch (Exception e) {
                // Print exception; ignore errors due to game reset in another thread
                if (alive && ((game == null) || (game.getGameState() != SOCGame.RESET_OLD))) {
                    // TODO end our turn if too many
                    ++turnExceptionCount;
                    String eMsg = (turnExceptionCount == 1) ? "*** Robot caught an exception - " + e : "*** Robot caught an exception (" + turnExceptionCount + " this turn) - " + e;
                    D.ebugPrintln(eMsg);
                    System.out.println(eMsg);
                    e.printStackTrace();
                }
            }
        }
    } else {
        System.out.println("AGG! NO PINGER!");
    }
    // D.ebugPrintln("STOPPING AND DEALLOCATING");
    gameEventQ = null;
    client.addCleanKill();
    client = null;
    game = null;
    ourPlayerData = null;
    dummyCancelPlayerData = null;
    whatWeWantToBuild = null;
    whatWeFailedToBuild = null;
    rejectedPlayInvItem = null;
    resourceChoices = null;
    ourPlayerTracker = null;
    playerTrackers = null;
    pinger.stopPinger();
    pinger = null;
}
Also used : SOCShip(soc.game.SOCShip) SOCMakeOffer(soc.message.SOCMakeOffer) SOCInventoryItem(soc.game.SOCInventoryItem) SOCRejectOffer(soc.message.SOCRejectOffer) SOCResourceSet(soc.game.SOCResourceSet) SOCMovePiece(soc.message.SOCMovePiece) Vector(java.util.Vector) SOCAcceptOffer(soc.message.SOCAcceptOffer) SOCMessage(soc.message.SOCMessage) SOCBoardLarge(soc.game.SOCBoardLarge) SOCStartGame(soc.message.SOCStartGame) SOCDiscardRequest(soc.message.SOCDiscardRequest) SOCSimpleAction(soc.message.SOCSimpleAction) SOCSetSpecialItem(soc.message.SOCSetSpecialItem) SOCClearOffer(soc.message.SOCClearOffer) SOCSimpleRequest(soc.message.SOCSimpleRequest) SOCPutPiece(soc.message.SOCPutPiece) SOCChoosePlayerRequest(soc.message.SOCChoosePlayerRequest) SOCDevCardAction(soc.message.SOCDevCardAction)

Example 3 with SOCBoardLarge

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

the class SOCRobotDM method smartGameStrategy.

/**
 * Plan building for the smart game strategy ({@link #SMART_STRATEGY}).
 * use player trackers' Win Game ETAs (WGETA) to determine best move
 * and update {@link #buildingPlan}.
 *<P>
 * For example, if {@link #favoriteSettlement} is chosen,
 * it's chosen from {@link #goodSettlements} or {@link #threatenedSettlements}.
 *<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.
 *
 *<H4>Outline:</H4>
 *<UL>
 * <LI> Determine our Win Game ETA, leading player's WGETA
 * <LI> {@link #scorePossibleSettlements(int, int) scorePossibleSettlements(BuildETAs, leaderWGETA)}:
 *      For each settlement we can build now (no roads/ships needed), add its ETA bonus to its score
 * <LI> Build {@link #goodRoads} from possibleRoads' roads & ships we can build now
 * <LI> Pick a {@link #favoriteSettlement} from threatened/good settlements, with the highest
 *      {@link SOCPossiblePiece#getScore() getScore()}  (ETA bonus)
 * <LI> Pick a {@link #favoriteRoad} from threatened/good, with highest getWinGameETABonusForRoad
 * <LI> Pick a {@link #favoriteCity} from our possibleCities, with highest score (ETA bonus)
 * <LI> If {@code favoriteCity} has the best score (best ETA if tied), choose to build the city
 * <LI> Otherwise choose {@code favoriteRoad} or {@code favoriteSettlement} based on their scores
 * <LI> If buying a dev card scores higher than the chosen piece, choose to buy one instead of building
 * <LI> Check for and calc any scenario-specific {@code buildingPlan}
 *</UL>
 *
 * @param buildingETAs  the ETAs for building each piece type
 * @see #dumbFastGameStrategy(int[])
 */
protected void smartGameStrategy(final int[] buildingETAs) {
    D.ebugPrintln("***** smartGameStrategy *****");
    // 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);
    // 
    // save the lr paths list to restore later
    // 
    @SuppressWarnings("unchecked") List<SOCLRPathData>[] savedLRPaths = new List[game.maxPlayers];
    for (int pn = 0; pn < game.maxPlayers; pn++) {
        savedLRPaths[pn] = new ArrayList<SOCLRPathData>();
        savedLRPaths[pn].addAll(game.getPlayer(pn).getLRPaths());
    }
    int ourCurrentWGETA = ourPlayerTracker.getWinGameETA();
    D.ebugPrintln("ourCurrentWGETA = " + ourCurrentWGETA);
    int leadersCurrentWGETA = ourCurrentWGETA;
    Iterator<SOCPlayerTracker> trackersIter = playerTrackers.values().iterator();
    while (trackersIter.hasNext()) {
        SOCPlayerTracker tracker = trackersIter.next();
        int wgeta = tracker.getWinGameETA();
        if (wgeta < leadersCurrentWGETA) {
            leadersCurrentWGETA = wgeta;
        }
    }
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) > 0) {
        scorePossibleSettlements(buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT], leadersCurrentWGETA);
    }
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD) > 0) {
        Iterator<SOCPossibleRoad> posRoadsIter = ourPlayerTracker.getPossibleRoads().values().iterator();
        while (posRoadsIter.hasNext()) {
            SOCPossibleRoad posRoad = posRoadsIter.next();
            if (!posRoad.isRoadNotShip())
                // ignore ships in this loop, ships have other conditions to check
                continue;
            if ((posRoad.getNecessaryRoads().isEmpty()) && (!threatenedRoads.contains(posRoad)) && (!goodRoads.contains(posRoad))) {
                goodRoads.add(posRoad);
            }
        }
    }
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.SHIP) > 0) {
        final SOCBoard board = game.getBoard();
        final int pirateHex = (board instanceof SOCBoardLarge) ? ((SOCBoardLarge) board).getPirateHex() : 0;
        final int[] pirateEdges = (pirateHex != 0) ? ((SOCBoardLarge) board).getAdjacentEdgesToHex_arr(pirateHex) : null;
        Iterator<SOCPossibleRoad> posRoadsIter = ourPlayerTracker.getPossibleRoads().values().iterator();
        while (posRoadsIter.hasNext()) {
            final SOCPossibleRoad posRoad = posRoadsIter.next();
            if (posRoad.isRoadNotShip())
                // ignore roads in this loop, we want ships
                continue;
            if (posRoad.getNecessaryRoads().isEmpty() && (!threatenedRoads.contains(posRoad)) && (!goodRoads.contains(posRoad))) {
                boolean edgeOK = true;
                if (pirateEdges != null) {
                    final int edge = posRoad.getCoordinates();
                    for (int i = 0; i < pirateEdges.length; ++i) {
                        if (edge == pirateEdges[i]) {
                            edgeOK = false;
                            break;
                        }
                    }
                }
                if (edgeOK)
                    goodRoads.add(posRoad);
            }
        }
    }
    /*
    ///
    /// check everything
    ///
    Enumeration threatenedSetEnum = threatenedSettlements.elements();
    while (threatenedSetEnum.hasMoreElements()) {
      SOCPossibleSettlement threatenedSet = (SOCPossibleSettlement)threatenedSetEnum.nextElement();
      D.ebugPrintln("*** threatened settlement at "+Integer.toHexString(threatenedSet.getCoordinates())+" has a score of "+threatenedSet.getScore());
      if (threatenedSet.getNecessaryRoads().isEmpty() &&
	  ! ourPlayerData.isPotentialSettlement(threatenedSet.getCoordinates())) {
	D.ebugPrintln("POTENTIAL SETTLEMENT ERROR");
	//System.exit(0);
      }
    }
    Enumeration goodSetEnum = goodSettlements.elements();
    while (goodSetEnum.hasMoreElements()) {
      SOCPossibleSettlement goodSet = (SOCPossibleSettlement)goodSetEnum.nextElement();
      D.ebugPrintln("*** good settlement at "+Integer.toHexString(goodSet.getCoordinates())+" has a score of "+goodSet.getScore());
      if (goodSet.getNecessaryRoads().isEmpty() &&
	  ! ourPlayerData.isPotentialSettlement(goodSet.getCoordinates())) {
	D.ebugPrintln("POTENTIAL SETTLEMENT ERROR");
	//System.exit(0);
      }
    }
    Enumeration threatenedRoadEnum = threatenedRoads.elements();
    while (threatenedRoadEnum.hasMoreElements()) {
      SOCPossibleRoad threatenedRoad = (SOCPossibleRoad)threatenedRoadEnum.nextElement();
      D.ebugPrintln("*** threatened road at "+Integer.toHexString(threatenedRoad.getCoordinates())+" has a score of "+threatenedRoad.getScore());
      if (threatenedRoad.getNecessaryRoads().isEmpty() &&
	  ! ourPlayerData.isPotentialRoad(threatenedRoad.getCoordinates())) {
	D.ebugPrintln("POTENTIAL ROAD ERROR");
	//System.exit(0);
      }
    }
    Enumeration goodRoadEnum = goodRoads.elements();
    while (goodRoadEnum.hasMoreElements()) {
      SOCPossibleRoad goodRoad = (SOCPossibleRoad)goodRoadEnum.nextElement();
      D.ebugPrintln("*** good road at "+Integer.toHexString(goodRoad.getCoordinates())+" has a score of "+goodRoad.getScore());
      if (goodRoad.getNecessaryRoads().isEmpty() &&
	  ! ourPlayerData.isPotentialRoad(goodRoad.getCoordinates())) {
	D.ebugPrintln("POTENTIAL ROAD ERROR");
	//System.exit(0);
      }
    }
    */
    D.ebugPrintln("PICKING WHAT TO BUILD");
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) > 0) {
        for (SOCPossibleSettlement threatenedSet : threatenedSettlements) {
            if (threatenedSet.getNecessaryRoads().isEmpty()) {
                D.ebugPrintln("$$$$$ threatened settlement at " + Integer.toHexString(threatenedSet.getCoordinates()) + " has a score of " + threatenedSet.getScore());
                if ((favoriteSettlement == null) || (threatenedSet.getScore() > favoriteSettlement.getScore())) {
                    favoriteSettlement = threatenedSet;
                }
            }
        }
        for (SOCPossibleSettlement goodSet : goodSettlements) {
            if (goodSet.getNecessaryRoads().isEmpty()) {
                D.ebugPrintln("$$$$$ good settlement at " + Integer.toHexString(goodSet.getCoordinates()) + " has a score of " + goodSet.getScore());
                if ((favoriteSettlement == null) || (goodSet.getScore() > favoriteSettlement.getScore())) {
                    favoriteSettlement = goodSet;
                }
            }
        }
    }
    // 
    // restore the LRPath list
    // 
    D.ebugPrintln("%%% RESTORING LRPATH LIST %%%");
    for (int pn = 0; pn < game.maxPlayers; pn++) {
        game.getPlayer(pn).setLRPaths(savedLRPaths[pn]);
    }
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD) > 0) {
        for (SOCPossibleRoad threatenedRoad : threatenedRoads) {
            D.ebugPrintln("$$$$$ threatened road at " + Integer.toHexString(threatenedRoad.getCoordinates()));
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().startRecording("ROAD" + threatenedRoad.getCoordinates());
                brain.getDRecorder().record("Estimate value of road at " + game.getBoard().edgeCoordToString(threatenedRoad.getCoordinates()));
            }
            // 
            // see how building this piece impacts our winETA
            // 
            threatenedRoad.resetScore();
            float wgetaScore = getWinGameETABonusForRoad(threatenedRoad, buildingETAs[SOCBuildingSpeedEstimate.ROAD], leadersCurrentWGETA, playerTrackers);
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().stopRecording();
            }
            D.ebugPrintln("wgetaScore = " + wgetaScore);
            if (favoriteRoad == null) {
                favoriteRoad = threatenedRoad;
            } else {
                if (threatenedRoad.getScore() > favoriteRoad.getScore()) {
                    favoriteRoad = threatenedRoad;
                }
            }
        }
        for (SOCPossibleRoad goodRoad : goodRoads) {
            D.ebugPrintln("$$$$$ good road at " + Integer.toHexString(goodRoad.getCoordinates()));
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().startRecording("ROAD" + goodRoad.getCoordinates());
                brain.getDRecorder().record("Estimate value of road at " + game.getBoard().edgeCoordToString(goodRoad.getCoordinates()));
            }
            // 
            // see how building this piece impacts our winETA
            // 
            // TODO better ETA scoring for coastal ships/roads
            // 
            goodRoad.resetScore();
            final int etype = ((goodRoad instanceof SOCPossibleShip) && !((SOCPossibleShip) goodRoad).isCoastalRoadAndShip) ? SOCBuildingSpeedEstimate.ROAD : SOCBuildingSpeedEstimate.SHIP;
            float wgetaScore = getWinGameETABonusForRoad(goodRoad, buildingETAs[etype], leadersCurrentWGETA, playerTrackers);
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().stopRecording();
            }
            D.ebugPrintln("wgetaScore = " + wgetaScore);
            if (favoriteRoad == null) {
                favoriteRoad = goodRoad;
            } else {
                if (goodRoad.getScore() > favoriteRoad.getScore()) {
                    favoriteRoad = goodRoad;
                }
            }
        }
    }
    // 
    // restore the LRPath list
    // 
    D.ebugPrintln("%%% RESTORING LRPATH LIST %%%");
    for (int pn = 0; pn < game.maxPlayers; pn++) {
        game.getPlayer(pn).setLRPaths(savedLRPaths[pn]);
    }
    // /
    if (ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) {
        HashMap<Integer, SOCPlayerTracker> trackersCopy = SOCPlayerTracker.copyPlayerTrackers(playerTrackers);
        SOCPlayerTracker ourTrackerCopy = trackersCopy.get(Integer.valueOf(ourPlayerNumber));
        int[] originalWGETAs = new int[game.maxPlayers];
        int[] WGETAdiffs = new int[game.maxPlayers];
        Vector<SOCPlayerTracker> leaders = new Vector<SOCPlayerTracker>();
        int bestWGETA = 1000;
        // int bonus = 0;
        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 value of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
            }
            // 
            // see how building this piece impacts our winETA
            // 
            leaders.clear();
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().suspend();
            }
            SOCPlayerTracker.updateWinGameETAs(trackersCopy);
            // TODO refactor? This section is like a copy of calcWGETABonus, with something added in the middle
            Iterator<SOCPlayerTracker> trackersBeforeIter = trackersCopy.values().iterator();
            while (trackersBeforeIter.hasNext()) {
                SOCPlayerTracker trackerBefore = trackersBeforeIter.next();
                final int pn = trackerBefore.getPlayer().getPlayerNumber();
                D.ebugPrintln("$$$ win game ETA for player " + pn + " = " + trackerBefore.getWinGameETA());
                originalWGETAs[pn] = trackerBefore.getWinGameETA();
                WGETAdiffs[pn] = trackerBefore.getWinGameETA();
                if (trackerBefore.getWinGameETA() < bestWGETA) {
                    bestWGETA = trackerBefore.getWinGameETA();
                    leaders.removeAllElements();
                    leaders.addElement(trackerBefore);
                } else if (trackerBefore.getWinGameETA() == bestWGETA) {
                    leaders.addElement(trackerBefore);
                }
            }
            D.ebugPrintln("^^^^ bestWGETA = " + bestWGETA);
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().resume();
            }
            // 
            // place the city
            // 
            SOCCity tmpCity = new SOCCity(ourPlayerData, posCity.getCoordinates(), null);
            game.putTempPiece(tmpCity);
            ourTrackerCopy.addOurNewCity(tmpCity);
            SOCPlayerTracker.updateWinGameETAs(trackersCopy);
            float wgetaScore = calcWGETABonusAux(originalWGETAs, trackersCopy, leaders);
            // 
            // remove the city
            // 
            ourTrackerCopy.undoAddOurNewCity(posCity);
            game.undoPutTempPiece(tmpCity);
            D.ebugPrintln("*** ETA for city = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().record("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
            }
            float etaBonus = getETABonus(buildingETAs[SOCBuildingSpeedEstimate.CITY], leadersCurrentWGETA, wgetaScore);
            D.ebugPrintln("etaBonus = " + etaBonus);
            posCity.addToScore(etaBonus);
            if ((brain != null) && (brain.getDRecorder().isOn())) {
                brain.getDRecorder().record("WGETA score = " + df1.format(wgetaScore));
                brain.getDRecorder().record("Total city score = " + df1.format(etaBonus));
                brain.getDRecorder().stopRecording();
            }
            D.ebugPrintln("$$$  final score = " + posCity.getScore());
            D.ebugPrintln("$$$$$ possible city at " + Integer.toHexString(posCity.getCoordinates()) + " has a score of " + posCity.getScore());
            if ((favoriteCity == null) || (posCity.getScore() > favoriteCity.getScore())) {
                favoriteCity = posCity;
            }
        }
    }
    if (favoriteSettlement != null) {
        D.ebugPrintln("### FAVORITE SETTLEMENT IS AT " + Integer.toHexString(favoriteSettlement.getCoordinates()));
        D.ebugPrintln("###   WITH A SCORE OF " + favoriteSettlement.getScore());
        D.ebugPrintln("###   WITH AN ETA OF " + buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT]);
        D.ebugPrintln("###   WITH A TOTAL SPEEDUP OF " + favoriteSettlement.getSpeedupTotal());
    }
    if (favoriteCity != null) {
        D.ebugPrintln("### FAVORITE CITY IS AT " + Integer.toHexString(favoriteCity.getCoordinates()));
        D.ebugPrintln("###   WITH A SCORE OF " + favoriteCity.getScore());
        D.ebugPrintln("###   WITH AN ETA OF " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
        D.ebugPrintln("###   WITH A TOTAL SPEEDUP OF " + favoriteCity.getSpeedupTotal());
    }
    final int road_eta_type = ((favoriteRoad != null) && (favoriteRoad instanceof SOCPossibleShip) && // TODO better ETA calc for coastal roads/ships
    !((SOCPossibleShip) favoriteRoad).isCoastalRoadAndShip) ? SOCBuildingSpeedEstimate.SHIP : SOCBuildingSpeedEstimate.ROAD;
    if (favoriteRoad != null) {
        D.ebugPrintln("### FAVORITE ROAD IS AT " + Integer.toHexString(favoriteRoad.getCoordinates()));
        D.ebugPrintln("###   WITH AN ETA OF " + buildingETAs[road_eta_type]);
        D.ebugPrintln("###   WITH A SCORE OF " + favoriteRoad.getScore());
    }
    // piece type, if any, to be pushed onto buildingPlan;
    int pick = -1;
    // use ROAD for road or ship, use MAXPLUSONE for dev card
    // getScore() of picked piece
    float pickScore = 0f;
    // /
    if ((favoriteCity != null) && (ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) && (favoriteCity.getScore() > 0) && ((favoriteSettlement == null) || (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) == 0) || (favoriteCity.getScore() > favoriteSettlement.getScore()) || ((favoriteCity.getScore() == favoriteSettlement.getScore()) && (buildingETAs[SOCBuildingSpeedEstimate.CITY] < buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT]))) && ((favoriteRoad == null) || (ourPlayerData.getNumPieces(favoriteRoad.getType()) == 0) || (favoriteCity.getScore() > favoriteRoad.getScore()) || ((favoriteCity.getScore() == favoriteRoad.getScore()) && (buildingETAs[SOCBuildingSpeedEstimate.CITY] < buildingETAs[road_eta_type])))) {
        D.ebugPrintln("### PICKED FAVORITE CITY");
        pick = SOCPlayingPiece.CITY;
        pickScore = favoriteCity.getScore();
    } else // /
    if ((favoriteRoad != null) && (ourPlayerData.getNumPieces(favoriteRoad.getType()) > 0) && (favoriteRoad.getScore() > 0) && ((favoriteSettlement == null) || (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) == 0) || (favoriteSettlement.getScore() < favoriteRoad.getScore()))) {
        D.ebugPrintln("### PICKED FAVORITE ROAD");
        // also represents SHIP here
        pick = SOCPlayingPiece.ROAD;
        pickScore = favoriteRoad.getScore();
    } else if ((favoriteSettlement != null) && (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) > 0)) {
        D.ebugPrintln("### PICKED FAVORITE SETTLEMENT");
        pick = SOCPlayingPiece.SETTLEMENT;
        pickScore = favoriteSettlement.getScore();
    }
    // /
    // / if buying a card is better than building...
    // /
    // 
    // see how buying a card improves our win game ETA
    // 
    float devCardScore = 0;
    if ((game.getNumDevCards() > 0) && !forSpecialBuildingPhase) {
        if ((brain != null) && (brain.getDRecorder().isOn())) {
            brain.getDRecorder().startRecording("DEVCARD");
            brain.getDRecorder().record("Estimate value of a dev card");
        }
        possibleCard = getDevCardScore(buildingETAs[SOCBuildingSpeedEstimate.CARD], leadersCurrentWGETA);
        devCardScore = possibleCard.getScore();
        D.ebugPrintln("### DEV CARD SCORE: " + devCardScore);
        if ((brain != null) && (brain.getDRecorder().isOn())) {
            brain.getDRecorder().stopRecording();
        }
        if ((pick == -1) || (devCardScore > pickScore)) {
            D.ebugPrintln("### BUY DEV CARD");
            pick = SOCPlayingPiece.MAXPLUSONE;
            pickScore = devCardScore;
        }
    }
    if (game.isGameOptionSet(SOCGameOption.K_SC_PIRI) || game.isGameOptionSet(SOCGameOption.K_SC_WOND)) {
        if (scenarioGameStrategyPlan(pickScore, devCardScore, true, (pick == SOCPlayingPiece.MAXPLUSONE), new SOCBuildingSpeedEstimate(ourPlayerData.getNumbers()), leadersCurrentWGETA, forSpecialBuildingPhase))
            // <--- Early return: Scenario-specific buildingPlan was pushed ---
            return;
    }
    // 
    switch(pick) {
        case SOCPlayingPiece.ROAD:
            D.ebugPrintln("$ PUSHING " + favoriteRoad);
            buildingPlan.push(favoriteRoad);
            break;
        case SOCPlayingPiece.SETTLEMENT:
            D.ebugPrintln("$ PUSHING " + favoriteSettlement);
            buildingPlan.push(favoriteSettlement);
            break;
        case SOCPlayingPiece.CITY:
            D.ebugPrintln("$ PUSHING " + favoriteCity);
            buildingPlan.push(favoriteCity);
            break;
        case SOCPlayingPiece.MAXPLUSONE:
            D.ebugPrintln("$ PUSHING " + possibleCard);
            buildingPlan.push(possibleCard);
            break;
    }
}
Also used : SOCBoard(soc.game.SOCBoard) ArrayList(java.util.ArrayList) List(java.util.List) Vector(java.util.Vector) SOCBoardLarge(soc.game.SOCBoardLarge) SOCCity(soc.game.SOCCity) SOCLRPathData(soc.game.SOCLRPathData)

Example 4 with SOCBoardLarge

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

the class SOCPlayerTracker method addOurNewSettlement.

/**
 * Add one of our settlements, and newly possible pieces from it.
 * Adds a new possible city; removes conflicting possible settlements (ours or other players).
 * On the large Sea board, if this is a coastal settlement adds newly possible ships, and if
 * we've just settled a new island, newly possible roads, because the coastal settlement is
 * a roads {@literal <->} ships transition.
 *<P>
 * Newly possible roads or ships next to the settlement are expanded by calling
 * {@link #expandRoadOrShip(SOCPossibleRoad, SOCPlayer, SOCPlayer, HashMap, int)}.
 * {@link #EXPAND_LEVEL} is the basic expansion length, and ships add
 * {@link #EXPAND_LEVEL_SHIP_EXTRA} to that for crossing the sea to nearby islands.
 *<P>
 * Called in 2 different conditions:
 *<UL>
 * <LI> To track an actual (not possible) settlement that's just been placed
 * <LI> To see the effects of trying to placing a possible settlement, in a copy of the PlayerTracker
 *      ({@link #tryPutPiece(SOCPlayingPiece, SOCGame, HashMap)})
 *</UL>
 *
 * @param settlement  the new settlement
 * @param trackers    player trackers for all of the players
 */
public synchronized void addOurNewSettlement(SOCSettlement settlement, HashMap<Integer, SOCPlayerTracker> trackers) {
    // D.ebugPrintln();
    D.ebugPrintln("$$$ addOurNewSettlement : " + settlement);
    SOCBoard board = game.getBoard();
    final Integer settlementCoords = Integer.valueOf(settlement.getCoordinates());
    /**
     * add a new possible city
     */
    possibleCities.put(settlementCoords, new SOCPossibleCity(player, settlement.getCoordinates()));
    /**
     * see if the new settlement was a possible settlement in
     * the list.  if so, remove it.
     */
    SOCPossibleSettlement ps = possibleSettlements.get(settlementCoords);
    if (ps != null) {
        D.ebugPrintln("$$$ was a possible settlement");
        /**
         * copy a list of all the conflicting settlements
         */
        List<SOCPossibleSettlement> conflicts = new ArrayList<SOCPossibleSettlement>(ps.getConflicts());
        /**
         * remove the possible settlement that is now a real settlement
         */
        D.ebugPrintln("$$$ removing " + Integer.toHexString(settlement.getCoordinates()));
        possibleSettlements.remove(settlementCoords);
        removeFromNecessaryRoads(ps);
        /**
         * remove possible settlements that this one cancels out
         */
        for (SOCPossibleSettlement conflict : conflicts) {
            D.ebugPrintln("$$$ checking conflict with " + conflict.getPlayer().getPlayerNumber() + ":" + Integer.toHexString(conflict.getCoordinates()));
            SOCPlayerTracker tracker = trackers.get(Integer.valueOf(conflict.getPlayer().getPlayerNumber()));
            if (tracker != null) {
                D.ebugPrintln("$$$ removing " + Integer.toHexString(conflict.getCoordinates()));
                tracker.getPossibleSettlements().remove(Integer.valueOf(conflict.getCoordinates()));
                removeFromNecessaryRoads(conflict);
                /**
                 * remove the conflicts that this settlement made
                 */
                for (SOCPossibleSettlement otherConflict : conflict.getConflicts()) {
                    D.ebugPrintln("$$$ removing conflict " + Integer.toHexString(conflict.getCoordinates()) + " from " + Integer.toHexString(otherConflict.getCoordinates()));
                    otherConflict.removeConflict(conflict);
                }
            }
        }
    } else {
        /**
         * if the new settlement wasn't a possible settlement,
         * we still need to cancel out other players possible settlements
         */
        D.ebugPrintln("$$$ wasn't possible settlement");
        ArrayList<SOCPossibleSettlement> trash = new ArrayList<SOCPossibleSettlement>();
        List<Integer> adjNodes = board.getAdjacentNodesToNode(settlement.getCoordinates());
        Iterator<SOCPlayerTracker> trackersIter = trackers.values().iterator();
        while (trackersIter.hasNext()) {
            SOCPlayerTracker tracker = trackersIter.next();
            SOCPossibleSettlement posSet = tracker.getPossibleSettlements().get(settlementCoords);
            D.ebugPrintln("$$$ tracker for player " + tracker.getPlayer().getPlayerNumber());
            /**
             * check the node that the settlement is on
             */
            D.ebugPrintln("$$$ checking node " + Integer.toHexString(settlement.getCoordinates()));
            if (posSet != null) {
                D.ebugPrintln("$$$ trashing " + Integer.toHexString(posSet.getCoordinates()));
                trash.add(posSet);
                /**
                 * remove the conflicts that this settlement made
                 */
                for (SOCPossibleSettlement conflict : posSet.getConflicts()) {
                    D.ebugPrintln("$$$ removing conflict " + Integer.toHexString(posSet.getCoordinates()) + " from " + Integer.toHexString(conflict.getCoordinates()));
                    conflict.removeConflict(posSet);
                }
            }
            /**
             * check adjacent nodes
             */
            for (Integer adjNode : adjNodes) {
                D.ebugPrintln("$$$ checking node " + Integer.toHexString(adjNode.intValue()));
                posSet = tracker.getPossibleSettlements().get(adjNode);
                if (posSet != null) {
                    D.ebugPrintln("$$$ trashing " + Integer.toHexString(posSet.getCoordinates()));
                    trash.add(posSet);
                    /**
                     * remove the conflicts that this settlement made
                     */
                    for (SOCPossibleSettlement conflict : posSet.getConflicts()) {
                        D.ebugPrintln("$$$ removing conflict " + Integer.toHexString(posSet.getCoordinates()) + " from " + Integer.toHexString(conflict.getCoordinates()));
                        conflict.removeConflict(posSet);
                    }
                }
            }
            /**
             * take out the trash
             * (no-longer-possible settlements, roads that support it)
             */
            D.ebugPrintln("$$$ removing trash for " + tracker.getPlayer().getPlayerNumber());
            for (SOCPossibleSettlement pset : trash) {
                D.ebugPrintln("$$$ removing " + Integer.toHexString(pset.getCoordinates()) + " owned by " + pset.getPlayer().getPlayerNumber());
                tracker.getPossibleSettlements().remove(Integer.valueOf(pset.getCoordinates()));
                removeFromNecessaryRoads(pset);
            }
            trash.clear();
        }
    }
    /**
     * Add possible road-ship transitions made possible by the new settlement.
     * Normally a new settlement placement doesn't need to add possible roads or ships,
     * because each road/ship placement adds possibles past the new far end of the route
     * in addOurNewRoadOrShip.
     */
    if (board instanceof SOCBoardLarge) {
        ArrayList<SOCPossibleRoad> roadsToExpand = null;
        /**
         * Only add new possible roads if we're on a new island
         * (that is, the newly placed settlement has no adjacent roads already).
         * Coastal ships/roads may still be added even if settleAlreadyHasRoad.
         */
        boolean settleAlreadyHasRoad = false;
        ArrayList<SOCPossibleRoad> possibleNewIslandRoads = null;
        final List<Integer> adjacEdges = board.getAdjacentEdgesToNode(settlementCoords);
        // First, loop to check for settleAlreadyHasRoad
        for (Integer edge : adjacEdges) {
            if (possibleRoads.get(edge) != null)
                // already a possible road or ship here
                continue;
            SOCRoad road = board.roadAtEdge(edge);
            if ((road != null) && road.isRoadNotShip()) {
                settleAlreadyHasRoad = true;
                break;
            }
        }
        // Now, possibly add new roads/ships/coastals
        for (Integer edge : adjacEdges) {
            // TODO remove these debug prints soon
            // System.err.println("L1348: examine edge 0x"
            // + Integer.toHexString(edge) + " for placed settle 0x"
            // + Integer.toHexString(settlementCoords));
            SOCPossibleRoad pRoad = possibleRoads.get(edge);
            if (pRoad != null) {
                // already a possible road or ship
                continue;
            }
            if (board.roadAtEdge(edge) != null) {
                // not new, something's already there
                continue;
            }
            if (player.isPotentialRoad(edge)) {
                // Add newly possible roads from settlement placement.
                // Probably won't need to happen (usually added in addOurNewRoadOrShip, see newPossibleRoads)
                // but could on a new island's first settlement
                final boolean isCoastline = player.isPotentialShip(edge);
                if (settleAlreadyHasRoad && !isCoastline)
                    continue;
                if (possibleNewIslandRoads == null)
                    possibleNewIslandRoads = new ArrayList<SOCPossibleRoad>();
                possibleNewIslandRoads.add((isCoastline) ? new SOCPossibleShip(player, edge, true, null) : new SOCPossibleRoad(player, edge, null));
                if (isCoastline)
                    System.err.println("L1675: " + toString() + ": new PossibleShip(true) at 0x" + Integer.toHexString(edge));
            } else if (player.isPotentialShip(edge)) {
                // A way out to a new island
                SOCPossibleShip newPS = new SOCPossibleShip(player, edge, false, null);
                possibleRoads.put(edge, newPS);
                System.err.println("L1685: " + toString() + ": new PossibleShip(false) at 0x" + Integer.toHexString(edge) + " from coastal settle 0x" + Integer.toHexString(settlementCoords));
                if (roadsToExpand == null)
                    roadsToExpand = new ArrayList<SOCPossibleRoad>();
                roadsToExpand.add(newPS);
                newPS.setExpandedFlag();
            }
        }
        if ((possibleNewIslandRoads != null) && !game.isInitialPlacement()) {
            // (Make sure this isn't initial placement, where nothing has adjacent roads)
            for (SOCPossibleRoad pr : possibleNewIslandRoads) {
                possibleRoads.put(Integer.valueOf(pr.getCoordinates()), pr);
                System.err.println("L1396: new possible road at edge 0x" + Integer.toHexString(pr.getCoordinates()) + " from coastal settle 0x" + Integer.toHexString(settlementCoords));
                if (roadsToExpand == null)
                    roadsToExpand = new ArrayList<SOCPossibleRoad>();
                roadsToExpand.add(pr);
                pr.setExpandedFlag();
            }
        }
        if (roadsToExpand != null) {
            // 
            // expand possible ships/roads that we've added
            // 
            SOCPlayer dummy = new SOCPlayer(player);
            for (SOCPossibleRoad expandPR : roadsToExpand) {
                final int expand = EXPAND_LEVEL + (expandPR.isRoadNotShip() ? 0 : EXPAND_LEVEL_SHIP_EXTRA);
                expandRoadOrShip(expandPR, player, dummy, trackers, expand);
            }
            dummy.destroyPlayer();
        }
    }
}
Also used : SOCBoardLarge(soc.game.SOCBoardLarge) SOCBoard(soc.game.SOCBoard) ArrayList(java.util.ArrayList) SOCRoad(soc.game.SOCRoad) SOCPlayer(soc.game.SOCPlayer)

Example 5 with SOCBoardLarge

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

the class SOCBoardPanel method drawBoard_SC_FTRI_placePort.

/**
 * Scenario game option {@link SOCGameOption#K_SC_FTRI _SC_FTRI}: In board mode {@link #SC_FTRI_PLACE_PORT},
 * draw the possible coastal edges where the port can be placed, and if the {@link #hilight} cursor is at
 * such an edge, draw the port semi-transparently and a solid hilight line at the edge.
 * @since 2.0.00
 */
private final void drawBoard_SC_FTRI_placePort(Graphics g) {
    drawSeaEdgeLines(g, Color.WHITE, player.getPortMovePotentialLocations(true));
    if (hilight == 0)
        return;
    // Draw the placing port semi-transparently if graphics support it.
    // Draw hilight line with some thickness if possible.
    int edge = hilight;
    if (edge == -1)
        edge = 0;
    final SOCInventoryItem portItem = game.getPlacingItem();
    if (portItem != null) {
        // draw the port; similar code to drawPorts_largeBoard
        final int landFacing = ((SOCBoardLarge) board).getPortFacingFromEdge(edge);
        final int landHexCoord = board.getAdjacentHexToEdge(edge, landFacing);
        int px = halfdeltaX * ((landHexCoord & 0xFF) - 1);
        int py = halfdeltaY * (landHexCoord >> 8);
        // now move 1 hex "backwards" from that hex's upper-left corner
        px -= DELTAX_FACING[landFacing];
        py -= DELTAY_FACING[landFacing];
        final Composite prevComposite;
        if (g instanceof Graphics2D) {
            prevComposite = ((Graphics2D) g).getComposite();
            ((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
        } else {
            prevComposite = null;
        }
        drawHex(g, px, py, -portItem.itype, landFacing, -1);
        if (prevComposite != null)
            ((Graphics2D) g).setComposite(prevComposite);
    }
    final Stroke prevStroke;
    if (g instanceof Graphics2D) {
        prevStroke = ((Graphics2D) g).getStroke();
        ((Graphics2D) g).setStroke(new BasicStroke(2.5f));
    } else {
        prevStroke = null;
    }
    g.setColor(Color.WHITE);
    drawSeaEdgeLine(g, edge);
    if (prevStroke != null)
        ((Graphics2D) g).setStroke(prevStroke);
}
Also used : BasicStroke(java.awt.BasicStroke) SOCBoardLarge(soc.game.SOCBoardLarge) SOCInventoryItem(soc.game.SOCInventoryItem) BasicStroke(java.awt.BasicStroke) Stroke(java.awt.Stroke) Composite(java.awt.Composite) AlphaComposite(java.awt.AlphaComposite) Graphics2D(java.awt.Graphics2D)

Aggregations

SOCBoardLarge (soc.game.SOCBoardLarge)19 SOCBoard (soc.game.SOCBoard)6 SOCPlayer (soc.game.SOCPlayer)6 SOCShip (soc.game.SOCShip)6 SOCGame (soc.game.SOCGame)5 ArrayList (java.util.ArrayList)4 SOCRoad (soc.game.SOCRoad)4 Graphics2D (java.awt.Graphics2D)3 SOCCity (soc.game.SOCCity)3 SOCFortress (soc.game.SOCFortress)3 SOCVillage (soc.game.SOCVillage)3 Color (java.awt.Color)2 HashSet (java.util.HashSet)2 Vector (java.util.Vector)2 SOCInventoryItem (soc.game.SOCInventoryItem)2 SOCResourceSet (soc.game.SOCResourceSet)2 SOCSettlement (soc.game.SOCSettlement)2 AlphaComposite (java.awt.AlphaComposite)1 BasicStroke (java.awt.BasicStroke)1 Composite (java.awt.Composite)1