soc.robot
Class SOCRobotBrain

java.lang.Object
  extended by java.lang.Thread
      extended by soc.robot.SOCRobotBrain
All Implemented Interfaces:
java.lang.Runnable

public class SOCRobotBrain
extends java.lang.Thread

AI for playing Settlers of Catan. Represents a robot player within 1 game. The bot is a separate thread, so everything happens in run() or a method called from there.

Some robot behaviors are altered by the SOCRobotParameters passed into our constructor. Some decision-making code is in the OpeningBuildStrategy, RobberStrategy, MonopolyStrategy, etc classes. Data and predictions about the other players in the game is in SOCPlayerTracker. If we're trading with other players for resources, some details of that are in SOCRobotNegotiator. All these, and data on the game and players, are initialized in setOurPlayerData().

At the start of each player's turn, buildingPlan and most other state fields are cleared (search run() for mesType == SOCMessage.TURN). The plan for what to build next is decided in SOCRobotDM.planStuff(int) (called from planBuilding() and some other places) which updates buildingPlan. That plan is executed in buildOrGetResourceByTradeOrCard().

Current status and the next expected action are tracked by the "waitingFor" and "expect" flag fields. If we've sent the server an action and we're waiting for the result, waitingForGameState is true along with one other "expect" flag, such as expectPLACING_ROBBER. All these fields can be output for inspection by calling debugPrintBrainStatus().

See run() for more details of how the bot waits for and reacts to incoming messages. Some robot actions wait for other players or other timeouts; the brain counts SOCTimingPing messages (1 per second) for timing. For robustness testing, the SOCRobotClient.debugRandomPause flag can be used to inject random delays in incoming messages.

To keep the game moving, the server may force an inactive bot to end its turn; see SOCForceEndTurnThread.

Author:
Robert S Thomas

Nested Class Summary
 
Nested classes/interfaces inherited from class java.lang.Thread
java.lang.Thread.State, java.lang.Thread.UncaughtExceptionHandler
 
Field Summary
protected  boolean alive
          Flag for whether or not we're alive
protected  java.util.Stack<SOCPossiblePiece> buildingPlan
          This is our current building plan, a stack of SOCPossiblePiece.
protected  SOCRobotClient client
          The client we are hooked up to
protected  int counter
          A counter used to measure passage of time.
protected  int currentDRecorder
          keeps track of which dRecorder is current
protected  int curState
          Our current state
private  boolean decidedIfSpecialBuild
          During this turn, which is another player's turn, have we yet decided whether to do the Special Building phase (for the 6-player board)?
protected  SOCRobotDM decisionMaker
          the thing that determines what we want to build next
protected  boolean doneTrading
          true if we're done trading
protected  DebugRecorder[] dRecorder
          an object for recording debug information that can be accessed interactively
protected  SOCPlayer dummyCancelPlayerData
          Dummy player for cancelling bad placements
protected  boolean expectDICERESULT
          true if we're expecting a DICERESULT message
protected  boolean expectDISCARD
          true if we're expecting a DISCARDREQUEST message
protected  boolean expectMOVEROBBER
          true if we're expecting to have to move the robber
protected  boolean expectPLACING_CITY
          true if we're expecting the PLACING_CITY state
protected  boolean expectPLACING_FREE_ROAD1
          true if we're expecting the PLACING_FREE_ROAD1 state
protected  boolean expectPLACING_FREE_ROAD2
          true if we're expecting the PLACING_FREE_ROAD2 state
protected  boolean expectPLACING_ROAD
          true if we're expecting the PLACING_ROAD state
protected  boolean expectPLACING_ROBBER
          True if we're expecting the PLACING_ROBBER state.
protected  boolean expectPLACING_SETTLEMENT
          true if we're expecting the PLACING_SETTLEMENT state
protected  boolean expectPLACING_SHIP
          true if we're expecting the PLACING_SHIP game state
protected  boolean expectPLAY
          true if we're expecting the PLAY state
protected  boolean expectPLAY1
          true if we're expecting the PLAY1 state
protected  boolean expectPUTPIECE_FROM_START1A
          true if were expecting a PUTPIECE message after a START1A game state
protected  boolean expectPUTPIECE_FROM_START1B
          true if were expecting a PUTPIECE message after a START1B game state
protected  boolean expectPUTPIECE_FROM_START2A
          true if were expecting a PUTPIECE message after a START1A game state
protected  boolean expectPUTPIECE_FROM_START2B
          true if were expecting a PUTPIECE message after a START1A game state
protected  boolean expectPUTPIECE_FROM_START3A
          true if were expecting a PUTPIECE message after a START3A game state.
protected  boolean expectPUTPIECE_FROM_START3B
          true if were expecting a PUTPIECE message after a START3B game state.
protected  boolean expectSTART1A
          true if we're expecting the START1A state
protected  boolean expectSTART1B
          true if we're expecting the START1B state
protected  boolean expectSTART2A
          true if we're expecting the START2A state
protected  boolean expectSTART2B
          true if we're expecting the START2B state
protected  boolean expectSTART3A
          true if we're expecting the START3A state.
protected  boolean expectSTART3B
          true if we're expecting the START3B state.
protected  boolean expectWAITING_FOR_DISCOVERY
          true if we're expecting to pick two resources
protected  boolean expectWAITING_FOR_MONOPOLY
          true if we're expecting to pick a monopoly
protected  int failedBuildingAttempts
          Track how many illegal placement requests we've made this turn.
protected  SOCGame game
          The game we are playing
protected  CappedQueue<SOCMessage> gameEventQ
          The queue of game messages; contents are SOCMessage.
private  boolean gameIs6Player
          The game we're playing is on the 6-player board.
protected  SOCPossiblePiece lastMove
          keeps track of the last thing we bought, for debugging purposes
private  int lastStartingPieceCoord
          During START states, coordinate of our most recently placed road or settlement.
private  int lastStartingRoadTowardsNode
          During START1B and START2B states, coordinate of the potential settlement node towards which we're building, as calculated by OpeningBuildStrategy.planInitRoad().
protected  SOCPossiblePiece lastTarget
          keeps track of the last thing we wanted, for debugging purposes
