/**
   * this is a function more for convience given a set of nodes, run a bunch of metrics across them
   * to find which one is best for building a settlement
   *
   * @param nodes a hashtable of nodes, the scores in the table will be modified.
   *     Hashtable<Integer,Integer>.
   * @param numberWeight the weight given to nodes on good numbers
   * @param miscPortWeight the weight given to nodes on 3:1 ports
   * @param portWeight the weight given to nodes on good 2:1 ports
   */
  protected void scoreNodesForSettlements(
      Hashtable nodes,
      int numberWeight,
      int miscPortWeight,
      int portWeight,
      SOCGame game,
      SOCPlayer ourPlayerData) {
    /** favor spots with the most high numbers */
    bestSpotForNumbers(nodes, ourPlayerData, numberWeight, game);

    /** favor spots on good ports */
    /** check if this is on a 3:1 ports, only if we don't have one */
    if (!ourPlayerData.getPortFlag(SOCBoard.MISC_PORT)) {
      Vector miscPortNodes = game.getBoard().getPortCoordinates(SOCBoard.MISC_PORT);
      bestSpotInANodeSet(nodes, miscPortNodes, miscPortWeight);
    }

    /** check out good 2:1 ports that we don't have */
    // TODO: this is extremely dangerous as there already exists a variable called resourceEstimates
    int[] resourceEstimates = null;
    resourceEstimates = estimateResourceRarity(game);

    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) && (!ourPlayerData.getPortFlag(portType))) {
        Vector portNodes = game.getBoard().getPortCoordinates(portType);
        int estimatedPortWeight = (resourceEstimates[portType] * portWeight) / 56;
        bestSpotInANodeSet(nodes, portNodes, estimatedPortWeight);
      }
    }
  }
  /**
   * Given a set of nodes, run a bunch of metrics across them to find which one is best for building
   * a settlement.
   *
   * @param nodes a hashtable of nodes; the scores in the table will be modified. Key = coord
   *     Integer; value = score Integer.
   * @param numberWeight the weight given to nodes on good numbers
   * @param miscPortWeight the weight given to nodes on 3:1 ports
   * @param portWeight the weight given to nodes on good 2:1 ports
   */
  protected void scoreNodesForSettlements(
      Hashtable<Integer, Integer> nodes,
      final int numberWeight,
      final int miscPortWeight,
      final int portWeight) {
    /** favor spots with the most high numbers */
    bestSpotForNumbers(nodes, ourPlayerData, numberWeight);

    /** Favor spots on good ports: */
    /** check if this is on a 3:1 ports, only if we don't have one */
    if (!ourPlayerData.getPortFlag(SOCBoard.MISC_PORT)) {
      Vector<Integer> miscPortNodes = game.getBoard().getPortCoordinates(SOCBoard.MISC_PORT);
      bestSpotInANodeSet(nodes, miscPortNodes, miscPortWeight);
    }

    /** check out good 2:1 ports that we don't have and calculate the resourceEstimates field */
    final int[] resourceEstimates = estimateResourceRarity();

    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) && (!ourPlayerData.getPortFlag(portType))) {
        Vector<Integer> portNodes = game.getBoard().getPortCoordinates(portType);
        int estimatedPortWeight = (resourceEstimates[portType] * portWeight) / 56;
        bestSpotInANodeSet(nodes, portNodes, estimatedPortWeight);
      }
    }
  }