/*Takes 3 players and generates a new array of Players * 50% are derived from first * 30% derived from second * 20% derived from third * any remainder slots are also filled with players derived from first */ private Player[] GenerateBracket(Player first, Player second, Player third) { Player[] bracket = new Player[playersPerBracket]; int playersGenerated = 0; int firstChildren = (int)(playersPerBracket * .5); //50% descendents derived from first int secondChildren = (int)(playersPerBracket * .3); //30% from second int thirdChildren = (int)(playersPerBracket * .2); //20% from third int remainder = playersPerBracket - (firstChildren + secondChildren + thirdChildren); firstChildren += remainder;//any remaining slots filled with descendents of first bracket[0] = first.Reproduce(0); bracket[1] = second.Reproduce(0); playersGenerated += 2; for (int i = 1; i < firstChildren; i++) { bracket[playersGenerated] = first.Reproduce(mutationRate); playersGenerated++; } for (int i = 1; i < secondChildren; i++) { bracket[playersGenerated] = second.Reproduce(mutationRate); playersGenerated++; } for (int i = 0; i < thirdChildren; i++) { bracket[playersGenerated] = third.Reproduce(mutationRate); playersGenerated++; } return(bracket); }
/*creates a bracket of players, has them each play all the others, and * creates a new bracket seeded by the top 3. Repeats iterationsPerTask times. */ public Player PlayAndEvolve(Player seed, CancellationToken cancel) { Thread.CurrentThread.Priority = ThreadPriority.Lowest; Player[] bracket = new Player[playersPerBracket]; Player first, second, third; first = seed; bracket[0] = seed; for (int i = 1; i < playersPerBracket; i++) { bracket[i] = seed.Reproduce(mutationRate); } for (int i = 0; i < iterationsPerTask; i++) { if (cancel.IsCancellationRequested) { return(first); } RunBracket(bracket); GetTop3Players(bracket, out first, out second, out third); bracket = GenerateBracket(first, second, third); } return(first); }
/* Training algorithm * * Algorithm works as follows: * several tasks run the PlayAndEvolve method (# tasks = trainingTasks) * PlayAndEvolve takes a seed player, fills an array (size = playersPerBracket) with mutated copies of the seed, * and has every player play all the others. The top 3 are used as seeds for the next iteration. This process * is repeated iterationsPerTask times, and then the top player is returned as the result of the task. * Once every training task completes, each player plays all the others, and the one with the most wins * becomes the challenger. The challenger plays the existing champion and, if it wins, becomes the * new champion. * The process is repeated in an infinite loop * * cancelAfterGeneration waits for all tasks in simTasks to complete and then computes the champion * cancelNow causes all the simTasks to abort before completing all their iterations */ public void Train(CancellationToken cancelNow, CancellationToken cancelAfterGeneration, Player seed) { generationsSinceNewChampion = 0; generations = 0; _gamesPlayed = 0; winRecord = 0; champion = seed; Player challenger; Task notifier = Task.Factory.StartNew(() => UpdateStats(cancelAfterGeneration)); //this task updates the trainingStats property at fixed intervals Task <Player>[] simTasks = new Task <Player> [trainingTasks]; Player[] bracket = new Player[trainingTasks]; trainerStatus = "Running. . ."; //first element is seeded with the champion, the remaining are seeded with mutations of the champion simTasks[0] = Task <Player> .Factory.StartNew(() => PlayAndEvolve(champion, cancelAfterGeneration)); for (int i = 1; i < trainingTasks; i++) { simTasks[i] = Task <Player> .Factory.StartNew(() => PlayAndEvolve(champion.Reproduce(i + 1), cancelNow)); } while (true) { /*The main training loop works as follows * Wait for all PlayAndEvolve tasks to complete. * Create a new bracket with the result of each task. * Call RunBracket method to have each of them play all the others * Have the top player from that bracket play against the reigning champion, * and make it the new champion if it wins. * If cancellation token was cancelled, end the training loop. * Else, begin new generation of PlayAndEvolve tasks with the results of the prior generation. */ Task.WaitAll(simTasks); for (int i = 0; i < trainingTasks; i++) { bracket[i] = simTasks[i].Result; } RunBracket(bracket, trainingTasks); challenger = GetTopPlayer(bracket); champion = GetWinnerOfGame(challenger, champion); generations++; if (champion != challenger) { generationsSinceNewChampion = 0; } else { generationsSinceNewChampion++; if (generationsSinceNewChampion > winRecord) { winRecord = generationsSinceNewChampion; } } if (cancelAfterGeneration.IsCancellationRequested) { trainerStatus = "Finished"; trainingStats = String.Format("{0}\nGeneration: {1}\nGames Played: {2}\nChamp for {3} generations\nRecord is {4} generations", trainerStatus, generations, _gamesPlayed, generationsSinceNewChampion, winRecord); UI.Invoke(TrainingFinished); return; } for (int i = 0; i < trainingTasks; i++) { Player p = bracket[i].Reproduce(0); simTasks[i] = Task <Player> .Factory.StartNew(() => PlayAndEvolve(p, cancelNow)); } } }