static int MAX_DENIED_BUILDING_PER_TURN
          If, during a turn, we make this many illegal build requests that the server denies, stop trying.
private  MonopolyStrategy monopolyStrategy
          Strategy to choose whether to monopolize, and which resource.
protected  boolean moveRobberOnSeven
          True when the robber will move because a seven was rolled.
protected  SOCRobotNegotiator negotiator
          The data and code that determines how we negotiate.
protected  boolean[] offerRejections
          true if the player with that player number has rejected our offer
protected  int oldGameState
          the game state before the current one
private  OpeningBuildStrategy openingBuildStrategy
          Strategy to plan and build initial settlements and roads.
protected  SOCPlayer ourPlayerData
          Our player data Set in setOurPlayerData()
private  int ourPlayerNumber
          Our player number; set in setOurPlayerData().
protected  SOCPlayerTracker ourPlayerTracker
          our player tracker
protected  boolean ourTurn
          Flag for whether or not it is our turn
private  boolean pauseFaster
          Pause for less time; speeds up response in 6-player games.
protected  SOCRobotPinger pinger
          a thread that sends ping messages to this one
protected  java.util.HashMap<java.lang.Integer,SOCPlayerTracker> playerTrackers
          trackers for all players (one per player, including this robot)
protected  java.util.Random rand
          Random number generator
private  int rejectedPlayDevCardType
          If set, the server rejected our play of this dev card type this turn (such as SOCDevCardConstants.KNIGHT) because of a bug in our robot; should not attempt to play the same type again this turn.
protected  SOCResourceSet resourceChoices
          these are the two resources that we want when we play a discovery dev card
(package private)  SOCRobotParameters robotParameters
          The robot parameters
private  java.util.Vector<SOCMessage> turnEventsCurrent
          The game messages received this turn / previous turn, for debugging.
private  java.util.Vector<SOCMessage> turnEventsPrev
          The game messages received this turn / previous turn, for debugging.
private  int turnExceptionCount
          Number of exceptions caught this turn, if any.
protected  int turnTime
          Timer for turn taking
protected  boolean waitingForDevCard
          true when we're waiting to receive a dev card
protected  boolean waitingForGameState
          true if we're waiting for a GAMESTATE message from the server.
protected  boolean waitingForOurTurn
          true if we're waiting for a TURN message from the server when it's our turn
protected  java.lang.String waitingForPickSpecialItem
          Non-null if we're waiting for server response to picking a SOCSpecialItem, for certain scenarios; contains the typeKey of the special item we're waiting on.
protected  boolean waitingForSC_PIRI_FortressRequest
          True if we're in a _SC_PIRI game and waiting for server response to a SOCSimpleRequest to attack a pirate fortress.
private  boolean waitingForSpecialBuild
          true when we're waiting for our requested Special Building phase (for the 6-player board).
protected  boolean waitingForTradeMsg
          true when we're waiting for the results of a trade
protected  boolean waitingForTradeResponse
          true if we're waiting for a response to our trade message
protected  SOCPlayingPiece whatWeFailedToBuild
          This is what we tried building this turn, but the server said it was an illegal move (due to a bug in our robot).
protected  SOCPlayingPiece whatWeWantToBuild
          This is the piece we want to build now.
 
Fields inherited from class java.lang.Thread
MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY
 
Constructor Summary
SOCRobotBrain(SOCRobotClient rc, SOCRobotParameters params, SOCGame ga, CappedQueue<SOCMessage> mq)
          Create a robot brain to play a game.
 
Method Summary
 void addPlayerTracker(int pn)
          A player has sat down and been added to the game, during game formation.
private  void buildOrGetResourceByTradeOrCard()
          Either ask to build a planned piece, or use trading or development cards to get resources to build it.
private  void buildRequestPlannedPiece()
          Have the client ask to build our top planned piece buildingPlan.pop(), unless we've already been told by the server to not build it.
protected  void cancelWrongPiecePlacement(SOCCancelBuildRequest mes)
          We've asked for an illegal piece placement.
protected  void cancelWrongPiecePlacementLocal(SOCPlayingPiece cancelPiece)
          Remove our incorrect piece placement, it's been rejected by the server.
protected  boolean chooseFreeResources(SOCResourceSet targetResources, int numChoose, boolean clearResChoices)
          Choose the resources we need most, for playing a Discovery development card or when a Gold Hex number is rolled.
private  boolean chooseFreeResourcesIfNeeded(SOCResourceSet targetResources, int numChoose, boolean chooseIfNotNeeded)
          Do we need to acquire at least numChoose resources to build our next piece? Choose the resources we need most; used when we want to play a discovery development card or when a Gold Hex number is rolled.
protected  int considerOffer(SOCTradeOffer offer)
          Consider a trade offer made by another player.
private  void considerPlayKnightCard()
          If we haven't played a dev card yet this turn, and we have a knight, and we can get largest army, play the knight.
private  boolean considerScenarioTurnFinalActions()
          Look for and take any scenario-specific final actions before ending the turn.
private  void debugInfo()
          this is for debugging
 java.util.List<java.lang.String> debugPrintBrainStatus()
          Print brain variables and status for this game to a list of Strings.
private static void debugPrintTurnMessages(java.util.Vector<?> msgV, java.lang.String msgDesc, java.util.List<java.lang.String> toList)
          Add the contents of this Vector as Strings to the provided list.
protected  void expandTradeTreeNode(SOCTradeTree currentTreeNode, java.util.Hashtable<SOCResourceSet,SOCTradeTree> table)
          expand a trade tree node
 java.util.Stack<SOCPossiblePiece> getBuildingPlan()
           
 SOCRobotClient getClient()
           
 SOCRobotDM getDecisionMaker()
           
 DebugRecorder getDRecorder()
           
 SOCGame getGame()
           
 SOCPossiblePiece getLastMove()
           
 SOCPossiblePiece getLastTarget()
           
 DebugRecorder getOldDRecorder()
           
 SOCPlayer getOurPlayerData()
           
 SOCPlayerTracker getOurPlayerTracker()
           
 java.util.HashMap<java.lang.Integer,SOCPlayerTracker> getPlayerTrackers()
           
 SOCRobotParameters getRobotParameters()
           
