public void alternate() { // 適応度を昇順に並び替える quickSort(0, Simulation.ROCKET_NUM - 1); Debug.Log($"第{Simulation.curGeneration-1}世代 最良適応度: {this.curIndividuals[0].fitness}"); // 前世代にTargetに到達した数を現世代のエリート数とする elite = 2; superElite = 0; for (int i = 0; i < Simulation.ROCKET_NUM; i++) { if (curIndividuals[i].isReachedTarget) { superElite++; } } elite = Mathf.Max(elite + superElite, 5); // elite上限5 // エリートは無条件に保存する for (int i = 0; i < elite; i++) { for (int j = 0; j < Rocket.LIFESPAN; j++) { nextIndividuals[i].chrom[j] = curIndividuals[i].chrom[j]; } } float totalFitness = 0; float worstFitness = curIndividuals[Simulation.ROCKET_NUM - 1].fitness; // ソート後、配列最後尾に最悪適応度が格納されている for (int i = 0; i < Simulation.ROCKET_NUM; i++) { trFit[i] = (worstFitness - curIndividuals[i].fitness + 0.001f) / worstFitness; trFit[i] = Mathf.Pow(trFit[i], 4.0f); totalFitness += trFit[i]; } // 交叉 for (int i = elite; i < Simulation.ROCKET_NUM; i++) { int parent = rouletteSelection(totalFitness); int r = Random.Range(0, 3); if (r == 0) { nextIndividuals[i].prevFitness = trFit[i] * trFit[parent]; nextIndividuals[i].Crossover(curIndividuals[i], curIndividuals[parent]); } else if (r == 1) { nextIndividuals[i].prevFitness = trFit[i] * trFit[parent]; nextIndividuals[i].Crossover(curIndividuals[parent], curIndividuals[i]); } else { int anotherParent = rouletteSelection(totalFitness); nextIndividuals[i].prevFitness = trFit[anotherParent] * trFit[parent]; nextIndividuals[i].Crossover(curIndividuals[parent], curIndividuals[anotherParent]); } } // 突然変異 for (int i = superElite; i < Simulation.ROCKET_NUM; i++) { nextIndividuals[i].Mutate(); } // 次世代に受け継ぐ Rocket[] tmp = new Rocket[Simulation.ROCKET_NUM]; curIndividuals.CopyTo(tmp, 0); nextIndividuals.CopyTo(curIndividuals, 0); tmp.CopyTo(nextIndividuals, 0); // reset all rockets for (int i = 0; i < Simulation.ROCKET_NUM; i++) { curIndividuals[i].Reset(); } }