// Adds the position and it's estimated utility to the table.
  // If the position is already in the table (which will happen sometimes), It will either update.
  public void addPositionToListOfAnalysedPositions(
      int key[], boolean isDarkPlayerCurrentTurn, int curdepth, double utility) {

    boolean alreadyDidPos = false;
    AnalysedPosition alreadyAnalysedPos = null;

    // check if the position has been inserted after doing the recursion:
    if (viewedPos != null) {
      alreadyAnalysedPos = viewedPos.search(key);
      if (alreadyAnalysedPos != null) {
        alreadyDidPos = true;
      }
    }

    // If the position is not already done:
    if (alreadyDidPos == false) {
      AnalysedPosition pos = new AnalysedPosition(curdepth, isDarkPlayerCurrentTurn, utility, key);
      viewedPos = BalancedSearchTree.addValueToTree(viewedPos, pos);

      // FOR TEST PURPOSES
      numPosRecorded++;
      // TESTING SLOW
      if (debug) {
        sanityCheckNumNodes();
        viewedPos.sanityCheckSorted();
      }
      // END TESTING

      // if we only need to update:
    } else {
      alreadyAnalysedPos.updatePositionWithImprovedCalculation(curdepth, utility);
    }
  }
  public Move get1stMove(
      Game game, CheckersSetup setup, checkersSetup.Board board, ArrayList<Move> choices) {
    // BasicCheckersAIFunctions.delayCompALittle();

    // start fresh after every turn:
    viewedPos = null;
    // TESTING
    numPosRecorded = 0;
    // END TESTING

    numJumpsAlreadyDoneThisTurn = 0;

    BasicCheckersAIFunctions.printAllAIPlayerOptions(setup, isDarkPlayer);

    desiredTurn = getBestMoveBasedOnSearchOfDepthN(setup, isDarkPlayer, this.depth);

    ArrayList<Move> desiredMoves = desiredTurn.getMovesFor1Turn();

    BasicCheckersAIFunctions.PrintDesiredMoves(desiredMoves);

    if (desiredMoves.get(0).isJump()) {
      numJumpsAlreadyDoneThisTurn++;
    }

    // TESTING (Display)
    System.out.println("Number of positions analysed for AI with Tree: " + numPosRecorded);
    if (viewedPos != null) {
      System.out.println("Height of tree: " + viewedPos.getHeightOfTree());
    }
    System.out.println();
    // END TESTING

    return desiredMoves.get(0);
  }
 // testing: MAKE SURE THAT THE KEY STAYS THE SAME!!!
 public void sanityTestKeyBeforeAndAfter(
     CheckersSetup setup, boolean isDarkPlayerCurrentTurn, int key[]) {
   int key2[] = AnalysedPosition.makeKey(setup, isDarkPlayerCurrentTurn);
   int compare = BalancedSearchTree.compare(key, key2);
   if (compare != 0) {
     System.out.println("ERROR: the board changes through the getEstUtilityOfPosition function.");
     System.exit(1);
   }
 }
  public Double getUtilityIfAlreadyFound(int key[], int curdepth) {

    if (viewedPos != null) {
      AnalysedPosition alreadyAnalysedPos = viewedPos.search(key);
      if (alreadyAnalysedPos != null && alreadyAnalysedPos.getDepth() >= curdepth) {
        return new Double(alreadyAnalysedPos.getUtility());
      }
    }
    return null;
  }
 // Testing: make sure the number of nodes in the tree is the same as the amount put in:
 public void sanityCheckNumNodes() {
   int sanity = viewedPos.sanityCheckGetNumberOfNodes();
   if (sanity != numPosRecorded) {
     System.err.println(
         "ERROR: the number of nodes in the tree is not equal to the number of nodes added. #Added: "
             + numPosRecorded
             + " number received: "
             + sanity);
     System.exit(1);
   }
 }
 // testing: make sure that the position didn't suddenly get on the list.
 public void sanityTestPositionDidntDissapearOffTree(
     AnalysedPosition alreadyAnalysedPos, int key[], boolean alreadyDidPos, int curdepth) {
   // note: this should not happen within this function.
   if (viewedPos != null) {
     alreadyAnalysedPos = viewedPos.search(key);
     if (alreadyAnalysedPos != null && alreadyDidPos == false) {
       if (alreadyAnalysedPos.getDepth() >= curdepth) {
         System.out.println("ERROR: Position should have been viewable earlier");
         System.exit(1);
       }
     }
   }
 }