/** place a road attached to the last initial settlement */ public int planInitRoad(SOCGame game, SOCPlayer ourPlayerData, SOCRobotClient client) { int settlementNode = ourPlayerData.getLastSettlementCoord(); Hashtable twoAway = new Hashtable(); // <Integer,Integer> log.debug("--- placeInitRoad"); /** look at all of the nodes that are 2 away from the last settlement and pick the best one */ SOCBoard board = game.getBoard(); for (int facing = 1; facing <= 6; ++facing) { // each of 6 directions: NE, E, SE, SW, W, NW int tmp = board.getAdjacentNodeToNode2Away(settlementNode, facing); if ((tmp != -9) && ourPlayerData.isPotentialSettlement(tmp)) twoAway.put(new Integer(tmp), new Integer(0)); } scoreNodesForSettlements(twoAway, 3, 5, 10, game, ourPlayerData); log.debug("Init Road for " + client.getNickname()); /** * create a dummy player to calculate possible places to build taking into account where other * players will build before we can. */ SOCPlayer dummy = new SOCPlayer(ourPlayerData.getPlayerNumber(), game); if (game.getGameState() == SOCGame.START1B) { /** do a look ahead so we don't build toward a place where someone else will build first. */ int numberOfBuilds = numberOfEnemyBuilds(game); log.debug( "Other players will build " + numberOfBuilds + " settlements before I get to build again."); if (numberOfBuilds > 0) { /** rule out where other players are going to build */ Hashtable allNodes = new Hashtable(); // <Integer.Integer> final int minNode = board.getMinNode(); for (int i = minNode; i <= SOCBoard.MAXNODE; i++) { if (ourPlayerData.isPotentialSettlement(i)) { log.debug("-- potential settlement at " + Integer.toHexString(i)); allNodes.put(new Integer(i), new Integer(0)); } } /** favor spots with the most high numbers */ bestSpotForNumbers(allNodes, 100, game); /** favor spots near good ports */ /** check 3:1 ports */ Vector miscPortNodes = board.getPortCoordinates(SOCBoard.MISC_PORT); bestSpot2AwayFromANodeSet(board, allNodes, miscPortNodes, 5); /** check out good 2:1 ports */ for (int portType = SOCBoard.CLAY_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { /** * if the chances of rolling a number on the resource is better than 1/3, then it's worth * looking at the port */ if (resourceEstimates[portType] > 33) { Vector portNodes = board.getPortCoordinates(portType); int portWeight = (resourceEstimates[portType] * 10) / 56; bestSpot2AwayFromANodeSet(board, allNodes, portNodes, portWeight); } } /* * create a list of potential settlements that takes into account * where other players will build */ Vector psList = new Vector(); // <Integer> for (int j = minNode; j <= SOCBoard.MAXNODE; j++) { if (ourPlayerData.isPotentialSettlement(j)) { log.debug("- potential settlement at " + Integer.toHexString(j)); psList.addElement(new Integer(j)); } } dummy.setPotentialSettlements(psList); for (int builds = 0; builds < numberOfBuilds; builds++) { BoardNodeScorePair bestNodePair = new BoardNodeScorePair(0, 0); Enumeration nodesEnum = allNodes.keys(); // <Integer> while (nodesEnum.hasMoreElements()) { Integer nodeCoord = (Integer) nodesEnum.nextElement(); final int score = ((Integer) allNodes.get(nodeCoord)).intValue(); log.debug("NODE = " + Integer.toHexString(nodeCoord.intValue()) + " SCORE = " + score); if (bestNodePair.getScore() < score) { bestNodePair.setScore(score); bestNodePair.setNode(nodeCoord.intValue()); } } /** pretend that someone has built a settlement on the best spot */ dummy.updatePotentials(new SOCSettlement(ourPlayerData, bestNodePair.getNode(), null)); /** remove this spot from the list of best spots */ allNodes.remove(new Integer(bestNodePair.getNode())); } } } /** Find the best scoring node */ BoardNodeScorePair bestNodePair = new BoardNodeScorePair(0, 0); Enumeration cenum = twoAway.keys(); // <Integer> while (cenum.hasMoreElements()) { Integer coord = (Integer) cenum.nextElement(); final int score = ((Integer) twoAway.get(coord)).intValue(); log.debug( "Considering " + Integer.toHexString(coord.intValue()) + " with a score of " + score); if (dummy.isPotentialSettlement(coord.intValue())) { if (bestNodePair.getScore() < score) { bestNodePair.setScore(score); bestNodePair.setNode(coord.intValue()); } } else { log.debug("Someone is bound to ruin that spot."); } } // Reminder: settlementNode == ourPlayerData.getLastSettlementCoord() final int destination = bestNodePair.getNode(); // coordinate of future settlement // 2 nodes away from settlementNode final int roadEdge // will be adjacent to settlementNode = board.getAdjacentEdgeToNode2Away(settlementNode, destination); dummy.destroyPlayer(); return roadEdge; }
/** figure out where to place the two settlements */ public int planInitialSettlements(SOCGame game, SOCPlayer ourPlayerData) { log.debug("--- planInitialSettlements"); int[] rolls; Enumeration hexes; // Integers int speed; boolean allTheWay; firstSettlement = 0; secondSettlement = 0; int bestSpeed = 4 * SOCBuildingSpeedEstimate.DEFAULT_ROLL_LIMIT; SOCBoard board = game.getBoard(); SOCResourceSet emptySet = new SOCResourceSet(); SOCPlayerNumbers playerNumbers = new SOCPlayerNumbers(board.getBoardEncodingFormat()); int probTotal; int bestProbTotal; boolean[] ports = new boolean[SOCBoard.WOOD_PORT + 1]; SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate(); int[] prob = SOCNumberProbabilities.INT_VALUES; bestProbTotal = 0; for (int firstNode = board.getMinNode(); firstNode <= SOCBoard.MAXNODE; firstNode++) { if (ourPlayerData.isPotentialSettlement(firstNode)) { Integer firstNodeInt = new Integer(firstNode); // // this is just for testing purposes // log.debug("FIRST NODE -----------"); log.debug("firstNode = " + board.nodeCoordToString(firstNode)); StringBuffer sb = new StringBuffer(); sb.append("numbers:["); playerNumbers.clear(); probTotal = 0; hexes = SOCBoard.getAdjacentHexesToNode(firstNode).elements(); while (hexes.hasMoreElements()) { Integer hex = (Integer) hexes.nextElement(); int number = board.getNumberOnHexFromCoord(hex.intValue()); int resource = board.getHexTypeFromCoord(hex.intValue()); playerNumbers.addNumberForResource(number, resource, hex.intValue()); probTotal += prob[number]; sb.append(number + " "); } sb.append("]"); log.debug(sb.toString()); sb = new StringBuffer(); sb.append("ports: "); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { if (board.getPortCoordinates(portType).contains(firstNodeInt)) { ports[portType] = true; } else { ports[portType] = false; } sb.append(ports[portType] + " "); } log.debug(sb.toString()); log.debug("probTotal = " + probTotal); estimate.recalculateEstimates(playerNumbers); speed = 0; allTheWay = false; try { speed += estimate.calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, 300, ports).getRolls(); speed += estimate.calculateRollsFast(emptySet, SOCGame.CITY_SET, 300, ports).getRolls(); speed += estimate.calculateRollsFast(emptySet, SOCGame.CARD_SET, 300, ports).getRolls(); speed += estimate.calculateRollsFast(emptySet, SOCGame.ROAD_SET, 300, ports).getRolls(); } catch (CutoffExceededException e) { } rolls = estimate.getEstimatesFromNothingFast(ports, 300); sb = new StringBuffer(); sb.append(" road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("speed = " + speed); // // end test // for (int secondNode = firstNode + 1; secondNode <= SOCBoard.MAXNODE; secondNode++) { if ((ourPlayerData.isPotentialSettlement(secondNode)) && (!board.getAdjacentNodesToNode(secondNode).contains(firstNodeInt))) { log.debug("firstNode = " + board.nodeCoordToString(firstNode)); log.debug("secondNode = " + board.nodeCoordToString(secondNode)); Integer secondNodeInt = new Integer(secondNode); /** get the numbers for these settlements */ sb = new StringBuffer(); sb.append("numbers:["); playerNumbers.clear(); probTotal = 0; hexes = SOCBoard.getAdjacentHexesToNode(firstNode).elements(); while (hexes.hasMoreElements()) { Integer hex = (Integer) hexes.nextElement(); int number = board.getNumberOnHexFromCoord(hex.intValue()); int resource = board.getHexTypeFromCoord(hex.intValue()); playerNumbers.addNumberForResource(number, resource, hex.intValue()); probTotal += prob[number]; sb.append(number + " "); } sb.append("] ["); hexes = SOCBoard.getAdjacentHexesToNode(secondNode).elements(); while (hexes.hasMoreElements()) { Integer hex = (Integer) hexes.nextElement(); int number = board.getNumberOnHexFromCoord(hex.intValue()); int resource = board.getHexTypeFromCoord(hex.intValue()); playerNumbers.addNumberForResource(number, resource, hex.intValue()); probTotal += prob[number]; sb.append(number + " "); } sb.append("]"); log.debug(sb.toString()); /** see if the settlements are on any ports */ sb = new StringBuffer(); sb.append("ports: "); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { if ((board.getPortCoordinates(portType).contains(firstNodeInt)) || (board.getPortCoordinates(portType).contains(secondNodeInt))) { ports[portType] = true; } else { ports[portType] = false; } sb.append(ports[portType] + " "); } log.debug(sb.toString()); log.debug("probTotal = " + probTotal); /** estimate the building speed for this pair */ estimate.recalculateEstimates(playerNumbers); speed = 0; allTheWay = false; try { speed += estimate .calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports) .getRolls(); allTheWay = true; } } } } catch (CutoffExceededException e) { speed = bestSpeed; } rolls = estimate.getEstimatesFromNothingFast(ports, bestSpeed); sb = new StringBuffer(); sb.append(" road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("allTheWay = " + allTheWay); log.debug("speed = " + speed); /** keep the settlements with the best speed */ if (speed < bestSpeed) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("bestSpeed = " + bestSpeed); log.debug("bestProbTotal = " + bestProbTotal); } else if ((speed == bestSpeed) && allTheWay) { if (probTotal > bestProbTotal) { log.debug("Equal speed, better prob"); firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); log.debug("bestSpeed = " + bestSpeed); log.debug("bestProbTotal = " + bestProbTotal); } } } } } } /** choose which settlement to place first */ playerNumbers.clear(); hexes = SOCBoard.getAdjacentHexesToNode(firstSettlement).elements(); while (hexes.hasMoreElements()) { int hex = ((Integer) hexes.nextElement()).intValue(); int number = board.getNumberOnHexFromCoord(hex); int resource = board.getHexTypeFromCoord(hex); playerNumbers.addNumberForResource(number, resource, hex); } Integer firstSettlementInt = new Integer(firstSettlement); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { if (board.getPortCoordinates(portType).contains(firstSettlementInt)) { ports[portType] = true; } else { ports[portType] = false; } } estimate.recalculateEstimates(playerNumbers); int firstSpeed = 0; int cutoff = 100; try { firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, cutoff, ports).getRolls(); } catch (CutoffExceededException e) { firstSpeed += cutoff; } try { firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CITY_SET, cutoff, ports).getRolls(); } catch (CutoffExceededException e) { firstSpeed += cutoff; } try { firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CARD_SET, cutoff, ports).getRolls(); } catch (CutoffExceededException e) { firstSpeed += cutoff; } try { firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.ROAD_SET, cutoff, ports).getRolls(); } catch (CutoffExceededException e) { firstSpeed += cutoff; } playerNumbers.clear(); hexes = SOCBoard.getAdjacentHexesToNode(secondSettlement).elements(); while (hexes.hasMoreElements()) { int hex = ((Integer) hexes.nextElement()).intValue(); int number = board.getNumberOnHexFromCoord(hex); int resource = board.getHexTypeFromCoord(hex); playerNumbers.addNumberForResource(number, resource, hex); } Integer secondSettlementInt = new Integer(secondSettlement); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { if (board.getPortCoordinates(portType).contains(secondSettlementInt)) { ports[portType] = true; } else { ports[portType] = false; } } estimate.recalculateEstimates(playerNumbers); int secondSpeed = 0; try { secondSpeed += estimate .calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports) .getRolls(); } catch (CutoffExceededException e) { secondSpeed += cutoff; } try { secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports).getRolls(); } catch (CutoffExceededException e) { secondSpeed += cutoff; } try { secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports).getRolls(); } catch (CutoffExceededException e) { secondSpeed += cutoff; } try { secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports).getRolls(); } catch (CutoffExceededException e) { secondSpeed += cutoff; } if (firstSpeed > secondSpeed) { int tmp = firstSettlement; firstSettlement = secondSettlement; secondSettlement = tmp; } log.debug( board.nodeCoordToString(firstSettlement) + ":" + firstSpeed + ", " + board.nodeCoordToString(secondSettlement) + ":" + secondSpeed); return firstSettlement; }
/** figure out where to place the second settlement */ public int planSecondSettlement(SOCGame game, SOCPlayer ourPlayerData) { log.debug("--- planSecondSettlement"); int bestSpeed = 4 * SOCBuildingSpeedEstimate.DEFAULT_ROLL_LIMIT; SOCBoard board = game.getBoard(); SOCResourceSet emptySet = new SOCResourceSet(); SOCPlayerNumbers playerNumbers = new SOCPlayerNumbers(board.getBoardEncodingFormat()); boolean[] ports = new boolean[SOCBoard.WOOD_PORT + 1]; SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate(); int probTotal; int bestProbTotal; int[] prob = SOCNumberProbabilities.INT_VALUES; int firstNode = firstSettlement; Integer firstNodeInt = new Integer(firstNode); bestProbTotal = 0; secondSettlement = -1; for (int secondNode = board.getMinNode(); secondNode <= SOCBoard.MAXNODE; secondNode++) { if ((ourPlayerData.isPotentialSettlement(secondNode)) && (!board.getAdjacentNodesToNode(secondNode).contains(firstNodeInt))) { Integer secondNodeInt = new Integer(secondNode); /** get the numbers for these settlements */ StringBuffer sb = new StringBuffer(); sb.append("numbers: "); playerNumbers.clear(); probTotal = 0; Enumeration hexes = SOCBoard.getAdjacentHexesToNode(firstNode).elements(); // Integers while (hexes.hasMoreElements()) { final int hex = ((Integer) hexes.nextElement()).intValue(); int number = board.getNumberOnHexFromCoord(hex); int resource = board.getHexTypeFromCoord(hex); playerNumbers.addNumberForResource(number, resource, hex); probTotal += prob[number]; sb.append(number + " "); } hexes = SOCBoard.getAdjacentHexesToNode(secondNode).elements(); while (hexes.hasMoreElements()) { final int hex = ((Integer) hexes.nextElement()).intValue(); int number = board.getNumberOnHexFromCoord(hex); int resource = board.getHexTypeFromCoord(hex); playerNumbers.addNumberForResource(number, resource, hex); probTotal += prob[number]; sb.append(number + " "); } /** see if the settlements are on any ports */ sb.append("ports: "); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { if ((board.getPortCoordinates(portType).contains(firstNodeInt)) || (board.getPortCoordinates(portType).contains(secondNodeInt))) { ports[portType] = true; } else { ports[portType] = false; } sb.append(ports[portType] + " "); } log.debug(sb.toString()); log.debug("probTotal = " + probTotal); /** estimate the building speed for this pair */ estimate.recalculateEstimates(playerNumbers); int speed = 0; try { speed += estimate .calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports) .getRolls(); } } } } catch (CutoffExceededException e) { speed = bestSpeed; } log.debug( Integer.toHexString(firstNode) + ", " + Integer.toHexString(secondNode) + ":" + speed); /** keep the settlements with the best speed */ if ((speed < bestSpeed) || (secondSettlement < 0)) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); int[] rolls = estimate.getEstimatesFromNothingFast(ports); sb = new StringBuffer(); sb.append("road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("bestSpeed = " + bestSpeed); } else if (speed == bestSpeed) { if (probTotal > bestProbTotal) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); int[] rolls = estimate.getEstimatesFromNothingFast(ports); sb = new StringBuffer(); sb.append("road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("bestSpeed = " + bestSpeed); } } } } return secondSettlement; }
/** * this figures out how many rolls it would take this player to get the target set of resources * given a starting set * * @param startingResources the starting resources * @param targetResources the target resources * @param cutoff throw an exception if the total speed is greater than this * @param ports a list of port flags * @return the number of rolls and our resources when the target is reached. If {@link * SOCResourceSet#contains(SOCResourceSet) startingResources.contains(targetResources)}, * returns 0 rolls and a {@code null} resource set. * @throws CutoffExceededException if estimate more than {@code cutoff} turns to obtain {@code * targetResources} */ protected SOCResSetBuildTimePair calculateRollsAccurate( SOCResourceSet startingResources, SOCResourceSet targetResources, int cutoff, boolean[] ports) throws CutoffExceededException { D.ebugPrintln("calculateRollsAccurate"); D.ebugPrintln(" start: " + startingResources); D.ebugPrintln(" target: " + targetResources); SOCResourceSet ourResources = startingResources.copy(); int rolls = 0; @SuppressWarnings("unchecked") Hashtable<SOCResourceSet, Float>[] resourcesOnRoll = new Hashtable[2]; resourcesOnRoll[0] = new Hashtable<SOCResourceSet, Float>(); resourcesOnRoll[1] = new Hashtable<SOCResourceSet, Float>(); int lastRoll = 0; int thisRoll = 1; resourcesOnRoll[lastRoll].put(ourResources, new Float(1.0)); boolean targetReached = ourResources.contains(targetResources); SOCResourceSet targetReachedResources = null; float targetReachedProb = (float) 0.0; while (!targetReached) { if (D.ebugOn) { D.ebugPrintln("roll: " + rolls); D.ebugPrintln("resourcesOnRoll[lastRoll]:"); Enumeration<SOCResourceSet> roltEnum = resourcesOnRoll[lastRoll].keys(); while (roltEnum.hasMoreElements()) { SOCResourceSet rs = roltEnum.nextElement(); Float prob = resourcesOnRoll[lastRoll].get(rs); D.ebugPrintln("---- prob:" + prob); D.ebugPrintln("---- rsrcs:" + rs); D.ebugPrintln(); } D.ebugPrintln("targetReachedProb: " + targetReachedProb); D.ebugPrintln("==================================="); } rolls++; if (rolls > cutoff) { D.ebugPrintln( "startingResources=" + startingResources + "\ntargetResources=" + targetResources + "\ncutoff=" + cutoff + "\nourResources=" + ourResources); throw new CutoffExceededException(); } // // get our resources for the roll // for (int diceResult = 2; diceResult <= 12; diceResult++) { SOCResourceSet gainedResources = resourcesForRoll[diceResult]; float diceProb = SOCNumberProbabilities.FLOAT_VALUES[diceResult]; // // add the resources that we get on this roll to // each set of resources that we got on the last // roll and multiply the probabilities // Enumeration<SOCResourceSet> lastResourcesEnum = resourcesOnRoll[lastRoll].keys(); while (lastResourcesEnum.hasMoreElements()) { SOCResourceSet lastResources = lastResourcesEnum.nextElement(); Float lastProb = resourcesOnRoll[lastRoll].get(lastResources); SOCResourceSet newResources = lastResources.copy(); newResources.add(gainedResources); float newProb = lastProb.floatValue() * diceProb; if (!newResources.contains(targetResources)) { // // do any possible trading with the bank/ports // for (int giveResource = SOCResourceConstants.CLAY; giveResource <= SOCResourceConstants.WOOD; giveResource++) { if ((newResources.getAmount(giveResource) - targetResources.getAmount(giveResource)) > 1) { // // find the ratio at which we can trade // int tradeRatio; if (ports[giveResource]) { tradeRatio = 2; } else if (ports[SOCBoard.MISC_PORT]) { tradeRatio = 3; } else { tradeRatio = 4; } // // get the target resources // int numTrades = (newResources.getAmount(giveResource) - targetResources.getAmount(giveResource)) / tradeRatio; // D.ebugPrintln("))) ***"); // D.ebugPrintln("))) giveResource="+giveResource); // D.ebugPrintln("))) tradeRatio="+tradeRatio); // D.ebugPrintln("))) newResources="+newResources); // D.ebugPrintln("))) targetResources="+targetResources); // D.ebugPrintln("))) numTrades="+numTrades); for (int trades = 0; trades < numTrades; trades++) { // // find the most needed resource by looking at // which of the resources we still need takes the // longest to aquire // int mostNeededResource = -1; for (int resource = SOCResourceConstants.CLAY; resource <= SOCResourceConstants.WOOD; resource++) { if (newResources.getAmount(resource) < targetResources.getAmount(resource)) { if (mostNeededResource < 0) { mostNeededResource = resource; } else { if (rollsPerResource[resource] > rollsPerResource[mostNeededResource]) { mostNeededResource = resource; } } } } // // make the trade // // D.ebugPrintln("))) want to trade "+tradeRatio+" "+giveResource+" for a // "+mostNeededResource); if ((mostNeededResource != -1) && (newResources.getAmount(giveResource) >= tradeRatio)) { // D.ebugPrintln("))) trading..."); newResources.add(1, mostNeededResource); if (newResources.getAmount(giveResource) < tradeRatio) { System.err.println("@@@ rsrcs=" + newResources); System.err.println("@@@ tradeRatio=" + tradeRatio); System.err.println("@@@ giveResource=" + giveResource); System.err.println("@@@ target=" + targetResources); } newResources.subtract(tradeRatio, giveResource); // D.ebugPrintln("))) newResources="+newResources); } if (newResources.contains(targetResources)) { break; } } if (newResources.contains(targetResources)) { break; } } } } // // if this set of resources is already in the list // of possible outcomes, add this probability to // that one, else just add this to the list // Float probFloat = resourcesOnRoll[thisRoll].get(newResources); float newProb2 = newProb; if (probFloat != null) { newProb2 = probFloat.floatValue() + newProb; } // // check to see if we reached our target // if (newResources.contains(targetResources)) { D.ebugPrintln("-----> TARGET HIT *"); D.ebugPrintln("newResources: " + newResources); D.ebugPrintln("newProb: " + newProb); targetReachedProb += newProb; if (targetReachedResources == null) { targetReachedResources = newResources; } if (targetReachedProb >= 0.5) { targetReached = true; } } else { resourcesOnRoll[thisRoll].put(newResources, new Float(newProb2)); } } } // // copy the resourcesOnRoll[thisRoll] table to the // resourcesOnRoll[lastRoll] table and clear the // resourcesOnRoll[thisRoll] table // int tmp = lastRoll; lastRoll = thisRoll; thisRoll = tmp; resourcesOnRoll[thisRoll].clear(); } if (D.ebugOn) { float probSum = (float) 0.0; D.ebugPrintln("**************** TARGET REACHED ************"); D.ebugPrintln("targetReachedResources: " + targetReachedResources); D.ebugPrintln("targetReachedProb: " + targetReachedProb); D.ebugPrintln("roll: " + rolls); D.ebugPrintln("resourcesOnRoll[lastRoll]:"); Enumeration<SOCResourceSet> roltEnum = resourcesOnRoll[lastRoll].keys(); while (roltEnum.hasMoreElements()) { SOCResourceSet rs = roltEnum.nextElement(); Float prob = resourcesOnRoll[lastRoll].get(rs); probSum += prob.floatValue(); D.ebugPrintln("---- prob:" + prob); D.ebugPrintln("---- rsrcs:" + rs); D.ebugPrintln(); } D.ebugPrintln("probSum = " + probSum); D.ebugPrintln("==================================="); } return (new SOCResSetBuildTimePair(targetReachedResources, rolls)); }
/** * Plan and place a road attached to our most recently placed initial settlement, in game states * {@link SOCGame#START1B START1B}, {@link SOCGame#START2B START2B}, {@link SOCGame#START3B * START3B}. Also sets {@link #getPlannedInitRoadDestinationNode()}. * * <p>Road choice is based on the best nearby potential settlements, and doesn't directly check * {@link SOCPlayer#isPotentialRoad(int) ourPlayerData.isPotentialRoad(edgeCoord)}. If the server * rejects our road choice, then {@link * SOCRobotBrain#cancelWrongPiecePlacementLocal(SOCPlayingPiece)} will need to know which * settlement node we were aiming for, and call {@link SOCPlayer#clearPotentialSettlement(int) * ourPlayerData.clearPotentialSettlement(nodeCoord)}. The {@link * SOCRobotBrain#lastStartingRoadTowardsNode} field holds this coordinate. * * @return road edge adjacent to initial settlement node */ public int planInitRoad() { // TODO handle ships here final int settlementNode = ourPlayerData.getLastSettlementCoord(); /** * Score the nearby nodes to build road towards: Key = coord Integer; value = Integer score * towards "best" node. */ Hashtable<Integer, Integer> twoAway = new Hashtable<Integer, Integer>(); log.debug("--- placeInitRoad"); /** look at all of the nodes that are 2 away from the last settlement, and pick the best one */ final SOCBoard board = game.getBoard(); for (int facing = 1; facing <= 6; ++facing) { // each of 6 directions: NE, E, SE, SW, W, NW int tmp = board.getAdjacentNodeToNode2Away(settlementNode, facing); if ((tmp != -9) && ourPlayerData.canPlaceSettlement(tmp)) twoAway.put(new Integer(tmp), new Integer(0)); } scoreNodesForSettlements(twoAway, 3, 5, 10); log.debug("Init Road for " + ourPlayerData.getName()); /** * create a dummy player to calculate possible places to build taking into account where other * players will build before we can. */ SOCPlayer dummy = new SOCPlayer(ourPlayerData.getPlayerNumber(), game); if ((game.getGameState() == SOCGame.START1B) || (game.isGameOptionSet(SOCGameOption.K_SC_3IP) && (game.getGameState() == SOCGame.START2B))) { /** do a look ahead so we don't build toward a place where someone else will build first. */ final int numberOfBuilds = numberOfEnemyBuilds(); log.debug( "Other players will build " + numberOfBuilds + " settlements before I get to build again."); if (numberOfBuilds > 0) { /** rule out where other players are going to build */ Hashtable<Integer, Integer> allNodes = new Hashtable<Integer, Integer>(); { Iterator<Integer> psi = ourPlayerData.getPotentialSettlements().iterator(); while (psi.hasNext()) allNodes.put(psi.next(), Integer.valueOf(0)); // log.debug("-- potential settlement at " + Integer.toHexString(next)); } /** favor spots with the most high numbers */ bestSpotForNumbers(allNodes, null, 100); /** favor spots near good ports */ /** check 3:1 ports */ Vector<Integer> miscPortNodes = board.getPortCoordinates(SOCBoard.MISC_PORT); bestSpot2AwayFromANodeSet(board, allNodes, miscPortNodes, 5); /** check out good 2:1 ports */ for (int portType = SOCBoard.CLAY_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { /** * if the chances of rolling a number on the resource is better than 1/3, then it's worth * looking at the port */ if (resourceEstimates[portType] > 33) { Vector<Integer> portNodes = board.getPortCoordinates(portType); final int portWeight = (resourceEstimates[portType] * 10) / 56; bestSpot2AwayFromANodeSet(board, allNodes, portNodes, portWeight); } } /* * create a list of potential settlements that takes into account * where other players will build */ Vector<Integer> psList = new Vector<Integer>(); psList.addAll(ourPlayerData.getPotentialSettlements()); // log.debug("- potential settlement at " + Integer.toHexString(j)); dummy.setPotentialAndLegalSettlements(psList, false, null); for (int builds = 0; builds < numberOfBuilds; builds++) { BoardNodeScorePair bestNodePair = new BoardNodeScorePair(0, 0); Enumeration<Integer> nodesEnum = allNodes.keys(); while (nodesEnum.hasMoreElements()) { final Integer nodeCoord = nodesEnum.nextElement(); final int score = allNodes.get(nodeCoord).intValue(); log.debug("NODE = " + Integer.toHexString(nodeCoord.intValue()) + " SCORE = " + score); if (bestNodePair.getScore() < score) { bestNodePair.setScore(score); bestNodePair.setNode(nodeCoord.intValue()); } } /** pretend that someone has built a settlement on the best spot */ dummy.updatePotentials(new SOCSettlement(ourPlayerData, bestNodePair.getNode(), null)); /** remove this spot from the list of best spots */ allNodes.remove(new Integer(bestNodePair.getNode())); } } } /** Find the best scoring node */ BoardNodeScorePair bestNodePair = new BoardNodeScorePair(0, 0); Enumeration<Integer> cenum = twoAway.keys(); while (cenum.hasMoreElements()) { final Integer coordInt = cenum.nextElement(); final int coord = coordInt.intValue(); final int score = twoAway.get(coordInt).intValue(); log.debug("Considering " + Integer.toHexString(coord) + " with a score of " + score); if (dummy.canPlaceSettlement(coord)) { if (bestNodePair.getScore() < score) { bestNodePair.setScore(score); bestNodePair.setNode(coord); } } else { log.debug("Someone is bound to ruin that spot."); } } // Reminder: settlementNode == ourPlayerData.getLastSettlementCoord() plannedRoadDestinationNode = bestNodePair.getNode(); // coordinate of future settlement // 2 nodes away from settlementNode final int roadEdge // will be adjacent to settlementNode = board.getAdjacentEdgeToNode2Away(settlementNode, plannedRoadDestinationNode); dummy.destroyPlayer(); return roadEdge; }
/** * figure out where to place the second settlement * * @return {@link #secondSettlement}, or -1 if none */ public int planSecondSettlement() { log.debug("--- planSecondSettlement"); int bestSpeed = 4 * SOCBuildingSpeedEstimate.DEFAULT_ROLL_LIMIT; final SOCBoard board = game.getBoard(); SOCResourceSet emptySet = new SOCResourceSet(); SOCPlayerNumbers playerNumbers = new SOCPlayerNumbers(board); boolean[] ports = new boolean[SOCBoard.WOOD_PORT + 1]; SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate(); int probTotal; int bestProbTotal; final int[] prob = SOCNumberProbabilities.INT_VALUES; final int firstNode = firstSettlement; bestProbTotal = 0; secondSettlement = -1; final int[] ourPotentialSettlements = ourPlayerData.getPotentialSettlements_arr(); if (ourPotentialSettlements == null) return -1; // Should not occur for (int i = 0; i < ourPotentialSettlements.length; ++i) { final int secondNode = ourPotentialSettlements[i]; // assert: ourPlayerData.isPotentialSettlement(secondNode) if (board.isNodeAdjacentToNode(secondNode, firstNode)) continue; // <-- too close to firstNode to build -- /** get the numbers for these settlements */ StringBuffer sb = new StringBuffer(); sb.append("numbers: "); playerNumbers.clear(); probTotal = playerNumbers.updateNumbersAndProbability(firstNode, board, prob, sb); probTotal += playerNumbers.updateNumbersAndProbability(secondNode, board, prob, sb); /** see if the settlements are on any ports */ // sb.append("ports: "); Arrays.fill(ports, false); int portType = board.getPortTypeFromNodeCoord(firstNode); if (portType != -1) ports[portType] = true; portType = board.getPortTypeFromNodeCoord(secondNode); if (portType != -1) ports[portType] = true; // log.debug(sb.toString()); log.debug("probTotal = " + probTotal); /** estimate the building speed for this pair */ estimate.recalculateEstimates(playerNumbers); int speed = 0; try { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports) .getRolls(); } } } // because of addition, speed might be as much as (bestSpeed - 1) + bestSpeed } catch (CutoffExceededException e) { speed = bestSpeed; } log.debug( Integer.toHexString(firstNode) + ", " + Integer.toHexString(secondNode) + ":" + speed); /** keep the settlements with the best speed */ if ((speed < bestSpeed) || (secondSettlement < 0)) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); int[] rolls = estimate.getEstimatesFromNothingFast(ports); sb = new StringBuffer(); sb.append("road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("bestSpeed = " + bestSpeed); } else if (speed == bestSpeed) { if (probTotal > bestProbTotal) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); int[] rolls = estimate.getEstimatesFromNothingFast(ports); sb = new StringBuffer(); sb.append("road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("bestSpeed = " + bestSpeed); } } } // for (i in ourPotentialSettlements[]) return secondSettlement; }
/** * figure out where to place the two settlements * * @return {@link #firstSettlement}, or 0 if no potential settlements for our player */ public int planInitialSettlements() { log.debug("--- planInitialSettlements"); int speed; boolean allTheWay; firstSettlement = 0; secondSettlement = 0; int bestSpeed = 4 * SOCBuildingSpeedEstimate.DEFAULT_ROLL_LIMIT; SOCBoard board = game.getBoard(); SOCResourceSet emptySet = new SOCResourceSet(); SOCPlayerNumbers playerNumbers = new SOCPlayerNumbers(board); int probTotal; int bestProbTotal; boolean[] ports = new boolean[SOCBoard.WOOD_PORT + 1]; SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate(); final int[] prob = SOCNumberProbabilities.INT_VALUES; bestProbTotal = 0; final int[] ourPotentialSettlements = ourPlayerData.getPotentialSettlements_arr(); if (ourPotentialSettlements == null) return 0; // Should not occur for (int i = 0; i < ourPotentialSettlements.length; ++i) { final int firstNode = ourPotentialSettlements[i]; // assert: ourPlayerData.isPotentialSettlement(firstNode) final Integer firstNodeInt = new Integer(firstNode); // // this is just for testing purposes // log.debug("FIRST NODE -----------"); log.debug("firstNode = " + board.nodeCoordToString(firstNode)); StringBuffer sb = new StringBuffer(); sb.append("numbers:["); playerNumbers.clear(); probTotal = playerNumbers.updateNumbersAndProbability(firstNode, board, prob, sb); sb.append("]"); log.debug(sb.toString()); sb = new StringBuffer(); sb.append("ports: "); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { ports[portType] = (board.getPortCoordinates(portType).contains(firstNodeInt)); sb.append(ports[portType] + " "); } log.debug(sb.toString()); log.debug("probTotal = " + probTotal); estimate.recalculateEstimates(playerNumbers); speed = 0; allTheWay = false; try { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.SETTLEMENT_SET, 300, ports) .getRolls(); speed += estimate.calculateRollsAndRsrcFast(emptySet, SOCGame.CITY_SET, 300, ports).getRolls(); speed += estimate.calculateRollsAndRsrcFast(emptySet, SOCGame.CARD_SET, 300, ports).getRolls(); speed += estimate.calculateRollsAndRsrcFast(emptySet, SOCGame.ROAD_SET, 300, ports).getRolls(); } catch (CutoffExceededException e) { } if (D.ebugOn) { final int[] rolls = estimate.getEstimatesFromNothingFast(ports, 300); sb = new StringBuffer(); sb.append(" road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("speed = " + speed); } // // end test // // // calculate pairs of first and second settlement together // for (int j = 1 + i; j < ourPotentialSettlements.length; ++j) { final int secondNode = ourPotentialSettlements[j]; // assert: ourPlayerData.isPotentialSettlement(secondNode) if (board.isNodeAdjacentToNode(secondNode, firstNode)) continue; // <-- too close to firstNode to build -- log.debug("firstNode = " + board.nodeCoordToString(firstNode)); log.debug("secondNode = " + board.nodeCoordToString(secondNode)); /** get the numbers for these settlements */ sb = new StringBuffer(); sb.append("numbers:["); playerNumbers.clear(); probTotal = playerNumbers.updateNumbersAndProbability(firstNode, board, prob, sb); sb.append("] ["); probTotal += playerNumbers.updateNumbersAndProbability(secondNode, board, prob, sb); sb.append("]"); log.debug(sb.toString()); /** see if the settlements are on any ports */ // sb = new StringBuffer(); // sb.append("ports: "); Arrays.fill(ports, false); int portType = board.getPortTypeFromNodeCoord(firstNode); if (portType != -1) ports[portType] = true; portType = board.getPortTypeFromNodeCoord(secondNode); if (portType != -1) ports[portType] = true; // log.debug(sb.toString()); log.debug("probTotal = " + probTotal); /** estimate the building speed for this pair */ estimate.recalculateEstimates(playerNumbers); speed = 0; allTheWay = false; try { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports) .getRolls(); if (speed < bestSpeed) { speed += estimate .calculateRollsAndRsrcFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports) .getRolls(); allTheWay = true; } } } // because of addition, speed might be as much as (bestSpeed - 1) + bestSpeed } catch (CutoffExceededException e) { speed = bestSpeed; } if (D.ebugOn) { final int[] rolls = estimate.getEstimatesFromNothingFast(ports, bestSpeed); sb = new StringBuffer(); sb.append(" road: " + rolls[SOCBuildingSpeedEstimate.ROAD]); sb.append(" stlmt: " + rolls[SOCBuildingSpeedEstimate.SETTLEMENT]); sb.append(" city: " + rolls[SOCBuildingSpeedEstimate.CITY]); sb.append(" card: " + rolls[SOCBuildingSpeedEstimate.CARD]); log.debug(sb.toString()); log.debug("allTheWay = " + allTheWay); log.debug("speed = " + speed); } /** keep the settlements with the best speed */ if (speed < bestSpeed) { firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("bestSpeed = " + bestSpeed); log.debug("bestProbTotal = " + bestProbTotal); } else if ((speed == bestSpeed) && allTheWay) { if (probTotal > bestProbTotal) { log.debug("Equal speed, better prob"); firstSettlement = firstNode; secondSettlement = secondNode; bestSpeed = speed; bestProbTotal = probTotal; log.debug("firstSettlement = " + Integer.toHexString(firstSettlement)); log.debug("secondSettlement = " + Integer.toHexString(secondSettlement)); log.debug("bestSpeed = " + bestSpeed); log.debug("bestProbTotal = " + bestProbTotal); } } } // for (j past i in ourPotentialSettlements[]) } // for (i in ourPotentialSettlements[]) /** choose which settlement to place first */ playerNumbers.clear(); playerNumbers.updateNumbers(firstSettlement, board); final Integer firstSettlementInt = new Integer(firstSettlement); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { ports[portType] = (board.getPortCoordinates(portType).contains(firstSettlementInt)); } estimate.recalculateEstimates(playerNumbers); int firstSpeed = 0; final int cutoff = 100; firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, cutoff, ports); firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CITY_SET, cutoff, ports); firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CARD_SET, cutoff, ports); firstSpeed += estimate.calculateRollsFast(emptySet, SOCGame.ROAD_SET, cutoff, ports); playerNumbers.clear(); playerNumbers.updateNumbers(secondSettlement, board); final Integer secondSettlementInt = new Integer(secondSettlement); for (int portType = SOCBoard.MISC_PORT; portType <= SOCBoard.WOOD_PORT; portType++) { ports[portType] = (board.getPortCoordinates(portType).contains(secondSettlementInt)); } estimate.recalculateEstimates(playerNumbers); int secondSpeed = 0; secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.SETTLEMENT_SET, bestSpeed, ports); secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CITY_SET, bestSpeed, ports); secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.CARD_SET, bestSpeed, ports); secondSpeed += estimate.calculateRollsFast(emptySet, SOCGame.ROAD_SET, bestSpeed, ports); if (firstSpeed > secondSpeed) { int tmp = firstSettlement; firstSettlement = secondSettlement; secondSettlement = tmp; } log.debug( board.nodeCoordToString(firstSettlement) + ":" + firstSpeed + ", " + board.nodeCoordToString(secondSettlement) + ":" + secondSpeed); return firstSettlement; }