private  void handleCANCELBUILDREQUEST(SOCCancelBuildRequest mes)
          Handle a CANCELBUILDREQUEST for this game.
private  void handleDEVCARDACTION(SOCDevCardAction mes)
          Handle a DEVCARDACTION for this game.
private  void handleMAKEOFFER(SOCMakeOffer mes)
          Handle a MAKEOFFER for this game.
protected  void handlePLAYERELEMENT_numRsrc(SOCPlayerElement mes, SOCPlayer pl, int rtype, java.lang.String rtypeStr)
          Update a player's amount of a resource.
private  void handlePLAYERELEMENT(SOCPlayerElement mes)
          Handle a PLAYERELEMENT for this game.
private  void handlePUTPIECE_updateGameData(SOCPutPiece mes)
          Handle a PUTPIECE for this game, by updating game data.
private  void handlePUTPIECE_updateTrackers(int pn, int coord, int pieceType)
          Handle a PUTPIECE for this game, by updating SOCPlayerTrackers.
private  void handleREJECTOFFER(SOCRejectOffer mes)
          Handle a REJECTOFFER for this game.
 void kill()
          kill this brain
protected  boolean makeCounterOffer(SOCTradeOffer offer)
          make a counter offer to another player
protected  boolean makeOffer(SOCPossiblePiece target)
          Make a trade offer to another player, or decide to make no offer.
protected  void moveRobber()
          move the robber
 void pause(int msec)
          pause for a bit.
protected  void pickFreeResources(int numChoose)
          Respond to server's request to pick resources to gain from the Gold Hex.
protected  void placeFirstSettlement(int firstSettlement)
          place planned first settlement
private  void placeIfExpectPlacing()
          If it's our turn and we have an expect flag set (such as expectPLACING_SETTLEMENT), then call client.putPiece (game, whatWeWantToBuild).
protected  void placeInitSettlement(int initSettlement)
          Place planned initial settlement after first one.
protected  void planAndPlaceInitRoad()
          Plan and place a road attached to our most recently placed initial settlement, in game states START1B, START2B, START3B.
private  void planBuilding()
          Plan the next building plan and target.
private  void playKnightCard()
          Play a Knight card.
private  void printResources()
          For each player in game: client.sendText, and debug-print to console, game.getPlayer(i).getResources()
private  void resetFieldsAtEndTurn()
          Bot is ending its turn; reset state control fields to act during other players' turns.
private  void rollOrPlayKnightOrExpectDice()
          On our turn, ask client to roll dice or play a knight; on other turns, update flags to expect dice result.
 void run()
          Here is the run method.
protected  int scoreTradeOutcome(SOCResourceSet tradeOutcome)
          evaluate a trade outcome by calculating how much you could build with it
 void setOurPlayerData()
          When we join a game and sit down to begin play, find our player data using our nickname.
private  void trackNewCity(SOCCity newCity, boolean isCancel)
          Run a newly placed city through the PlayerTrackers.
protected  void trackNewRoadOrShip(SOCRoad newRoad, boolean isCancel)
          Run a newly placed road or ship through the playerTrackers.
protected  void trackNewSettlement(SOCSettlement newSettlement, boolean isCancel)
          Run a newly placed settlement through the playerTrackers.
private  void tradeStopWaitingClearOffer()
          Stop waiting for responses to a trade offer.
protected  void tradeStuff()
          do some trading -- this method is obsolete and not called.
protected  boolean tradeToTarget2(SOCResourceSet targetResources)
          Make bank trades or port trades to get the target resources, if possible.
 void turnOffDRecorder()
          turns the debug recorders off
 void turnOnDRecorder()
          turns the debug recorders on
 
Methods inherited from class java.lang.Thread
activeCount, checkAccess, clone, countStackFrames, currentThread, destroy, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getId, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, join, join, join, resume, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, sleep, start, stop, stop, suspend, toString, yield
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

robotParameters

SOCRobotParameters robotParameters
The robot parameters


alive

protected boolean alive
Flag for whether or not we're alive


ourTurn

protected boolean ourTurn
Flag for whether or not it is our turn


turnTime

protected int turnTime
Timer for turn taking


pauseFaster

private boolean pauseFaster
Pause for less time; speeds up response in 6-player games. Ignored if SOCGame.isBotsOnly, which pauses for even less time.

Since:
1.1.09

curState

protected int curState
Our current state


rand

protected java.util.Random rand
Random number generator


client

protected SOCRobotClient client
The client we are hooked up to


game

protected SOCGame game
The game we are playing


gameIs6Player

private final boolean gameIs6Player
The game we're playing is on the 6-player board.

Since:
1.1.08

ourPlayerData

protected SOCPlayer ourPlayerData
Our player data Set in setOurPlayerData()


ourPlayerNumber

private int ourPlayerNumber
Our player number; set in setOurPlayerData().

Since:
2.0.00

dummyCancelPlayerData

protected SOCPlayer dummyCancelPlayerData
Dummy player for cancelling bad placements


gameEventQ

protected CappedQueue<SOCMessage> gameEventQ
The queue of game messages; contents are SOCMessage.


turnEventsCurrent

private java.util.Vector<SOCMessage> turnEventsCurrent
The game messages received this turn / previous turn, for debugging.

Since:
1.1.13

turnEventsPrev

private java.util.Vector<SOCMessage> turnEventsPrev
The game messages received this turn / previous turn, for debugging.

Since:
1.1.13

turnExceptionCount

private int turnExceptionCount
Number of exceptions caught this turn, if any. Resets at each player's turn during TURN message.

Since:
1.1.20

counter

protected int counter
A counter used to measure passage of time. Incremented each second, when the server sends SOCTimingPing. When we decide to take an action, resets to 0. If counter gets too high, we assume a bug and leave the game (alive = false).


decidedIfSpecialBuild

private boolean decidedIfSpecialBuild
During this turn, which is another player's turn, have we yet decided whether to do the Special Building phase (for the 6-player board)?

Since:
1.1.08

waitingForSpecialBuild

private boolean waitingForSpecialBuild
true when we're waiting for our requested Special Building phase (for the 6-player board).

