public CameraPlacementState getBestSuccessor() {
    this.setScore();
    // Generate a successor, test successor, keep highest-scoring successor
    CameraPlacementState best = this;
    CameraPlacementState challenger = null;

    // Try all the spin possibilities:
    for (int c = 0; c < cameraLocations.size(); c++) {
      System.out.println("On rotation, camera " + c);
      for (int orient = 0; orient < 360; orient++) {
        Node newCam = cameraLocations.get(c).clone();
        newCam.setOri(orient);
        List<Node> newCamList = new ArrayList<Node>();
        for (int copy = 0; copy < cameraLocations.size(); copy++) {
          if (c != copy) {
            newCamList.add(cameraLocations.get(copy));
          }
        }
        newCamList.add(newCam);

        challenger = new CameraPlacementState(plans, newCamList);

        challenger.setScore();

        if (challenger.getScore() > best.getScore()) {
          best = challenger;
          System.out.println("New best: " + best.getScore());
        }
      }
    }

    // Try all new location possibilities:
    List<Node> possibleMoves = this.calculatePossibleLocations();
    for (int c = 0; c < cameraLocations.size(); c++) {
      System.out.println("On relocation, camera " + c);
      for (Node poss : possibleMoves) {
        Node newCam = cameraLocations.get(c).clone();
        newCam.x = poss.x;
        newCam.y = poss.y;
        List<Node> newCamList = new ArrayList<Node>();
        for (int copy = 0; copy < cameraLocations.size(); copy++) {
          if (c != copy) {
            newCamList.add(cameraLocations.get(copy));
          }
        }
        newCamList.add(newCam);

        challenger = new CameraPlacementState(plans, newCamList);

        challenger.setScore();

        if (challenger.getScore() > best.getScore()) {
          best = challenger;
          System.out.println("New best: " + best.getScore());
        }
      }
    }
    if (best == this) {
      return null;
    }
    return best;
  }
  private CameraPlacementState improveSingleCamera(Node camera) {
    // Motivation: We waste a lot of time calculating for cameras that are, for the moment,
    // "complete"
    // So, let's narrow the focus of the algorithm to one camera, so we skip unnecessary
    // calculations
    // We'll be using the Best-Choice algorithm to optimize this camera.
    this.setScore();
    // Generate a successor, test successor, keep highest-scoring successor
    CameraPlacementState best = this;
    CameraPlacementState challenger = null;

    // Try all the spin possibilities:
    //            System.out.println("On rotation, camera "+c);
    for (int orient = 0; orient < 360; orient++) {
      Node newCam = camera.clone();
      newCam.setOri(orient);
      List<Node> newCamList = new ArrayList<Node>();
      for (int copy = 0; copy < cameraLocations.size(); copy++) {
        if (!camera.equals(cameraLocations.get(copy))) {
          newCamList.add(cameraLocations.get(copy));
        }
      }
      newCamList.add(newCam);

      challenger = new CameraPlacementState(plans, newCamList);

      challenger.setScore();

      if (challenger.getScore() > best.getScore()) {
        best = challenger;
        System.out.println("New best: " + best.getScore());
        //                    return best;
      }
    }

    // Try all new location possibilities:
    List<Node> possibleMoves = this.calculatePossibleLocations();
    //            System.out.println("On relocation, camera "+c);
    for (Node poss : possibleMoves) {
      Node newCam = camera.clone();
      newCam.x = poss.x;
      newCam.y = poss.y;
      List<Node> newCamList = new ArrayList<Node>();
      for (int copy = 0; copy < cameraLocations.size(); copy++) {
        if (!camera.equals(cameraLocations.get(copy))) {
          newCamList.add(cameraLocations.get(copy));
        }
      }
      newCamList.add(newCam);

      challenger = new CameraPlacementState(plans, newCamList);

      challenger.setScore();

      if (challenger.getScore() > best.getScore()) {
        best = challenger;
        System.out.println("New best: " + best.getScore());
        //                    return best;
      }
    }
    if (best == this) {
      return null;
    }
    return best;
  }