/**
   * Takes a table of nodes and adds a weighted score to each node score in the table. Nodes
   * touching hexes with better numbers get better scores. Also numbers that the player isn't
   * touching yet are better than ones that the player is already touching.
   *
   * @param nodes the table of nodes with scores: Hashtable<Integer,Integer> . Contents will
   *     be modified by the scoring.
   * @param player the player that we are doing the rating for, or <tt>null</tt>; will give a bonus
   *     to numbers the player isn't already touching
   * @param weight a number that is multiplied by the score
   */
  protected void bestSpotForNumbers(
      Hashtable<Integer, Integer> nodes, SOCPlayer player, int weight) {
    final int[] numRating = SOCNumberProbabilities.INT_VALUES;
    final SOCPlayerNumbers playerNumbers = (player != null) ? player.getNumbers() : null;
    final SOCBoard board = game.getBoard();

    // 80 is highest practical score (40 if player == null)
    final int maxScore = (player != null) ? 80 : 40;

    int oldScore;
    Enumeration<Integer> nodesEnum = nodes.keys();

    while (nodesEnum.hasMoreElements()) {
      final Integer node = nodesEnum.nextElement();

      // log.debug("BSN - looking at node "+Integer.toHexString(node.intValue()));
      oldScore = nodes.get(node).intValue();

      int score = 0;
      Enumeration<Integer> hexesEnum = board.getAdjacentHexesToNode(node.intValue()).elements();

      while (hexesEnum.hasMoreElements()) {
        final int hex = hexesEnum.nextElement().intValue();
        final int number = board.getNumberOnHexFromCoord(hex);
        score += numRating[number];

        if ((number != 0) && (playerNumbers != null) && !playerNumbers.hasNumber(number)) {
          /** add a bonus for numbers that the player doesn't already have */

          // log.debug("ADDING BONUS FOR NOT HAVING "+number);
          score += numRating[number];
        }

        // log.debug(" -- -- Adding "+numRating[board.getNumberOnHexFromCoord(hex)]);
      }

      /*
       * normalize score and multiply by weight
       * 80 is highest practical score (40 if player == null)
       * lowest score is 0
       */
      final int nScore = ((score * 100) / maxScore) * weight;
      final Integer finalScore = new Integer(nScore + oldScore);
      nodes.put(node, finalScore);

      // log.debug("BSN -- put node "+Integer.toHexString(node.intValue())+" with old score
      // "+oldScore+" + new score "+nScore);
    }
  }
  /**
   * Estimate the rolls for this player to obtain each resource. Will construct a
   * <tt>SOCBuildingSpeedEstimate</tt> from {@link SOCPlayer#getNumbers() pl.getNumbers()}, and call
   * {@link #getRollsPerResource()}.
   *
   * @param pl Player to check numbers
   * @return Resource order, sorted by rolls per resource descending; a 5-element array containing
   *     {@link SOCResourceConstants#CLAY}, {@link SOCResourceConstants#WHEAT}, etc, where the
   *     resource in [0] has the highest rolls per resource.
   * @since 2.0.00
   */
  public static final int[] getRollsForResourcesSorted(final SOCPlayer pl) {
    SOCBuildingSpeedEstimate estimate = new SOCBuildingSpeedEstimate(pl.getNumbers());
    final int[] rollsPerResource = estimate.getRollsPerResource();
    int[] resourceOrder = {
      SOCResourceConstants.CLAY, SOCResourceConstants.ORE,
      SOCResourceConstants.SHEEP, SOCResourceConstants.WHEAT,
      SOCResourceConstants.WOOD
    };

    // Sort descending; resourceOrder[0] will have the highest rollsPerResource.
    for (int j = 4; j >= 0; j--) {
      for (int i = 0; i < j; i++) {
        if (rollsPerResource[resourceOrder[i]] < rollsPerResource[resourceOrder[i + 1]]) {
          int tmp = resourceOrder[i];
          resourceOrder[i] = resourceOrder[i + 1];
          resourceOrder[i + 1] = tmp;
        }
      }
    }

    return resourceOrder;
  }