// train the neural networks environment IEnumerator Train() { bool complexify = true; int index = 0; // Create the initial neural networks generationNetworks = ga.CreateNetworks(); raceManager.Reset(); FitnessTracker.totLength = 0; for (int i = 0; i < LoadTrackManager.instance.selectedTrackNames.Count; i++) { trackManagers.Add(Instantiate(trackPrefab).GetComponent <TrackManager>()); trackManagers[i].Initialize(LoadTrackManager.instance.selectedTrackNames[i]); trackManagers[i].gameObject.SetActive(false); } TrackManager.SetTotalLength(); // Training loop. Keep the training running as long as desired. while (true) { // This pauses the training yield return(StartCoroutine(Pause())); fitnesses.Clear(); float sum = 0; // add all new networks to the networks list raceManager.ResetPlayers(); for (int individual = 0; individual < generationNetworks.Count; individual++) { raceManager.AddAIPlayer(individual.ToString(), generationNetworks[individual], individual); } raceManager.FinishPlayers(generationNetworks.Count); yield return(StartCoroutine(raceManager.StartRace(true, trackManagers, false))); // Get the fitnesses of the networks and calculate the sum of all fitnesses fitnesses = raceManager.GetFitnesses(); int bestRacerIndex = 0; bool updateTime = false; for (int i = 0; i < fitnesses.Count; i++) { if (fitnesses[i] >= bestFitnessSoFar) { bestFitnessSoFar = fitnesses[i]; bestRacerIndex = i; updateTime = true; bestGeneration = curGeneration; } if (fitnesses[i] < 0) { fitnesses[i] = 0; } sum += fitnesses[i]; } float currentBestFitness = 0; for (int i = 0; i < fitnesses.Count; i++) { if (fitnesses[i] >= currentBestFitness) { currentBestFitness = fitnesses[i]; } } curGeneration++; // Restart the simulation if non of the cars has a fitness higher than 0 if (sum == 0) { curGeneration = 0; InitializeNetworks(); generationNetworks = ga.CreateNetworks(); continue; } float totalTime = raceManager.GetCurrentCompetingCars()[bestRacerIndex].totalTime; if (raceManager.GetCurrentCompetingCars()[bestRacerIndex].GetFitnessTracker().finished != LoadTrackManager.instance.selectedTrackNames.Count) { totalTime = -1; } // Update the best and average fitness on the UI UIController.instance.UpdateUI(bestFitnessSoFar, currentBestFitness, sum / ga.populationSize, curGeneration, totalTime, updateTime); // Determine the population for the next generation based on the fitnesses of the current networks generationNetworks = ga.DoGeneration(fitnesses, complexify); index++; if (index > 50) { index = 0; if (complexify && Random.Range(0f, 1f) < 0.3f) { complexify = !complexify; } else if (!complexify) { complexify = true; } } } }