code: package tracks.singlePlayer.advanced.sampleRHEA;
  import java.util.Random;
  
  public class Individual implements Comparable{
  
      protected int[] actions; // actions in individual. length of individual = actions.length
      private int nLegalActions; // number of legal actions
      protected double value;
      private Random gen;
  
      Individual(int L, int nLegalActions, Random gen) {
          actions = new int[L];
          for (int i = 0; i < L; i++) {
              actions[i] = gen.nextInt(nLegalActions);
          }
          this.nLegalActions = nLegalActions;
          this.gen = gen;
      }
  
      public void setActions (int[] a) {
          System.arraycopy(a, 0, actions, 0, a.length);
      }
  
      /**
       * Returns new individual
       * @param MUT - number of genes to mutate
       * @return - new individual, mutated from this
       */
      Individual mutate(int MUT) {
          Individual b = this.copy();
          b.setActions(actions);
  
          int count = 0;
          if (nLegalActions > 1) { // make sure you can actually mutate
              while (count < MUT) {
                  int a; // index of action to mutate
  
                  // random mutation of one action
                  a = gen.nextInt(b.actions.length);
  
                  int s;
                  s = gen.nextInt(nLegalActions); // find new action
                  b.actions[a] = s;
  
                  count++;
              }
          }
  
          return b;
      }
  
      /**
       * Modifies individual
       * @param CROSSOVER_TYPE - type of crossover
       */
      public void crossover (Individual parent1, Individual parent2, int CROSSOVER_TYPE) {
          if (CROSSOVER_TYPE == Agent.POINT1_CROSS) {
              // 1-point
              int p = gen.nextInt(actions.length - 3) + 1;
              for ( int i = 0; i < actions.length; i++) {
                  if (i < p)
                      actions[i] = parent1.actions[i];
                  else
                      actions[i] = parent2.actions[i];
              }
  
          } else if (CROSSOVER_TYPE == Agent.UNIFORM_CROSS) {
              // uniform
              for (int i = 0; i < actions.length; i++) {
                  if (gen.nextFloat() >= 0.5)
                      actions[i] = parent1.actions[i];
                  else
                      actions[i] = parent2.actions[i];
              }
          }
      }
  
      @Override
      public int compareTo(Object o) {
          Individual a = this;
          Individual b = (Individual)o;
          return Double.compare(b.value, a.value);
      }
  
      @Override
      public boolean equals(Object o) {
          if (!(o instanceof Individual)) return false;
  
          Individual a = this;
          Individual b = (Individual)o;
  
          for (int i = 0; i < actions.length; i++) {
              if (a.actions[i] != b.actions[i]) return false;
          }
  
          return true;
      }
  
      public Individual copy () {
          Individual a = new Individual(this.actions.length, this.nLegalActions, this.gen);
          a.value = this.value;
          a.setActions(this.actions);
  
          return a;
      }
  
      @Override
      public String toString() {
          StringBuilder s = new StringBuilder("" + value + ": ");
          for (int action : actions) s.append(action).append(" ");
          return s.toString();
      }
  }
  