Since:
1.1.08

whatWeWantToBuild

protected SOCPlayingPiece whatWeWantToBuild
This is the piece we want to build now. Set in buildOrGetResourceByTradeOrCard() from buildingPlan, used in placeIfExpectPlacing().

See Also:
whatWeFailedToBuild

buildingPlan

protected java.util.Stack<SOCPossiblePiece> buildingPlan
This is our current building plan, a stack of SOCPossiblePiece.

Cleared at the start of each player's turn, and a few other places if certain conditions arise. Set in planBuilding(). When making a buildingPlan, be sure to also set negotiator's target piece.

SOCRobotDM.buildingPlan is the same Stack.

See Also:
whatWeWantToBuild

whatWeFailedToBuild

protected SOCPlayingPiece whatWeFailedToBuild
This is what we tried building this turn, but the server said it was an illegal move (due to a bug in our robot).

See Also:
whatWeWantToBuild, failedBuildingAttempts

failedBuildingAttempts

protected int failedBuildingAttempts
Track how many illegal placement requests we've made this turn. Avoid infinite turn length, by preventing robot from alternately choosing two wrong things when the server denies a bad build.

See Also:
whatWeFailedToBuild, MAX_DENIED_BUILDING_PER_TURN

MAX_DENIED_BUILDING_PER_TURN

public static int MAX_DENIED_BUILDING_PER_TURN
If, during a turn, we make this many illegal build requests that the server denies, stop trying.

See Also:
failedBuildingAttempts

resourceChoices

protected SOCResourceSet resourceChoices
these are the two resources that we want when we play a discovery dev card


ourPlayerTracker

protected SOCPlayerTracker ourPlayerTracker
our player tracker


playerTrackers

protected java.util.HashMap<java.lang.Integer,SOCPlayerTracker> playerTrackers
trackers for all players (one per player, including this robot)


decisionMaker

protected SOCRobotDM decisionMaker
the thing that determines what we want to build next


negotiator

protected SOCRobotNegotiator negotiator
The data and code that determines how we negotiate. SOCRobotNegotiator.setTargetPiece(int, SOCPossiblePiece) is set when buildingPlan is updated.

See Also:
tradeToTarget2(SOCResourceSet), makeOffer(SOCPossiblePiece), considerOffer(SOCTradeOffer), tradeStopWaitingClearOffer()

expectSTART1A

protected boolean expectSTART1A
true if we're expecting the START1A state


expectSTART1B

protected boolean expectSTART1B
true if we're expecting the START1B state


expectSTART2A

protected boolean expectSTART2A
true if we're expecting the START2A state


expectSTART2B

protected boolean expectSTART2B
true if we're expecting the START2B state


expectSTART3A

protected boolean expectSTART3A
true if we're expecting the START3A state.

Since:
2.0.00

expectSTART3B

protected boolean expectSTART3B
true if we're expecting the START3B state.

Since:
2.0.00

expectPLAY

protected boolean expectPLAY
true if we're expecting the PLAY state


expectPLAY1

protected boolean expectPLAY1
true if we're expecting the PLAY1 state


expectPLACING_ROAD

protected boolean expectPLACING_ROAD
true if we're expecting the PLACING_ROAD state


expectPLACING_SETTLEMENT

protected boolean expectPLACING_SETTLEMENT
true if we're expecting the PLACING_SETTLEMENT state


expectPLACING_CITY

protected boolean expectPLACING_CITY
true if we're expecting the PLACING_CITY state


expectPLACING_SHIP

protected boolean expectPLACING_SHIP
true if we're expecting the PLACING_SHIP game state

Since:
2.0.00

expectPLACING_ROBBER

protected boolean expectPLACING_ROBBER
True if we're expecting the PLACING_ROBBER state. playKnightCard() sets this field and waitingForGameState.

In scenario SC_PIRI, this flag is also used when we've just played a "Convert to Warship" card (Knight/Soldier card) and we're waiting for the server response. The response won't be a GAMESTATE(PLACING_SOLDIER) message, it will either be PLAYERLEMENT(GAIN, SCENARIO_WARSHIP_COUNT) or DEVCARDACTION(CANNOT_PLAY). Since this situation is otherwise the same as playing a Knight/Soldier, we use this same waiting flags.


expectPLACING_FREE_ROAD1

protected boolean expectPLACING_FREE_ROAD1
true if we're expecting the PLACING_FREE_ROAD1 state


expectPLACING_FREE_ROAD2

protected boolean expectPLACING_FREE_ROAD2
true if we're expecting the PLACING_FREE_ROAD2 state


expectPUTPIECE_FROM_START1A

protected boolean expectPUTPIECE_FROM_START1A
true if were expecting a PUTPIECE message after a START1A game state


expectPUTPIECE_FROM_START1B

protected boolean expectPUTPIECE_FROM_START1B
true if were expecting a PUTPIECE message after a START1B game state


expectPUTPIECE_FROM_START2A

protected boolean expectPUTPIECE_FROM_START2A
true if were expecting a PUTPIECE message after a START1A game state


expectPUTPIECE_FROM_START2B

protected boolean expectPUTPIECE_FROM_START2B
true if were expecting a PUTPIECE message after a START1A game state


expectPUTPIECE_FROM_START3A

protected boolean expectPUTPIECE_FROM_START3A
true if were expecting a PUTPIECE message after a START3A game state.

Since:
2.0.00

expectPUTPIECE_FROM_START3B

protected boolean expectPUTPIECE_FROM_START3B
true if were expecting a PUTPIECE message after a START3B game state.

Since:
2.0.00

expectDICERESULT

protected boolean expectDICERESULT
true if we're expecting a DICERESULT message


expectDISCARD

protected boolean expectDISCARD
true if we're expecting a DISCARDREQUEST message


expectMOVEROBBER

protected boolean expectMOVEROBBER
true if we're expecting to have to move the robber


expectWAITING_FOR_DISCOVERY

protected boolean expectWAITING_FOR_DISCOVERY
true if we're expecting to pick two resources


expectWAITING_FOR_MONOPOLY

