@Override
  public Result solve(TaskDefinition task, ProgressListener listener) {

    long startTime = System.nanoTime();

    /* initial nests */
    nests = new ArrayList<Nest>(config.getNestNumber());
    for (int i = 0; i < config.getNestNumber(); i++) {
      Nest nest = new Nest(random, task.getJobCount());
      nests.add(nest); // jobCount <=> solution (egg) size
      nest.setFitness(computeMakespan(task, nest.getEgg()));
    }

    Nest bestSoFar = getBestNest();
    int iterationsUntilResult = 0;

    for (int t = 1; t <= config.getMaxIterations(); t++) {

      int jIndex = random.nextInt(config.getNestNumber());
      Nest jNest = nests.get(jIndex);

      Nest nestWithCuckooEgg = new NestWithCuckooEgg(jNest);

      nestWithCuckooEgg.setFitness(computeMakespan(task, nestWithCuckooEgg.getEgg()));

      if (nestWithCuckooEgg.getFitness() > jNest.getFitness()) {
        nests.remove(jIndex);
        nests.add(nestWithCuckooEgg);
      }

      // With given probability we will abandon our worst nest and replace with new nests
      if (random.nextDouble() < config.getDiscoveryProbability()) {

        Collections.sort(nests, new Comparator<Nest>() {
            @Override
            public int compare(Nest o1, Nest o2) {
            return o2.getFitness() - o1.getFitness();
            }
            });

        ArrayList<Nest> replacementNests = new ArrayList<Nest>(config.getNestsToAbandonNumber());
        for (int i = 0; i < config.getNestsToAbandonNumber(); ++i) {
          Nest nest = new Nest(random, task.getJobCount());
          replacementNests.add(nest); 
          nest.setFitness(computeMakespan(task, nest.getEgg()));  
        }

        nests.subList(0, config.getNestsToAbandonNumber()).clear();
        nests.addAll(replacementNests);
      } 


      Nest bestNow = getBestNest();
      if (bestNow.getFitness() < bestSoFar.getFitness()) {
        bestSoFar = bestNow;
        iterationsUntilResult = t;
      }

      int fivePercentGens = config.getMaxIterations() / 20;
      if (t % fivePercentGens == 1) {
        int resultSoFar = bestSoFar.getFitness();
        listener.onProgress(t / fivePercentGens * 5, resultSoFar);
      }

    }

    Collections.sort(nests, new Comparator<Nest>() {
      @Override
      public int compare(Nest o1, Nest o2) {
        return o1.getFitness() - o2.getFitness(); // reverse to above
      }
    });



    double computationTime = (System.nanoTime() - startTime) / 1e9;

    Result r = new Result();          
    r.setExecutionTimespan(bestSoFar.getFitness());
    r.setComputationTime(computationTime);
    r.setIterationsUntilResult(iterationsUntilResult);

    int[] order = bestSoFar.getEgg();
    for (int i = 0; i < order.length; i++)
      order[i]++;
    r.setJobOrder(order);

    return r;
  }