/** 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; }
/** * 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; }