/** * Estimate the rarity of each resource, given this board's resource locations vs dice numbers. * Useful for initial settlement placement and free-resource choice (when no other info * available). This is based on the board and doesn't change when pieces are placed. Cached after * the first call, as {@link #resourceEstimates}. * * <p>Calls each hex's {@link SOCBoard#getHexTypeFromCoord(int)}, ignores all hex types besides * the usual {@link SOCBoard#CLAY_HEX} through {@link SOCBoard#WOOD_HEX} and {@link * SOCBoardLarge#GOLD_HEX}. * * @return an array of rarity numbers, where estimates[SOCBoard.CLAY_HEX] == the clay rarity, as * an integer percentage 0-100 of dice rolls. */ public int[] estimateResourceRarity() { if (resourceEstimates == null) { final SOCBoard board = game.getBoard(); final int[] numberWeights = SOCNumberProbabilities.INT_VALUES; resourceEstimates = new int[SOCResourceConstants.UNKNOWN]; // uses 1 to 5 (CLAY to WOOD) resourceEstimates[0] = 0; // look at each hex if (board.getBoardEncodingFormat() <= SOCBoard.BOARD_ENCODING_6PLAYER) { // v1 or v2 encoding final int L = board.getNumberLayout().length; for (int i = 0; i < L; i++) { final int hexNumber = board.getNumberOnHexFromNumber(i); if (hexNumber > 0) resourceEstimates[board.getHexTypeFromNumber(i)] += numberWeights[hexNumber]; } } else { // v3 encoding final int[] hcoord = board.getLandHexCoords(); if (hcoord != null) { final int L = hcoord.length; for (int i = 0; i < L; i++) { final int hexNumber = board.getNumberOnHexFromCoord(hcoord[i]); if (hexNumber == 0) continue; final int htype = board.getHexTypeFromCoord(hcoord[i]); if (htype == SOCBoardLarge.GOLD_HEX) { // Count gold as all resource types for (int ht = SOCBoard.CLAY_HEX; ht <= SOCBoard.WOOD_HEX; ++ht) resourceEstimates[ht] += numberWeights[hexNumber]; } else if ((htype >= 0) && (htype <= SOCBoard.WOOD_HEX)) { resourceEstimates[htype] += numberWeights[hexNumber]; } } } } } // D.ebugPrint("Resource Estimates = "); // for (int i = 1; i < 6; i++) // { // D.ebugPrint(i+":"+resourceEstimates[i]+" "); // } // log.debug(); return resourceEstimates; }
/** 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; }