use of soc.game.SOCLRPathData 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.SOCLRPathData in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method recalcLongestRoadETA.
/**
* Calculate the longest road ETA.
* Always 500 or more if {@link SOCGameOption#K_SC_0RVP} is set.
* Updates fields for {@link #getLongestRoadETA()} and {@link #getRoadsToGo()}.
*/
public void recalcLongestRoadETA() {
// TODO handle ships here (different resources, etc)
D.ebugPrintln("=== recalcLongestRoadETA for player " + playerNumber);
final int roadETA;
SOCBuildingSpeedEstimate bse = new SOCBuildingSpeedEstimate(player.getNumbers());
roadETA = bse.calculateRollsFast(SOCGame.EMPTY_RESOURCES, SOCRoad.COST, 500, player.getPortFlags());
roadsToGo = 500;
longestRoadETA = 500;
int longestRoadLength;
SOCPlayer lrPlayer = game.getPlayerWithLongestRoad();
if ((lrPlayer != null) && (lrPlayer.getPlayerNumber() == playerNumber)) {
// /
// / we have longest road
// /
// D.ebugPrintln("=== we have longest road");
longestRoadETA = 0;
roadsToGo = 0;
} else if (!game.isGameOptionSet(SOCGameOption.K_SC_0RVP)) {
if (lrPlayer == null) {
// /
// / no one has longest road
// /
longestRoadLength = Math.max(4, player.getLongestRoadLength());
} else {
longestRoadLength = lrPlayer.getLongestRoadLength();
}
Iterator<SOCLRPathData> lrPathsIter = player.getLRPaths().iterator();
int depth;
while (lrPathsIter.hasNext()) {
SOCLRPathData pathData = lrPathsIter.next();
depth = Math.min(((longestRoadLength + 1) - pathData.getLength()), player.getNumPieces(SOCPlayingPiece.ROAD));
int minRoads = recalcLongestRoadETAAux(pathData.getBeginning(), pathData.getLength(), longestRoadLength, depth);
roadsToGo = Math.min(minRoads, roadsToGo);
minRoads = recalcLongestRoadETAAux(pathData.getEnd(), pathData.getLength(), longestRoadLength, depth);
roadsToGo = Math.min(minRoads, roadsToGo);
}
}
D.ebugPrintln("--- roadsToGo = " + roadsToGo);
longestRoadETA = roadsToGo * roadETA;
}
use of soc.game.SOCLRPathData in project JSettlers2 by jdmonin.
the class SOCRobotDM method dumbFastGameStrategy.
/**
* Plan building for the dumbFastGameStrategy ({@link #FAST_STRATEGY}).
* uses rules to determine what to build next
* and update {@link #buildingPlan}.
*<P>
* For example, if {@link #favoriteSettlement} is chosen,
* it's chosen from {@link #ourPlayerTracker}{@link SOCPlayerTracker#getPossibleSettlements() .getPossibleSettlements()}.
*
*<H4>Outline:</H4>
* Possible cities and settlements are looked at first.
* Find the city with best {@link SOCPossibleCity#getSpeedupTotal()}, then check each possible
* settlement's {@link SOCPossiblePiece#getETA()} against the city's ETA to possibly choose one to build.
* (If one is chosen, its {@link SOCPossibleSettlement#getNecessaryRoads()}
* will also be chosen here.) Then, Knights or Dev Cards.
* Only then would roads or ships be looked at, for Longest Route
* (and only if we're at 5 VP or more).
*<P>
* This method never directly checks
* {@code ourPlayerTracker}{@link SOCPlayerTracker#getPossibleRoads() .getPossibleRoads()}, instead
* it adds the roads or ships from {@link SOCPossibleSettlement#getNecessaryRoads()} to {@link #buildingPlan}
* when a possible settlement is picked to build.
*<P>
* Some scenarios require special moves or certain actions to win the game. If we're playing in
* such a scenario, after calculating {@link #favoriteSettlement}, {@link #favoriteCity}, etc, calls
* {@link #scenarioGameStrategyPlan(float, float, boolean, boolean, SOCBuildingSpeedEstimate, int, boolean)}.
* See that method for the list of scenarios which need such planning.
*
* @param buildingETAs the ETAs for building each piece type
* @see #smartGameStrategy(int[])
*/
protected void dumbFastGameStrategy(final int[] buildingETAs) {
D.ebugPrintln("***** dumbFastGameStrategy *****");
// If this game is on the 6-player board, check whether we're planning for
// the Special Building Phase. Can't buy cards or trade in that phase.
final boolean forSpecialBuildingPhase = game.isSpecialBuilding() || (game.getCurrentPlayerNumber() != ourPlayerNumber);
int bestETA = 500;
SOCBuildingSpeedEstimate ourBSE = new SOCBuildingSpeedEstimate(ourPlayerData.getNumbers());
if (ourPlayerData.getTotalVP() < 5) {
//
if (ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) {
Iterator<SOCPossibleCity> posCitiesIter = ourPlayerTracker.getPossibleCities().values().iterator();
while (posCitiesIter.hasNext()) {
SOCPossibleCity posCity = posCitiesIter.next();
D.ebugPrintln("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
D.ebugPrintln("Speedup = " + posCity.getSpeedupTotal());
D.ebugPrintln("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
if ((brain != null) && brain.getDRecorder().isOn()) {
brain.getDRecorder().startRecording("CITY" + posCity.getCoordinates());
brain.getDRecorder().record("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
brain.getDRecorder().record("Speedup = " + posCity.getSpeedupTotal());
brain.getDRecorder().record("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
brain.getDRecorder().stopRecording();
}
if ((favoriteCity == null) || (posCity.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
favoriteCity = posCity;
bestETA = buildingETAs[SOCBuildingSpeedEstimate.CITY];
}
}
}
//
// score the possible settlements
//
scoreSettlementsForDumb(buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT], ourBSE);
//
// pick something to build
//
Iterator<SOCPossibleSettlement> posSetsIter = ourPlayerTracker.getPossibleSettlements().values().iterator();
while (posSetsIter.hasNext()) {
SOCPossibleSettlement posSet = posSetsIter.next();
if ((brain != null) && brain.getDRecorder().isOn()) {
brain.getDRecorder().startRecording("SETTLEMENT" + posSet.getCoordinates());
brain.getDRecorder().record("Estimate speedup of stlmt at " + game.getBoard().nodeCoordToString(posSet.getCoordinates()));
brain.getDRecorder().record("Speedup = " + posSet.getSpeedupTotal());
brain.getDRecorder().record("ETA = " + posSet.getETA());
Stack<SOCPossibleRoad> roadPath = posSet.getRoadPath();
if (roadPath != null) {
brain.getDRecorder().record("Path:");
Iterator<SOCPossibleRoad> rpIter = roadPath.iterator();
while (rpIter.hasNext()) {
SOCPossibleRoad posRoad = rpIter.next();
brain.getDRecorder().record("Road at " + game.getBoard().edgeCoordToString(posRoad.getCoordinates()));
}
}
brain.getDRecorder().stopRecording();
}
if (posSet.getETA() < bestETA) {
bestETA = posSet.getETA();
favoriteSettlement = posSet;
} else if (posSet.getETA() == bestETA) {
if (favoriteSettlement == null) {
if ((favoriteCity == null) || (posSet.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
favoriteSettlement = posSet;
}
} else {
if (posSet.getSpeedupTotal() > favoriteSettlement.getSpeedupTotal()) {
favoriteSettlement = posSet;
}
}
}
}
if (favoriteSettlement != null) {
//
// we want to build a settlement
//
D.ebugPrintln("Picked favorite settlement at " + game.getBoard().nodeCoordToString(favoriteSettlement.getCoordinates()));
buildingPlan.push(favoriteSettlement);
if (!favoriteSettlement.getNecessaryRoads().isEmpty()) {
//
// we need to build roads first
//
Stack<SOCPossibleRoad> roadPath = favoriteSettlement.getRoadPath();
while (!roadPath.empty()) {
buildingPlan.push(roadPath.pop());
}
}
} else if (favoriteCity != null) {
//
// we want to build a city
//
D.ebugPrintln("Picked favorite city at " + game.getBoard().nodeCoordToString(favoriteCity.getCoordinates()));
buildingPlan.push(favoriteCity);
} else {
//
if ((game.getNumDevCards() > 0) && !forSpecialBuildingPhase) {
//
// buy a card if there are any left
//
D.ebugPrintln("Buy a card");
SOCPossibleCard posCard = new SOCPossibleCard(ourPlayerData, buildingETAs[SOCBuildingSpeedEstimate.CARD]);
buildingPlan.push(posCard);
}
}
} else {
//
// we have more than 4 points
//
int choice = -1;
//
// consider Largest Army
//
D.ebugPrintln("Calculating Largest Army ETA");
int laETA = 500;
int laSize = 0;
SOCPlayer laPlayer = game.getPlayerWithLargestArmy();
if (laPlayer == null) {
// /
// / no one has largest army
// /
laSize = 3;
} else if (laPlayer.getPlayerNumber() == ourPlayerNumber) {
// /
// / we have largest army
// /
D.ebugPrintln("We have largest army");
} else {
laSize = laPlayer.getNumKnights() + 1;
}
// /
// / figure out how many knights we need to buy
// /
int knightsToBuy = 0;
if ((ourPlayerData.getNumKnights() + // OLD + NEW knights
ourPlayerData.getInventory().getAmount(SOCDevCardConstants.KNIGHT)) < laSize) {
knightsToBuy = laSize - (ourPlayerData.getNumKnights() + ourPlayerData.getInventory().getAmount(SOCInventory.OLD, SOCDevCardConstants.KNIGHT));
}
D.ebugPrintln("knightsToBuy = " + knightsToBuy);
if (ourPlayerData.getGame().getNumDevCards() >= knightsToBuy) {
// /
// / figure out how long it takes to buy this many knights
// /
SOCResourceSet targetResources = new SOCResourceSet();
for (int i = 0; i < knightsToBuy; i++) {
targetResources.add(SOCDevCard.COST);
}
laETA = ourBSE.calculateRollsFast(ourPlayerData.getResources(), targetResources, 100, ourPlayerData.getPortFlags());
} else {
// /
// / not enough dev cards left
// /
}
if ((laETA < bestETA) && !forSpecialBuildingPhase) {
bestETA = laETA;
choice = LA_CHOICE;
}
D.ebugPrintln("laETA = " + laETA);
//
// consider Longest Road
//
D.ebugPrintln("Calculating Longest Road ETA");
int lrETA = 500;
Stack<?> bestLRPath = null;
int lrLength;
SOCPlayer lrPlayer = game.getPlayerWithLongestRoad();
if ((lrPlayer != null) && (lrPlayer.getPlayerNumber() == ourPlayerNumber)) {
// /
// / we have longest road
// /
D.ebugPrintln("We have longest road");
} else if (!game.isGameOptionSet(SOCGameOption.K_SC_0RVP)) {
if (lrPlayer == null) {
// /
// / no one has longest road
// /
lrLength = Math.max(4, ourPlayerData.getLongestRoadLength());
} else {
lrLength = lrPlayer.getLongestRoadLength();
}
Iterator<SOCLRPathData> lrPathsIter = ourPlayerData.getLRPaths().iterator();
int depth;
while (lrPathsIter.hasNext()) {
Stack<?> path;
SOCLRPathData pathData = lrPathsIter.next();
depth = Math.min(((lrLength + 1) - pathData.getLength()), ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD));
path = (Stack<?>) recalcLongestRoadETAAux(ourPlayerData, true, pathData.getBeginning(), pathData.getLength(), lrLength, depth);
if ((path != null) && ((bestLRPath == null) || (path.size() < bestLRPath.size()))) {
bestLRPath = path;
}
path = (Stack<?>) recalcLongestRoadETAAux(ourPlayerData, true, pathData.getEnd(), pathData.getLength(), lrLength, depth);
if ((path != null) && ((bestLRPath == null) || (path.size() < bestLRPath.size()))) {
bestLRPath = path;
}
}
if (bestLRPath != null) {
//
// calculate LR eta
//
D.ebugPrintln("Number of roads: " + bestLRPath.size());
SOCResourceSet targetResources = new SOCResourceSet();
for (int i = 0; i < bestLRPath.size(); i++) {
targetResources.add(SOCRoad.COST);
}
lrETA = ourBSE.calculateRollsFast(ourPlayerData.getResources(), targetResources, 100, ourPlayerData.getPortFlags());
}
}
if (lrETA < bestETA) {
bestETA = lrETA;
choice = LR_CHOICE;
}
D.ebugPrintln("lrETA = " + lrETA);
//
if ((ourPlayerData.getNumPieces(SOCPlayingPiece.CITY) > 0) && (buildingETAs[SOCBuildingSpeedEstimate.CITY] <= bestETA)) {
Iterator<SOCPossibleCity> posCitiesIter = ourPlayerTracker.getPossibleCities().values().iterator();
while (posCitiesIter.hasNext()) {
SOCPossibleCity posCity = posCitiesIter.next();
if ((brain != null) && brain.getDRecorder().isOn()) {
brain.getDRecorder().startRecording("CITY" + posCity.getCoordinates());
brain.getDRecorder().record("Estimate speedup of city at " + game.getBoard().nodeCoordToString(posCity.getCoordinates()));
brain.getDRecorder().record("Speedup = " + posCity.getSpeedupTotal());
brain.getDRecorder().record("ETA = " + buildingETAs[SOCBuildingSpeedEstimate.CITY]);
brain.getDRecorder().stopRecording();
}
if ((favoriteCity == null) || (posCity.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
favoriteCity = posCity;
bestETA = buildingETAs[SOCBuildingSpeedEstimate.CITY];
choice = CITY_CHOICE;
}
}
}
//
if (ourPlayerData.getNumPieces(SOCPlayingPiece.SETTLEMENT) > 0) {
scoreSettlementsForDumb(buildingETAs[SOCBuildingSpeedEstimate.SETTLEMENT], ourBSE);
Iterator<SOCPossibleSettlement> posSetsIter = ourPlayerTracker.getPossibleSettlements().values().iterator();
while (posSetsIter.hasNext()) {
SOCPossibleSettlement posSet = posSetsIter.next();
if ((brain != null) && brain.getDRecorder().isOn()) {
brain.getDRecorder().startRecording("SETTLEMENT" + posSet.getCoordinates());
brain.getDRecorder().record("Estimate speedup of stlmt at " + game.getBoard().nodeCoordToString(posSet.getCoordinates()));
brain.getDRecorder().record("Speedup = " + posSet.getSpeedupTotal());
brain.getDRecorder().record("ETA = " + posSet.getETA());
Stack<SOCPossibleRoad> roadPath = posSet.getRoadPath();
if (roadPath != null) {
brain.getDRecorder().record("Path:");
Iterator<SOCPossibleRoad> rpIter = roadPath.iterator();
while (rpIter.hasNext()) {
SOCPossibleRoad posRoad = rpIter.next();
brain.getDRecorder().record("Road at " + game.getBoard().edgeCoordToString(posRoad.getCoordinates()));
}
}
brain.getDRecorder().stopRecording();
}
if ((posSet.getRoadPath() == null) || (ourPlayerData.getNumPieces(SOCPlayingPiece.ROAD) >= posSet.getRoadPath().size())) {
if (posSet.getETA() < bestETA) {
bestETA = posSet.getETA();
favoriteSettlement = posSet;
choice = SETTLEMENT_CHOICE;
} else if (posSet.getETA() == bestETA) {
if (favoriteSettlement == null) {
if ((favoriteCity == null) || (posSet.getSpeedupTotal() > favoriteCity.getSpeedupTotal())) {
favoriteSettlement = posSet;
choice = SETTLEMENT_CHOICE;
}
} else {
if (posSet.getSpeedupTotal() > favoriteSettlement.getSpeedupTotal()) {
favoriteSettlement = posSet;
}
}
}
}
}
}
if (game.isGameOptionSet(SOCGameOption.K_SC_PIRI) || game.isGameOptionSet(SOCGameOption.K_SC_WOND)) {
if (scenarioGameStrategyPlan(bestETA, -1f, false, (choice == LA_CHOICE), ourBSE, 0, forSpecialBuildingPhase))
// <--- Early return: Scenario-specific buildingPlan was pushed ---
return;
}
//
switch(choice) {
case LA_CHOICE:
D.ebugPrintln("Picked LA");
if (!forSpecialBuildingPhase) {
for (int i = 0; i < knightsToBuy; i++) {
SOCPossibleCard posCard = new SOCPossibleCard(ourPlayerData, 1);
buildingPlan.push(posCard);
}
}
break;
case LR_CHOICE:
D.ebugPrintln("Picked LR");
while (!bestLRPath.empty()) {
SOCPossibleRoad pr = (SOCPossibleRoad) bestLRPath.pop();
D.ebugPrintln("LR road at " + game.getBoard().edgeCoordToString(pr.getCoordinates()));
buildingPlan.push(pr);
}
break;
case CITY_CHOICE:
D.ebugPrintln("Picked favorite city at " + game.getBoard().nodeCoordToString(favoriteCity.getCoordinates()));
buildingPlan.push(favoriteCity);
break;
case SETTLEMENT_CHOICE:
D.ebugPrintln("Picked favorite settlement at " + game.getBoard().nodeCoordToString(favoriteSettlement.getCoordinates()));
buildingPlan.push(favoriteSettlement);
if (!favoriteSettlement.getNecessaryRoads().isEmpty()) {
//
// we need to build roads first
//
Stack<SOCPossibleRoad> roadPath = favoriteSettlement.getRoadPath();
while (!roadPath.empty()) {
SOCPossibleRoad pr = roadPath.pop();
D.ebugPrintln("Nec road at " + game.getBoard().edgeCoordToString(pr.getCoordinates()));
buildingPlan.push(pr);
}
}
}
}
}
use of soc.game.SOCLRPathData in project JSettlers2 by jdmonin.
the class SOCRobotDM method recalcLongestRoadETAAux.
/**
* Does a depth first search of legal possible road edges from the end point of the longest
* path connecting a graph of nodes, and returns which roads or how many roads
* would need to be built to take longest road.
*<P>
* Do not call if {@link SOCGameOption#K_SC_0RVP} is set, because
* this method needs {@link SOCPlayer#getLRPaths()} which will be empty.
*<P>
* Combined implementation for use by SOCRobotDM and {@link SOCPlayerTracker}.
*
* @param pl Calculate this player's longest road;
* typically SOCRobotDM.ourPlayerData or SOCPlayerTracker.player
* @param wantsStack If true, return the Stack; otherwise, return numRoads.
* @param startNode the path endpoint, such as from
* {@link SOCPlayer#getLRPaths()}.(i){@link SOCLRPathData#getBeginning() .getBeginning()}
* or {@link SOCLRPathData#getEnd() .getEnd()}
* @param pathLength the length of that path
* @param lrLength length of longest road in the game
* @param searchDepth how many roads out to search
*
* @return if <tt>wantsStack</tt>: a {@link Stack} containing the path of roads with the last one
* (farthest from <tt>startNode</tt>) on top, or <tt>null</tt> if it can't be done.
* If ! <tt>wantsStack</tt>: Integer: the number of roads needed, or 500 if it can't be done
*/
static Object recalcLongestRoadETAAux(SOCPlayer pl, final boolean wantsStack, final int startNode, final int pathLength, final int lrLength, final int searchDepth) {
// D.ebugPrintln("=== recalcLongestRoadETAAux("+Integer.toHexString(startNode)+","+pathLength+","+lrLength+","+searchDepth+")");
//
// We're doing a depth first search of all possible road paths.
// For similar code, see SOCPlayer.calcLongestRoad2
// Both methods rely on a stack holding NodeLenVis (pop to curNode in loop);
// they differ in actual element type within the stack because they are
// gathering slightly different results (length or a stack of edges).
//
int longest = 0;
int numRoads = 500;
Pair<NodeLenVis<Integer>, List<Integer>> bestPathNode = null;
final SOCBoard board = pl.getGame().getBoard();
Stack<Pair<NodeLenVis<Integer>, List<Integer>>> pending = new Stack<Pair<NodeLenVis<Integer>, List<Integer>>>();
// Holds as-yet unvisited nodes:
// Pair members are <NodeLenVis, null or node-coordinate list of all parents (from DFS traversal order)>.
// Lists have most-distant node at beginning (item 0), and most-immediate at end of list (n-1).
// That list is used at the end to build the returned Stack which is the road path needed.
pending.push(new Pair<NodeLenVis<Integer>, List<Integer>>(new NodeLenVis<Integer>(startNode, pathLength, new Vector<Integer>()), null));
while (!pending.empty()) {
final Pair<NodeLenVis<Integer>, List<Integer>> dataPair = pending.pop();
final NodeLenVis<Integer> curNode = dataPair.getA();
// D.ebugPrintln("curNode = "+curNode);
final int coord = curNode.node;
int len = curNode.len;
final Vector<Integer> visited = curNode.vis;
boolean pathEnd = false;
//
if (len > 0) {
final int pn = pl.getPlayerNumber();
SOCPlayingPiece p = board.settlementAtNode(coord);
if ((p != null) && (p.getPlayerNumber() != pn)) {
pathEnd = true;
// D.ebugPrintln("^^^ path end at "+Integer.toHexString(coord));
}
}
if (!pathEnd) {
//
// check if we've connected to another road graph of this player
//
Iterator<SOCLRPathData> lrPathsIter = pl.getLRPaths().iterator();
while (lrPathsIter.hasNext()) {
SOCLRPathData pathData = lrPathsIter.next();
if ((startNode != pathData.getBeginning()) && (startNode != pathData.getEnd()) && ((coord == pathData.getBeginning()) || (coord == pathData.getEnd()))) {
pathEnd = true;
len += pathData.getLength();
break;
}
}
}
if (!pathEnd) {
//
if ((len - pathLength) >= searchDepth) {
pathEnd = true;
}
// D.ebugPrintln("Reached search depth");
}
if (!pathEnd) {
/**
* For each of the 3 adjacent edges of coord's node,
* check for unvisited legal road possibilities.
* When they are found, push that edge's far-end node
* onto the pending stack.
*/
pathEnd = true;
for (int dir = 0; dir < 3; ++dir) {
int j = board.getAdjacentEdgeToNode(coord, dir);
if (pl.isLegalRoad(j)) {
final Integer edge = new Integer(j);
boolean match = false;
for (Enumeration<Integer> ev = visited.elements(); ev.hasMoreElements(); ) {
Integer vis = ev.nextElement();
if (vis.equals(edge)) {
match = true;
break;
}
}
if (!match) {
Vector<Integer> newVis = new Vector<Integer>(visited);
newVis.addElement(edge);
List<Integer> nodeParentList = dataPair.getB();
if (nodeParentList == null)
nodeParentList = new ArrayList<Integer>();
else
// clone before we add to it
nodeParentList = new ArrayList<Integer>(nodeParentList);
// curNode's coord will be parent to new pending element
nodeParentList.add(coord);
// edge's other node
j = board.getAdjacentNodeToNode(coord, dir);
pending.push(new Pair<NodeLenVis<Integer>, List<Integer>>(new NodeLenVis<Integer>(j, len + 1, newVis), nodeParentList));
pathEnd = false;
}
}
}
}
if (pathEnd) {
if (len > longest) {
longest = len;
numRoads = curNode.len - pathLength;
bestPathNode = dataPair;
} else if ((len == longest) && (curNode.len < numRoads)) {
numRoads = curNode.len - pathLength;
bestPathNode = dataPair;
}
}
}
if (!wantsStack) {
// As used by SOCPlayerTracker.
int rv;
if (longest > lrLength)
rv = numRoads;
else
rv = 500;
// <-- Early return: ! wantsStack ---
return new Integer(rv);
}
if ((longest > lrLength) && (bestPathNode != null)) {
// D.ebugPrintln("Converting nodes to road coords.");
//
// Return the path in a stack, with the last road (the one from bestPathNode) on top.
// Convert pairs of node coords to edge coords for roads.
// List is ordered from farthest parent at 0 to bestPathNode's parent at (n-1),
// so iterate same way to build the stack.
//
Stack<SOCPossibleRoad> path = new Stack<SOCPossibleRoad>();
int coordC, coordP;
List<Integer> nodeList = bestPathNode.getB();
if ((nodeList == null) || nodeList.isEmpty())
// <--- early return, no node list: should not happen ---
return null;
// append bestPathNode
nodeList.add(new Integer(bestPathNode.getA().node));
final int L = nodeList.size();
// root ancestor
coordP = nodeList.get(0);
for (int i = 1; i < L; ++i) {
coordC = nodeList.get(i);
path.push(new SOCPossibleRoad(pl, board.getEdgeBetweenAdjacentNodes(coordC, coordP), null));
coordP = coordC;
}
return path;
}
return null;
}
Aggregations