code: private int greedyMoves(int n, SubsetNeighbourhood neigh){
          int applied = 0;
          boolean cont = true;
          while(applied < n && cont){
              // go through all moves to find the best one
              Move<? super SubsetSolution> bestMove = null;
              double bestDelta = -Double.MAX_VALUE, delta;
              Evaluation newEvaluation, bestEvaluation = null;
              SubsetValidation newValidation, bestValidation = null;
              for(Move<? super SubsetSolution> move : neigh.getAllMoves(getCurrentSolution())){
                  // validate move (IMPORTANT: ignore current subset size)
                  newValidation = getProblem().validate(move, getCurrentSolution(), getCurrentSolutionValidation());
                  if(newValidation.passed(false)){
                      // evaluate move
                      newEvaluation = getProblem().evaluate(move, getCurrentSolution(), getCurrentSolutionEvaluation());
                      // compute delta
                      delta = computeDelta(newEvaluation, getCurrentSolutionEvaluation());
                      // new best move?
                      if(delta > bestDelta){
                          bestDelta = delta;
                          bestMove = move;
                          bestEvaluation = newEvaluation;
                          bestValidation = newValidation;
                      }
                  }
              }
              // apply best move, if any
              if(bestMove != null){
                  // apply move
                  bestMove.apply(getCurrentSolution());
                  // update current and best solution (NOTe: best solution will only be updated
                  // if it is fully valid, also taking into account the current subset size)
                  updateCurrentAndBestSolution(getCurrentSolution(), bestEvaluation, bestValidation);
                  // increase counter
                  applied++;
              } else {
                  // no valid move found, stop
                  cont = false;
              }
          }
          // return actual number of applied moves
          return applied;
      }
docs: Greedily apply a series of n moves generated by the given neighbourhood, where the move yielding the most
  improvement (or smallest decline) is iteratively selected. Returns the actual number of performed moves,
  which is always lower than or equal to the requested number of moves. It may be strictly lower in case
  no more moves can be applied at some point.
  
  @param n number of requested moves
  @return actual number of applied moves, lower than or equal to requested number of moves