protected boolean expectWAITING_FOR_MONOPOLY
true if we're expecting to pick a monopoly


waitingForGameState

protected boolean waitingForGameState
true if we're waiting for a GAMESTATE message from the server. This is set after a robot action or requested action is sent to server, or just before ending our turn (which also sets waitingForOurTurn == true).

For example, when playing a SOCDevCardAction, set true and also set an "expect" flag (expectPLACING_ROBBER, expectWAITING_FOR_DISCOVERY, etc).

Special case:
In scenario SC_PIRI, this flag is also set when we've just played a "Convert to Warship" card (Knight/Soldier card), although the server won't respond with a GAMESTATE message; see expectPLACING_ROBBER javadoc.

See Also:
rejectedPlayDevCardType

waitingForOurTurn

protected boolean waitingForOurTurn
true if we're waiting for a TURN message from the server when it's our turn


waitingForTradeMsg

protected boolean waitingForTradeMsg
true when we're waiting for the results of a trade


waitingForDevCard

protected boolean waitingForDevCard
true when we're waiting to receive a dev card


moveRobberOnSeven

protected boolean moveRobberOnSeven
True when the robber will move because a seven was rolled. Used to help bot remember why the robber is moving (Knight dev card, or 7). Set true when SOCMessage.DICERESULT received. Read in gamestate PLACING_ROBBER.


waitingForTradeResponse

protected boolean waitingForTradeResponse
true if we're waiting for a response to our trade message


waitingForPickSpecialItem

protected java.lang.String waitingForPickSpecialItem
Non-null if we're waiting for server response to picking a SOCSpecialItem, for certain scenarios; contains the typeKey of the special item we're waiting on.


waitingForSC_PIRI_FortressRequest

protected boolean waitingForSC_PIRI_FortressRequest
True if we're in a _SC_PIRI game and waiting for server response to a SOCSimpleRequest to attack a pirate fortress.


doneTrading

protected boolean doneTrading
true if we're done trading


offerRejections

protected boolean[] offerRejections
true if the player with that player number has rejected our offer


rejectedPlayDevCardType

private int rejectedPlayDevCardType
If set, the server rejected our play of this dev card type this turn (such as SOCDevCardConstants.KNIGHT) because of a bug in our robot; should not attempt to play the same type again this turn. Otherwise -1.

Since:
1.1.17

oldGameState

protected int oldGameState
the game state before the current one


lastStartingPieceCoord

private int lastStartingPieceCoord
During START states, coordinate of our most recently placed road or settlement. Used to avoid repeats in cancelWrongPiecePlacement(SOCCancelBuildRequest).

Since:
1.1.09

lastStartingRoadTowardsNode

private int lastStartingRoadTowardsNode
During START1B and START2B states, coordinate of the potential settlement node towards which we're building, as calculated by OpeningBuildStrategy.planInitRoad(). Used to avoid repeats in cancelWrongPiecePlacementLocal(SOCPlayingPiece).

Since:
1.1.09

openingBuildStrategy

private OpeningBuildStrategy openingBuildStrategy
Strategy to plan and build initial settlements and roads. Set in setOurPlayerData().

Since:
2.0.00

monopolyStrategy

private MonopolyStrategy monopolyStrategy
Strategy to choose whether to monopolize, and which resource. Set in setOurPlayerData().

Since:
2.0.00

pinger

protected SOCRobotPinger pinger
a thread that sends ping messages to this one


dRecorder

protected DebugRecorder[] dRecorder
an object for recording debug information that can be accessed interactively


currentDRecorder

protected int currentDRecorder
keeps track of which dRecorder is current


lastMove

protected SOCPossiblePiece lastMove
keeps track of the last thing we bought, for debugging purposes


lastTarget

protected SOCPossiblePiece lastTarget
keeps track of the last thing we wanted, for debugging purposes

Constructor Detail

SOCRobotBrain

public SOCRobotBrain(SOCRobotClient rc,
                     SOCRobotParameters params,
                     SOCGame ga,
                     CappedQueue<SOCMessage> mq)
Create a robot brain to play a game.

Depending on game options, constructor might copy and alter the robot parameters (for example, to clear SOCRobotParameters.getTradeFlag()).

Please call setOurPlayerData() before using this brain or starting its thread.

Parameters:
rc - the robot client
params - the robot parameters
ga - the game we're playing
mq - the message queue
Method Detail

getRobotParameters

public SOCRobotParameters getRobotParameters()
Returns:
the robot parameters

getClient

public SOCRobotClient getClient()
Returns:
the player client

getPlayerTrackers

public java.util.HashMap<java.lang.Integer,SOCPlayerTracker> getPlayerTrackers()
Returns:
the player trackers (one per player, including this robot)

getOurPlayerTracker

public SOCPlayerTracker getOurPlayerTracker()
Returns:
our player tracker

addPlayerTracker

public void addPlayerTracker(int pn)
A player has sat down and been added to the game, during game formation. Create a PlayerTracker for them.

Called when SITDOWN received from server; one SITDOWN is sent for every player, and our robot player might not be the first or last SITDOWN.

Since our playerTrackers are initialized when our robot's SITDOWN is received (robotclient calls setOurPlayerData()), and seats may be vacant at that time (because SITDOWN not yet received for those seats), we must add a PlayerTracker for each SITDOWN received after our player's.

Parameters:
pn - Player number

getGame

public SOCGame getGame()
Returns:
the game data

getOurPlayerData

public SOCPlayer getOurPlayerData()
Returns:
our player data

getBuildingPlan

public java.util.Stack<SOCPossiblePiece> getBuildingPlan()
Returns:
the building plan, a stack of SOCPossiblePiece

getDecisionMaker

public SOCRobotDM getDecisionMaker()
Returns:
the decision maker

turnOnDRecorder

public void turnOnDRecorder()
turns the debug recorders on


turnOffDRecorder

public void turnOffDRecorder()
turns the debug recorders off


getDRecorder

public DebugRecorder getDRecorder()
Returns:
the debug recorder

getOldDRecorder

public DebugRecorder getOldDRecorder()
Returns:
the old debug recorder

getLastMove

public SOCPossiblePiece getLastMove()
Returns:
the last move we made

