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;
  }
  public List<Move> createMoveList(Solution solution) {
    NurseRoster nurseRoster = (NurseRoster) solution;
    List<Employee> employeeList = nurseRoster.getEmployeeList();
    // This code assumes the shiftAssignmentList is sorted
    List<ShiftAssignment> shiftAssignmentList = nurseRoster.getShiftAssignmentList();

    // 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(employee, 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(employee, 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);

        LowestDayIndexAssignmentSequenceIterator lowestIt =
            new LowestDayIndexAssignmentSequenceIterator(
                leftAssignmentSequenceList, rightAssignmentSequenceList);
        // For every pillar part duo
        while (lowestIt.hasNext()) {
          AssignmentSequence pillarPartAssignmentSequence = lowestIt.next();
          // Note: the initialCapacity is probably to high,
          // which is bad for memory, but the opposite is bad for performance (which is worse)
          List<Move> moveListByPillarPartDuo =
              new ArrayList<Move>(
                  leftAssignmentSequenceList.size() + rightAssignmentSequenceList.size());
          int lastDayIndex = pillarPartAssignmentSequence.getLastDayIndex();
          Employee otherEmployee;
          int leftMinimumFirstDayIndex = Integer.MIN_VALUE;
          int rightMinimumFirstDayIndex = Integer.MIN_VALUE;
          if (lowestIt.isLastNextWasLeft()) {
            otherEmployee = rightEmployee;
            leftMinimumFirstDayIndex = lastDayIndex;
          } else {
            otherEmployee = leftEmployee;
            rightMinimumFirstDayIndex = lastDayIndex;
          }
          moveListByPillarPartDuo.add(
              new EmployeeMultipleChangeMove(
                  pillarPartAssignmentSequence.getEmployee(),
                  pillarPartAssignmentSequence.getShiftAssignmentList(),
                  otherEmployee));
          // For every AssignmentSequence in that pillar part duo
          while (lowestIt.hasNextWithMaximumFirstDayIndexes(
              leftMinimumFirstDayIndex, rightMinimumFirstDayIndex)) {
            pillarPartAssignmentSequence = lowestIt.next();
            lastDayIndex = pillarPartAssignmentSequence.getLastDayIndex();
            if (lowestIt.isLastNextWasLeft()) {
              otherEmployee = rightEmployee;
              leftMinimumFirstDayIndex = Math.max(leftMinimumFirstDayIndex, lastDayIndex);
            } else {
              otherEmployee = leftEmployee;
              rightMinimumFirstDayIndex = Math.max(rightMinimumFirstDayIndex, lastDayIndex);
            }
            moveListByPillarPartDuo.add(
                new EmployeeMultipleChangeMove(
                    pillarPartAssignmentSequence.getEmployee(),
                    pillarPartAssignmentSequence.getShiftAssignmentList(),
                    otherEmployee));
          }
          moveList.add(new CompositeMove(moveListByPillarPartDuo));
        }
      }
    }
    return moveList;
  }