public List<Move> createMoveList(NurseRoster nurseRoster) {
    List<Employee> employeeList = nurseRoster.getEmployeeList();
    // This code assumes the shiftAssignmentList is sorted
    // Filter out every immovable ShiftAssignment
    List<ShiftAssignment> shiftAssignmentList =
        new ArrayList<ShiftAssignment>(nurseRoster.getShiftAssignmentList());
    for (Iterator<ShiftAssignment> it = shiftAssignmentList.iterator(); it.hasNext(); ) {
      ShiftAssignment shiftAssignment = it.next();
      if (!filter.accept(nurseRoster, shiftAssignment)) {
        it.remove();
      }
    }

    // Hash the assignments per employee
    Map<Employee, List<AssignmentSequence>> employeeToAssignmentSequenceListMap =
        new HashMap<Employee, List<AssignmentSequence>>(employeeList.size());
    int assignmentSequenceCapacity = nurseRoster.getShiftDateList().size() + 1 / 2;
    for (Employee employee : employeeList) {
      employeeToAssignmentSequenceListMap.put(
          employee, new ArrayList<AssignmentSequence>(assignmentSequenceCapacity));
    }
    for (ShiftAssignment shiftAssignment : shiftAssignmentList) {
      Employee employee = shiftAssignment.getEmployee();
      List<AssignmentSequence> assignmentSequenceList =
          employeeToAssignmentSequenceListMap.get(employee);
      if (assignmentSequenceList.isEmpty()) {
        AssignmentSequence assignmentSequence = new AssignmentSequence(shiftAssignment);
        assignmentSequenceList.add(assignmentSequence);
      } else {
        AssignmentSequence lastAssignmentSequence =
            assignmentSequenceList // getLast()
                .get(assignmentSequenceList.size() - 1);
        if (lastAssignmentSequence.belongsHere(shiftAssignment)) {
          lastAssignmentSequence.add(shiftAssignment);
        } else {
          AssignmentSequence assignmentSequence = new AssignmentSequence(shiftAssignment);
          assignmentSequenceList.add(assignmentSequence);
        }
      }
    }

    // The create the move list
    List<Move> moveList = new ArrayList<Move>();
    // For every 2 distinct employees
    for (ListIterator<Employee> leftEmployeeIt = employeeList.listIterator();
        leftEmployeeIt.hasNext(); ) {
      Employee leftEmployee = leftEmployeeIt.next();
      List<AssignmentSequence> leftAssignmentSequenceList =
          employeeToAssignmentSequenceListMap.get(leftEmployee);
      for (ListIterator<Employee> rightEmployeeIt =
              employeeList.listIterator(leftEmployeeIt.nextIndex());
          rightEmployeeIt.hasNext(); ) {
        Employee rightEmployee = rightEmployeeIt.next();
        List<AssignmentSequence> rightAssignmentSequenceList =
            employeeToAssignmentSequenceListMap.get(rightEmployee);

        final int SWITCH_LENGTH = 3;
        for (AssignmentSequence leftAssignmentSequence : leftAssignmentSequenceList) {
          List<ShiftAssignment> leftShiftAssignmentList =
              leftAssignmentSequence.getShiftAssignmentList();
          for (int leftIndex = 0;
              leftIndex <= leftShiftAssignmentList.size() - SWITCH_LENGTH;
              leftIndex++) {

            for (AssignmentSequence rightAssignmentSequence : rightAssignmentSequenceList) {
              List<ShiftAssignment> rightShiftAssignmentList =
                  rightAssignmentSequence.getShiftAssignmentList();
              for (int rightIndex = 0;
                  rightIndex <= rightShiftAssignmentList.size() - SWITCH_LENGTH;
                  rightIndex++) {

                List<Move> subMoveList = new ArrayList<Move>(SWITCH_LENGTH * 2);
                for (ShiftAssignment leftShiftAssignment :
                    leftShiftAssignmentList.subList(leftIndex, leftIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new EmployeeChangeMove(leftShiftAssignment, rightEmployee));
                }
                for (ShiftAssignment rightShiftAssignment :
                    rightShiftAssignmentList.subList(rightIndex, rightIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new EmployeeChangeMove(rightShiftAssignment, leftEmployee));
                }
                moveList.add(CompositeMove.buildMove(subMoveList));
              }
            }
          }
        }
      }
    }
    return moveList;
  }
  @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;
  }