getLastTarget

public SOCPossiblePiece getLastTarget()
Returns:
our last target piece

setOurPlayerData

public void setOurPlayerData()
When we join a game and sit down to begin play, find our player data using our nickname. Called from SOCRobotClient when the server sends a SOCSitDown message. Initializes our game and player data, SOCRobotDM, SOCRobotNegotiator, strategy fields, SOCPlayerTrackers, etc.


debugPrintBrainStatus

public java.util.List<java.lang.String> debugPrintBrainStatus()
Print brain variables and status for this game to a list of Strings. Includes all of the expect and waitingFor fields (expectPLAY, waitingForGameState, etc.) Also prints the game state, and the messages received by this brain during the previous and current turns.

Before v1.1.20, this printed to System.err instead of returning the status as Strings.

Since:
1.1.13

debugPrintTurnMessages

private static void debugPrintTurnMessages(java.util.Vector<?> msgV,
                                           java.lang.String msgDesc,
                                           java.util.List<java.lang.String> toList)
Add the contents of this Vector as Strings to the provided list. One element per line, indented by \t. Headed by a line formatted as one of:
Current turn: No messages received.
Current turn: 5 messages received:

Parameters:
msgV - Vector of SOCMessages from server
msgDesc - Short description of the vector, like 'previous' or 'current'
toList - Add to this list
Since:
1.1.13

run

public void run()
Here is the run method. Just keep receiving game events through gameEventQ and deal with each one. Remember that we're sent a SOCTimingPing event once per second, incrementing counter. That allows the bot to wait a certain time for other players before it decides whether to do something.

Nearly all bot actions start in this method; the overview of bot structures is in the class javadoc for prominence. See comments within run() for minor details.

Specified by:
run in interface java.lang.Runnable
Overrides:
run in class java.lang.Thread

resetFieldsAtEndTurn

private final void resetFieldsAtEndTurn()
Bot is ending its turn; reset state control fields to act during other players' turns.

Does not call SOCDisplaylessPlayerClient.endTurn(SOCGame).

Since:
2.0.00

considerScenarioTurnFinalActions

private boolean considerScenarioTurnFinalActions()
Look for and take any scenario-specific final actions before ending the turn.

For example, _SC_PIRI will check if we've reached the fortress and have 5 or more warships, and if so will attack the fortress. Doing so ends the turn, so we don't try to attack before end of turn.

NOTE: For now this method assumes it's called only in the SC_PIRI scenario. Caller must check the game for any relevant scenario SOCGameOptions before calling.

Returns:
true if an action was taken and turn shouldn't be ended yet, false otherwise
Since:
2.0.00

tradeStopWaitingClearOffer

private void tradeStopWaitingClearOffer()
Stop waiting for responses to a trade offer. Remember other players' responses, Call client.clearOffer, clear waitingForTradeResponse and counter.

Since:
1.1.09

considerPlayKnightCard

private void considerPlayKnightCard()
If we haven't played a dev card yet this turn, and we have a knight, and we can get largest army, play the knight. Must be our turn and gameState PLAY1. ourPlayerData.hasPlayedDevCard() must be false.

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 we call playKnightCard(), it sets the flags expectPLACING_ROBBER and waitingForGameState.

Since:
2.0.00
See Also:
rollOrPlayKnightOrExpectDice()

placeIfExpectPlacing

private void placeIfExpectPlacing()
If it's our turn and we have an expect flag set (such as expectPLACING_SETTLEMENT), then call client.putPiece (game, whatWeWantToBuild).

Looks for one of these game states:

Since:
1.1.09

playKnightCard

private void playKnightCard()
Play a Knight card. In scenario _SC_PIRI, play a "Convert to Warship" card. Sets expectPLACING_ROBBER, waitingForGameState. Calls client.playDevCard(KNIGHT).

In scenario _SC_PIRI, the server response messages are different, but we still use those two flag fields; see expectPLACING_ROBBER javadoc.

Since:
2.0.00

rollOrPlayKnightOrExpectDice

private void rollOrPlayKnightOrExpectDice()
On our turn, ask client to roll dice or play a knight; on other turns, update flags to expect dice result.

Call when gameState SOCGame.PLAY && ! waitingForGameState.

Clears expectPLAY to false. Sets either expectDICERESULT, or expectPLACING_ROBBER and waitingForGameState.

In scenario _SC_PIRI, don't play a Knight card before dice roll, because the scenario has no robber: Playing before the roll won't un-block any of our resource hexes, and it might put us over 7 resources.

Since:
1.1.08
See Also:
considerPlayKnightCard()

buildOrGetResourceByTradeOrCard

private void buildOrGetResourceByTradeOrCard()
                                      throws java.lang.IllegalStateException
Either ask to build a planned piece, or use trading or development cards to get resources to build it. Examines buildingPlan for the next piece wanted. Sets whatWeWantToBuild by calling buildRequestPlannedPiece() or using a Road Building dev card.

If we need resources and we can't get them through the robber, the Road Building or Monopoly or Discovery development cards, then trades with the bank (tradeToTarget2(SOCResourceSet)) or with other players (makeOffer(SOCPossiblePiece)).

Call when these conditions are all true:

May set any of these flags:

In a future iteration of the run() loop with the expected PLACING_ state, the bot will build whatWeWantToBuild by calling placeIfExpectPlacing().

Throws:
java.lang.IllegalStateException - if buildingPlan.isEmpty()
Since:
1.1.08

handlePUTPIECE_updateGameData

private void handlePUTPIECE_updateGameData(SOCPutPiece mes)
Handle a PUTPIECE for this game, by updating game data. For initial roads, also track their initial settlement in SOCPlayerTracker. In general, most tracking is done a bit later in handlePUTPIECE_updateTrackers(int, int, int).

Since:
1.1.08

handleCANCELBUILDREQUEST

private void handleCANCELBUILDREQUEST(SOCCancelBuildRequest mes)
Handle a CANCELBUILDREQUEST for this game.

During game startup (START1B or START2B):
When sent from server to client, CANCELBUILDREQUEST means the current player wants to undo the placement of their initial settlement.

