code: @Override
      public Move<? super SolutionType> getRandomMove(SolutionType solution, Random rnd) {
          // generate random move for each neighbourhood
          List<Move<? super SolutionType>> moves = new ArrayList<>();
          List<Double> respectiveWeights = new ArrayList<>();
          Move<? super SolutionType> move;
          for(int i=0; i<neighs.size(); i++){
              move = neighs.get(i).getRandomMove(solution, rnd);
              if(move != null){
                  // neighbourhood was able to produce a move
                  moves.add(move);
                  respectiveWeights.add(weights.get(i));
              }
          }
          if(moves.isEmpty()){
              // no moves produced by any neighbourhood
              return null;
          } else {
              // roulette selection to pick a move
              return RouletteSelector.select(moves, respectiveWeights, rnd);
          }
      }
docs: Produces a random move generated by one of the contained neighbourhoods based on the assigned weights.
  First, a random move is requested from each neighbourhood as it may happen that one or more neighbourhoods
  are unable to produce a random move. If no moves are obtained, this method returns <code>null</code>.
  Else, it selects a move through roulette selection based on the weights assigned at construction.
  
  @param solution solution for which a move is generated
  @param rnd source of randomness used to generate random move
  @return random move generated by one of the contained neighbourhoods, which is selected by
  roulette selection based on the assigned weights; <code>null</code> if none of the
  contained neighbourhoods are able to produce a random move