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();
}
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;
}
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;
}
}
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();
}
}
}
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);
}
Aggregations