During piece placement (PLACING_ROAD, PLACING_CITY, PLACING_SETTLEMENT, PLACING_FREE_ROAD1, or PLACING_FREE_ROAD2):
When sent from server to client, CANCELBUILDREQUEST means the player has sent an illegal PUTPIECE (bad building location). Humans can probably decide a better place to put their road, but robots must cancel the build request and decide on a new plan.

Since:
1.1.08

handleMAKEOFFER

private void handleMAKEOFFER(SOCMakeOffer mes)
Handle a MAKEOFFER for this game. if another player makes an offer, that's the same as a rejection, but still wants to deal. Call considerOffer(SOCTradeOffer), and if we accept, clear our buildingPlan so we'll replan it. Ignore our own MAKEOFFERs echoed from server.

Since:
1.1.08

handleREJECTOFFER

private void handleREJECTOFFER(SOCRejectOffer mes)
Handle a REJECTOFFER for this game. watch rejections of other players' offers, and of our offers.

Since:
1.1.08

handleDEVCARDACTION

private void handleDEVCARDACTION(SOCDevCardAction mes)
Handle a DEVCARDACTION for this game. No brain-specific action.

Since:
1.1.08

handlePUTPIECE_updateTrackers

private void handlePUTPIECE_updateTrackers(int pn,
                                           int coord,
                                           int pieceType)
Handle a PUTPIECE for this game, by updating SOCPlayerTrackers. Also handles the "move piece to here" part of MOVEPIECE.

For initial placement of our own pieces, this method also checks and clears expectPUTPIECE_FROM_START1A, and sets expectSTART1B, etc. The final initial putpiece clears expectPUTPIECE_FROM_START2B and sets expectPLAY.

For initial settlements, won't track here: Delay tracking until the corresponding road is placed, in handlePUTPIECE_updateGameData(SOCPutPiece). This prevents the need for tracker "undo" work if a human player changes their mind on where to place the settlement.

Parameters:
pn - Piece's player number
coord - Piece coordinate
pieceType - Piece type, as in SOCPlayingPiece.SETTLEMENT
Since:
1.1.08

buildRequestPlannedPiece

private void buildRequestPlannedPiece()
Have the client ask to build our top planned piece buildingPlan.pop(), unless we've already been told by the server to not build it. Sets whatWeWantToBuild, waitingForDevCard, or waitingForPickSpecialItem. Called from buildOrGetResourceByTradeOrCard().

Checks against whatWeFailedToBuild to see if server has rejected this already. Calls client.buyDevCard() or client.buildRequest(). Sets waitingForDevCard or waitingForPickSpecialItem, or sets waitingForGameState and expectPLACING_SETTLEMENT (etc).

Since:
1.1.08

planBuilding

private final void planBuilding()
Plan the next building plan and target. Should be called from run() under these conditions:
( !expectPLACING_ROBBER && buildingPlan.empty() && (ourPlayerData.getResources().getTotal() > 1) && (failedBuildingAttempts < MAX_DENIED_BUILDING_PER_TURN))

Sets these fields and makes these calls:

Since:
1.1.08

handlePLAYERELEMENT

private void handlePLAYERELEMENT(SOCPlayerElement mes)
Handle a PLAYERELEMENT for this game. Update a player's amount of a resource or a building type.

If this during the SOCGame.PLAY state, then update the SOCRobotNegotiator'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.

Otherwise, only the game data is updated, nothing brain-specific.

Since:
1.1.08

handlePLAYERELEMENT_numRsrc

protected void handlePLAYERELEMENT_numRsrc(SOCPlayerElement mes,
                                           SOCPlayer pl,
                                           int rtype,
                                           java.lang.String rtypeStr)
Update a player's amount of a resource.

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.

Parameters:
mes - Message with amount and action (SET/GAIN/LOSE)
pl - Player to update
rtype - Type of resource, like SOCResourceConstants.CLAY
rtypeStr - Resource type name, for debugging

trackNewSettlement

protected void trackNewSettlement(SOCSettlement newSettlement,
                                  boolean isCancel)
Run a newly placed settlement through the playerTrackers. Called only after SOCGame.putPiece(SOCPlayingPiece) or SOCGame.putTempPiece(SOCPlayingPiece).

During initial board setup, settlements aren't tracked when placed. They are deferred until their corresponding road placement, in case a human player decides to cancel their settlement and place it elsewhere. During normal play, the settlements are tracked immediately when placed. (Code previously in body of the run method.) Placing the code in its own method allows tracking that settlement when the road's putPiece message arrives.

Parameters:
newSettlement - The newly placed settlement for the playerTrackers
isCancel - Is this our own robot's settlement placement, rejected by the server? If so, this method call will cancel its placement within the game data / robot data.

trackNewCity

private void trackNewCity(SOCCity newCity,
                          boolean isCancel)
Run a newly placed city through the PlayerTrackers.

Parameters:
newCity - The newly placed city
isCancel - Is this our own robot's city placement, rejected by the server? If so, this method call will cancel its placement within the game data / robot data.

trackNewRoadOrShip

protected void trackNewRoadOrShip(SOCRoad newRoad,
                                  boolean isCancel)
Run a newly placed road or ship through the playerTrackers.

Parameters:
newRoad - The newly placed road or ship
isCancel - Is this our own robot's placement, rejected by the server? If so, this method call will cancel its placement within the game data / robot data.

cancelWrongPiecePlacement

protected void cancelWrongPiecePlacement(SOCCancelBuildRequest mes)
We've asked for an illegal piece placement. Cancel and invalidate this planned piece, make a new plan. If SOCGame.isSpecialBuilding(), will set variables to force the end of our special building turn. Also handles illegal requests to buy development cards (piece type -2 in SOCCancelBuildRequest).

This method increments failedBuildingAttempts, but won't leave the game if we've failed too many times. The brain's run loop should make that decision.

Parameters:
mes - Cancel message from server, including piece type

cancelWrongPiecePlacementLocal

protected void cancelWrongPiecePlacementLocal(SOCPlayingPiece cancelPiece)
Remove our incorrect piece placement, it's been rejected by the server. Take this piece out of trackers, without sending any response back to the server.

