children = blendCrossover(parentA, parentB); TetrisAgent childA = children[0]; TetrisAgent childB = children[1]; mutateNoise(childA, probMutate); mutateNoise(childB, probMutate); newPopulation[newIndex] = childA; newIndex++; newPopulation[newIndex] = childB; newIndex++; } hist.add(population); population = newPopulation; currentGeneration++; System.out.println("Melhor da geracao " + currentGeneration + ": " + bestAgent.fitness); for (int i = 0; i < bestAgent.genes.length; i++) System.out.print(bestAgent.genes[i] + " "); System.out.println(); } while(currentGeneration < maxGens); return hist; } /* formata output em .csv */ public static void formatResults(ArrayList&ltTetrisAgent[]&gt generations, String file) { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(file, false)); } catch(IOException ex){ex.printStackTrace();} int gens = generations.size(); //header for(int i = 0; i < gens; i++) { try { if (i == gens - 1) writer.write("g" + i + "\n"); else writer.write("g" + i + ","); } catch (IOException ex){ex.printStackTrace();} } int pop = generations.get(0).length; for(int indiv = 0; indiv < pop; indiv++) { //dados for(int i = 0; i < gens; i++) { TetrisAgent agent = generations.get(i)[indiv]; float fitness = agent.fitness; try { if (i == gens - 1) writer.write(fitness + "\n"); else writer.write(fitness + ","); } catch (IOException ex){ex.printStackTrace();} } } try { writer.close(); } catch(IOException ex){ex.printStackTrace();} } } //fim da classe GeneticAlgorithmExecutando a GA Dependendo dos valores usados em popSize, maxGens e gamesPerAgent, o algoritmo levara mais ou menos tempo para finalizar. Ao passar um valor maior do que 1 para gamesPerAgent, aumentamos a chance de agentes com bom desempenho contribuir para a evolucao dos individuos, ja que maus agentes serao desmascarados ao tomarmos a media do numero de linhas removidas. No meu teste, usei os seguintes valores: popSize = 20 maxGens = 30 probMutate = 0.2 gamesPerAgent = 10 eliteRate = 0.2 No meu macbook (2.4 GHz Intel Core 2 Duo, memoria de 4 GB 1067 MHz DDR3), usando os valores acima, o algoritmo demorou um tempo absurdo para finalizar. A principio nao achei estranho, pois conforme os agentes evoluem, os jogos ficam cada vez mais longos. Na verdade, como apontado pelo leitor Kevin Nash, o problema esta no metodo run da classe AIGame. Ao final deste metodo invocamos Thread.sleep(20L), causando uma queda generalizada na performance. Para resolver este problema, o construtor da classe AIGame agora aceita uma variavel boolean doSleep, inicializada como false. Somente ao visualizar o agente jogando, setamos doSleep para true. Atualize sua classe AIGame antes de testar o algoritmo! Existem algumas otimizacoes que podem ser feitas no codigo, uma delas e garantir que um agente que nao teve seus genes modificados nao seja testado novamente. Outra possibilidade seria detectar agentes que sejam muito ruins, e simplesmente abortar o jogo. A primeira sugestao parece mais facil de implementar, mas realmente nao me preocupei com desempenho neste caso. Adicione o metodo main na classe GeneticAlgorithm: public static void main (String[] args){ int popSize = 20; int maxGens = 30; float probMutate = 0.2f; int gamesPerAgent = 10; float eliteRate = 0.2f; ArrayList&ltTetrisAgent[]&gt hist = runGA(popSize, maxGens, probMutate, gamesPerAgent, eliteRate); GeneticAlgorithm.formatResults(hist, "outputGA.csv");}Evolucao Para analisar o arquivo gerado vamos usar a Linguagem R. Para quem nao conhece, R e uma linguagem voltada para computacao estatistica e graficos, com versoes para