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