This method invalidates that piece in trackers, so we don't try again to build it. Since we treat it like another player's new placement, we can remove any of our planned pieces depending on this one.

Also calls SOCPlayer.clearPotentialSettlement(int), clearPotentialRoad, or clearPotentialCity.

Parameters:
cancelPiece - Type and coordinates of the piece to cancel; null is allowed but not very useful.

kill

public void kill()
kill this brain


pause

public void pause(int msec)
pause for a bit.

When SOCGame.isBotsOnly, pause only 25% as long, to quicken the simulation but not make it too fast to allow a person to observe.

In a 6-player game, pause only 75% as long, to shorten the overall game delay, except if waitingForTradeResponse. This is indicated by the pauseFaster flag.

Parameters:
msec - number of milliseconds to pause

placeFirstSettlement

protected void placeFirstSettlement(int firstSettlement)
place planned first settlement

Parameters:
firstSettlement - First settlement's node coordinate
See Also:
placeInitSettlement(int)

placeInitSettlement

protected void placeInitSettlement(int initSettlement)
Place planned initial settlement after first one.

Parameters:
initSettlement - Second or third settlement's node coordinate, from OpeningBuildStrategy.planSecondSettlement() or from OpeningBuildStrategy#planThirdSettlement(); should not be -1
See Also:
placeFirstSettlement(int)

planAndPlaceInitRoad

protected void planAndPlaceInitRoad()
Plan and place a road attached to our most recently placed initial settlement, in game states START1B, START2B, START3B. Calls OpeningBuildStrategy.planInitRoad().

Road choice is based on the best nearby potential settlements, and doesn't directly check ourPlayerData.isPotentialRoad(edgeCoord). If the server rejects our road choice, then cancelWrongPiecePlacementLocal(SOCPlayingPiece) will need to know which settlement node we were aiming for, and call ourPlayerData.clearPotentialSettlement(nodeCoord). The lastStartingRoadTowardsNode field holds this coordinate.


moveRobber

protected void moveRobber()
move the robber


pickFreeResources

protected void pickFreeResources(int numChoose)
Respond to server's request to pick resources to gain from the Gold Hex. Use buildingPlan or, if that's empty (initial placement), pick what's rare from OpeningBuildStrategy.estimateResourceRarity().

Parameters:
numChoose - Number of resources to pick
Since:
2.0.00

tradeStuff

protected void tradeStuff()
do some trading -- this method is obsolete and not called. Instead see makeOffer(SOCPossiblePiece), considerOffer(SOCTradeOffer), etc, and the javadoc for negotiator.


expandTradeTreeNode

protected void expandTradeTreeNode(SOCTradeTree currentTreeNode,
                                   java.util.Hashtable<SOCResourceSet,SOCTradeTree> table)
expand a trade tree node

Parameters:
currentTreeNode - the tree node that we're expanding
table - the table of all of the nodes in the tree except this one

scoreTradeOutcome

protected int scoreTradeOutcome(SOCResourceSet tradeOutcome)
evaluate a trade outcome by calculating how much you could build with it

Parameters:
tradeOutcome - a set of resources that would be the result of trading

tradeToTarget2

protected boolean tradeToTarget2(SOCResourceSet targetResources)
Make bank trades or port trades to get the target resources, if possible.

Parameters:
targetResources - the resources that we want, can be null for an empty set (method returns false)
Returns:
true if we sent a request to trade, false if we already have the resources or if we don't have enough to trade in for targetResources.

considerOffer

protected int considerOffer(SOCTradeOffer offer)
Consider a trade offer made by another player.

Parameters:
offer - the offer to consider
Returns:
a code that represents how we want to respond. Note: a negative result means we do nothing
See Also:
makeCounterOffer(SOCTradeOffer)

makeOffer

protected boolean makeOffer(SOCPossiblePiece target)
Make a trade offer to another player, or decide to make no offer. Calls SOCRobotNegotiator.makeOffer(SOCPossiblePiece). Will set either waitingForTradeResponse or doneTrading, and update ourPlayerData.setCurrentOffer(),

Parameters:
target - the resources that we want
Returns:
true if we made an offer

makeCounterOffer

protected boolean makeCounterOffer(SOCTradeOffer offer)
make a counter offer to another player

Parameters:
offer - their offer
Returns:
true if we made an offer

chooseFreeResources

protected boolean chooseFreeResources(SOCResourceSet targetResources,
                                      int numChoose,
                                      boolean clearResChoices)
Choose the resources we need most, for playing a Discovery development card or when a Gold Hex number is rolled. Find the most needed resource by looking at which of the resources we still need takes the longest to acquire, then add to resourceChoices. Looks at our player's current resources.

Parameters:
targetResources - Resources needed to build our next planned piece, from SOCPossiblePiece.getResourcesToBuild() for buildingPlan.peek()
numChoose - Number of resources to choose
clearResChoices - If true, clear resourceChoices before choosing what to add to it; set false if calling several times to iteratively build up a big choice.
Returns:
True if we could choose numChoose resources towards targetResources, false if we could fully satisfy targetResources from our current resources + less than numChoose more. Examine resourceChoices.getTotal() to see how many were chosen.

chooseFreeResourcesIfNeeded

private boolean chooseFreeResourcesIfNeeded(SOCResourceSet targetResources,
                                            int numChoose,
                                            boolean chooseIfNotNeeded)
Do we need to acquire at least numChoose resources to build our next piece? Choose the resources we need most; used when we want to play a discovery development card or when a Gold Hex number is rolled. If returns true, has called chooseFreeResources(SOCResourceSet, int, boolean) and has set resourceChoices.

Parameters:
targetResources - Resources needed to build our next planned piece, from SOCPossiblePiece.getResourcesToBuild() for buildingPlan. If null, returns false (no more resources required).
numChoose - Number of resources to choose
chooseIfNotNeeded - Even if we find we don't need them, choose anyway; set true for Gold Hex choice, false for Discovery card pick.
Returns:
true if we need numChoose resources
Since:
2.0.00

debugInfo

private void debugInfo()
this is for debugging


printResources

private void printResources()
For each player in game: client.sendText, and debug-print to console, game.getPlayer(i).getResources()