os resultados, vamos gerar um arquivo .csv, partindo do output da GA (veja o metodo formatResults). Segue a classe GeneticAlgorithm:import java.util.concurrent.*;import java.util.ArrayList;import java.util.Random;public class GeneticAlgorithm{ public static TetrisAgent[] blendCrossover(TetrisAgent father, TetrisAgent mother) { TetrisAgent copy1 = father.cloneAgent(); TetrisAgent copy2 = mother.cloneAgent(); Random random = new Random(); int N_GENES = father.genes.length; int index = random.nextInt(N_GENES); for (int i = index; i < N_GENES; i++) { float beta = random.nextFloat(); float var1 = father.genes[i]; float var2 = mother.genes[i]; float newVar1 = beta * var1 + (1 - beta) * var2; float newVar2 = (1 - beta) * var1 + beta * var2; copy1.genes[i] = newVar1; copy2.genes[i] = newVar2; } return new TetrisAgent[]{copy1, copy2}; } public static void mutateNoise(TetrisAgent agent, float probMutate) { int N_GENES = agent.genes.length; Random random = new Random(); for (int i = 0; i < N_GENES ; i++) { float sort = random.nextFloat(); if (sort < probMutate) { float prob = random.nextFloat(); if (prob < 0.5f) { float genValue = agent.genes[i]; float complement = 1.0f - genValue; float noise = random.nextFloat() * complement; agent.genes[i] += noise; } else { float genValue = agent.genes[i]; float noise = random.nextFloat() * genValue; agent.genes[i] -= noise; } } } } public static TetrisAgent doSelection(TetrisAgent[] population) { TetrisAgent sorted = null; float totalFitness = 0.0f; for (TetrisAgent agent : population) totalFitness += agent.fitness; float frac = new Random().nextFloat(); float cut = frac * totalFitness; for (TetrisAgent agent:population) { cut -= agent.fitness; if (cut <= 0.0f) { sorted = agent; break; } } return sorted; } public static ArrayList&ltTetrisAgent[]&gt runGA(int popSize, int maxGens, float probMutate, int gamesPerAgent, float eliteRate) { ArrayList&ltTetrisAgent[]&gt hist = new ArrayList&ltTetrisAgent[]&gt(); //popSize par, importante caso haja elitismo if (popSize % 2 == 1) popSize += 1; int elite = (int)(popSize * eliteRate); //elite par, importante caso haja elitismo if (elite % 2 == 1) elite += 1; int currentGeneration = 0; Random random = new Random(); TetrisAgent[] population = new TetrisAgent[popSize]; TetrisAgent bestAgent = null; int rows = 20; int cols = 10; int blockSize = 1; //qualquer valor diferente de zero //cria populacao inicial e inicia fitness for (int i = 0; i < population.length; i++) population[i] = TetrisAgent.randomAgent(); int seed = random.nextInt(); do { CountDownLatch doneSignal = new CountDownLatch(popSize * gamesPerAgent); for (TetrisAgent agent : population) { for (int i = 0; i < gamesPerAgent; i++) { AIGame game = new AIGame(rows, cols, blockSize, i + seed, doneSignal); game.agent = agent; new Thread(game).start(); } } //espera games terminarem try { doneSignal.await(); } catch(InterruptedException ex){} //calcula fitness for (TetrisAgent agent : population) { float average = 0.0f; for (Integer cleared : agent.clearedRowsArray) average += cleared; agent.fitness = 1.0f * average/gamesPerAgent; agent.clearedRowsArray.clear(); } //atualiza bestAgent for (TetrisAgent agent : population) if (bestAgent == null || agent.fitness > bestAgent.fitness) bestAgent = agent; TetrisAgent[] newPopulation = new TetrisAgent[popSize]; java.util.Arrays.sort(population); //elite TetrisAgent[] eliteArray = new TetrisAgent[elite]; for (int i = 0; i < elite;i++) newPopulation[i] = population[popSize - i - 1]; int newIndex = elite; for (int i = 0; i < (popSize - elite)/2; i++) { TetrisAgent parentA = doSelection(population); TetrisAgent parentB = doSelection(population); TetrisAgent[]