javaalgorithmarraylistgenetic-algorithmgenetic

Genetic algorithm: nothing getting added?


I am creating a game that allows two users to compete against each other in a mini-game involving an Army of Troops (e.g; Soldier, Tank, Cavalry), and whoever wins gets awarded the option of optimizing their army with a genetic algorithm.

The maximum army space is 100 units, with a soldier taking up 1 unit, tank (10 units), and cavalry (5 units).

A soldier has a damage rate of 5, a tank has a damage rate of 15, and a cavalry has a damage rate of 10.

My genetic algorithm seeks to maximize total attack value while minimizing space within the army.

public static Army processArmy(Army reference) {

  ArrayList<Army> armyPopulation = new ArrayList<Army>(); // creates population of Armies based on original reference.

  for (int i=0; i<100; i++) {
     Army copy = new Army(reference.getCountry(), 0); // creates a bunch of Armies, copying the original.
     for (int j=0; j<reference.size(); j++) {
        copy.addTroop(reference.getTroop(j)); 
        //System.out.println(copy.size());
     }

     Army generated = new Army(reference.getCountry(), 0); // new Knapsack that will be apart of the population.

     boolean canRun = true;

     while (canRun && (reference.size() <= 100)) { 
        int randomNum = (int)(Math.random() * (((copy.size()-1) + 1))); 
        if ((generated.size() + copy.getTroop(randomNum).getWeight()) < reference.getMaxSize() && (copy.getTroop(randomNum) != null)) {
           generated.addTroop(copy.getTroop(randomNum));
           System.out.println(generated.size());
           copy.removeTroop(randomNum); 
        } else {
           canRun = false;
        }
     }
     armyPopulation.add(generated); 
    }

  int indexOfBest = 0;
  int valueOfBest = 0;
  for(int k=0; k<armyPopulation.size(); k++) { 
        if (armyPopulation.get(k).getTotalAttack() > valueOfBest){
          indexOfBest = k; 
     }         
  }

  Army bestArmy = armyPopulation.get(indexOfBest);      

  System.out.println("Generation 1: Best army has a size of " + bestArmy.size() + " and attack power of " + bestArmy.getTotalAttack()); 

  // Mutation portion of code
  boolean hasNotChanged = true; // has not changed in 100 generations
  int generationsUnchanged = 0;  // counts how many times the previous Army is equal to the newest Army/generated Army
  int stopIt = 0;

  while (hasNotChanged && (generationsUnchanged < 100)) {   
  for (int m=0; m<100; m++) {

     Army copy = new Army(reference.getCountry(), 0); // copy will be an exact copy of reference, which means copy will inititally have all the items in it. It will
                                     // be used as a list for the algorithm to pick which item should go into the newly generated Army.
                                     // Copy is used, unlike reference, because we do not want to delete the items within the reference Army for future generations.
     for (int j=0; j<reference.size(); j++) {
        copy.addTroop(reference.getTroop(j));
     }

     Army copyBest = new Army(copy.getCountry(), 0); // bestArmy's items are copied into the copyBest Army.
     for (int p=0; p<bestArmy.size(); p++) {
        copyBest.addTroop(bestArmy.getTroop(p));
     }

     Army generated = new Army(reference.getCountry(), 0); // will create a Army to be put into the ArmyPopulation ArrayList
     boolean canRun = true; // boolean condition on if while() loop should run; blanket caution boolean

     // while loop will handle the creation of the new generated Army, which will be added into the ArmyPopulation ArrayList

     while (canRun && (generated.size() <= reference.getMaxSize())) { 
        int randomNum = (int)(Math.random() * (((copy.size()-1) + 1))); // picks a number that is [0, copy.size())
        int randomNumBest = (int)(Math.random() * (((copyBest.size()-1) + 1)));
        if (((randomNum < copy.size()) && (randomNumBest < copyBest.size())) && ((generated.size() + copy.getTroop(randomNum).getWeight()) < reference.getMaxSize()) && ((generated.size() + copyBest.getTroop(randomNumBest).getWeight()) < reference.getMaxSize())){

           int randomTwoThirds = (int)(Math.random() * 3); // will generate a number betwen [0, 3]

           if (randomTwoThirds >= 2) { // for every random number above >=2, it will be added into the Army; this is used to mutate and randomize the Armys
              generated.addTroop(copy.getTroop(randomNum)); 
              copy.removeTroop(randomNum); // this removes the same item from the Army copy to prevent duplicates
           } else {
              generated.addTroop(copyBest.getTroop(randomNumBest)); // for every number < 2, it will just add the copyBest item that is referenced through copyBest[randomNum] 
              copyBest.removeTroop(randomNumBest); // this removes the same item from the Army copyBest to prevent duplicates
           }

        } else {
           canRun = false; 
        }
     }
     armyPopulation.add(generated);      
  }
  indexOfBest = 0; // stores index of best/most fittest Army
  valueOfBest = 0; // stores value of best/most fittest Army
  for(int k=0; k<armyPopulation.size(); k++) {
     if (armyPopulation.get(k).getTotalAttack() > valueOfBest){ // if the newest Army is more fit than the current-pointed "most fit" Army, change it to the new one
        indexOfBest = k;
     }         
  }
  if (bestArmy.getTotalAttack() == armyPopulation.get(indexOfBest).getTotalAttack()) { // if the best stored Army has the same value as the most newly "fittest" Army
     generationsUnchanged++;                                                                 // in the nth generation, then generations unchanged + 1. 
     stopIt++;
  } else if (bestArmy.getTotalAttack() < armyPopulation.get(indexOfBest).getTotalAttack()) {
     bestArmy = armyPopulation.get(indexOfBest);                                     // if the newest "fittest" Army from newest population has a greater value, point it as most fit.
  }
  if(generationsUnchanged == 100){
     hasNotChanged = false;
  }
  System.out.println("Best army has a total of " + bestArmy.size() + " soldiers and attack value of " + bestArmy.getTotalAttack());
  if (bestArmy.size() == 1)  { // just for aesthetic/correct grammar
     System.out.println("There is " +  bestArmy.size() + " troop contained in the army.");  
  } else {
     System.out.println("There are " +  bestArmy.size() + " troops contained in the army.");
  }

  }
  return bestArmy;
  }

The Army labelled reference is the winner's Army. However, I am sure that the Army is full, as prior to the game you must have at least 100 troops before both can begin playing.

The error returned is that the army has a size of 0, and therefore has no troops or any attack power.

Generation 1: Best army has a size of 0 and attack power of 0
Best army has a total of 0 soldiers and attack value of 0
There are 0 troops contained in the army.


Solution

  • (int) Math.random() will always return 0. If you want to convert the type like this, u need to put brackets surrounding the calculation excluding the typecast only