private void add(CourseAssignment courseAssignment) {
   courseAssignmentList.add(courseAssignment);
   int dayIndex = courseAssignment.getCourseDayDayIndex();
   if (dayIndex < lastDayIndex) {
     throw new IllegalStateException(
         "The courseAssignmentList is expected to be sorted by courseDay.");
   }
   lastDayIndex = dayIndex;
 }
  @Override
  public List<Move> createMoveList(TaRoster taRoster) {
    List<Ta> taList = taRoster.getTaList();
    // This code assumes the courseAssignmentList is sorted
    // Filter out every immovable CourseAssignment
    List<CourseAssignment> courseAssignmentList =
        new ArrayList<>(taRoster.getCourseAssignmentList());

    // Hash the assignments per ta
    Map<Ta, List<AssignmentSequence>> taToAssignmentSequenceListMap = new HashMap<>(taList.size());
    int assignmentSequenceCapacity = taRoster.getCourseDayList().size() + 1 / 2;
    for (Ta ta : taList) {
      taToAssignmentSequenceListMap.put(
          ta, new ArrayList<AssignmentSequence>(assignmentSequenceCapacity));
    }
    for (CourseAssignment courseAssignment : courseAssignmentList) {
      Ta ta = courseAssignment.getTa();
      List<AssignmentSequence> assignmentSequenceList = taToAssignmentSequenceListMap.get(ta);
      if (assignmentSequenceList.isEmpty()) {
        AssignmentSequence assignmentSequence = new AssignmentSequence(courseAssignment);
        assignmentSequenceList.add(assignmentSequence);
      } else {
        AssignmentSequence lastAssignmentSequence =
            assignmentSequenceList // getLast()
                .get(assignmentSequenceList.size() - 1);
        if (lastAssignmentSequence.belongsHere(courseAssignment)) {
          lastAssignmentSequence.add(courseAssignment);
        } else {
          AssignmentSequence assignmentSequence = new AssignmentSequence(courseAssignment);
          assignmentSequenceList.add(assignmentSequence);
        }
      }
    }

    // The create the move list
    List<Move> moveList = new ArrayList<>();
    // For every 2 distinct tas
    for (ListIterator<Ta> leftTaIt = taList.listIterator(); leftTaIt.hasNext(); ) {
      Ta leftTa = leftTaIt.next();
      List<AssignmentSequence> leftAssignmentSequenceList =
          taToAssignmentSequenceListMap.get(leftTa);
      for (ListIterator<Ta> rightTaIt = taList.listIterator(leftTaIt.nextIndex());
          rightTaIt.hasNext(); ) {
        Ta rightTa = rightTaIt.next();
        List<AssignmentSequence> rightAssignmentSequenceList =
            taToAssignmentSequenceListMap.get(rightTa);

        final int SWITCH_LENGTH = 3;
        for (AssignmentSequence leftAssignmentSequence : leftAssignmentSequenceList) {
          List<CourseAssignment> leftCourseAssignmentList =
              leftAssignmentSequence.getCourseAssignmentList();
          for (int leftIndex = 0;
              leftIndex <= leftCourseAssignmentList.size() - SWITCH_LENGTH;
              leftIndex++) {

            for (AssignmentSequence rightAssignmentSequence : rightAssignmentSequenceList) {
              List<CourseAssignment> rightCourseAssignmentList =
                  rightAssignmentSequence.getCourseAssignmentList();
              for (int rightIndex = 0;
                  rightIndex <= rightCourseAssignmentList.size() - SWITCH_LENGTH;
                  rightIndex++) {

                List<Move> subMoveList = new ArrayList<>(SWITCH_LENGTH * 2);
                for (CourseAssignment leftCourseAssignment :
                    leftCourseAssignmentList.subList(leftIndex, leftIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new TaChangeMove(leftCourseAssignment, rightTa));
                }
                for (CourseAssignment rightCourseAssignment :
                    rightCourseAssignmentList.subList(rightIndex, rightIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new TaChangeMove(rightCourseAssignment, leftTa));
                }
                moveList.add(CompositeMove.buildMove(subMoveList));
              }
            }
          }
        }
      }
    }
    return moveList;
  }
 private boolean belongsHere(CourseAssignment courseAssignment) {
   return courseAssignment.getCourseDayDayIndex() <= (lastDayIndex + 1);
 }
 private AssignmentSequence(CourseAssignment courseAssignment) {
   courseAssignmentList = new ArrayList<>();
   courseAssignmentList.add(courseAssignment);
   firstDayIndex = courseAssignment.getCourseDayDayIndex();
   lastDayIndex = firstDayIndex;
 }