public void Run() { if (!quiet) { Console.WriteLine("Tic Tac Toe Machine Learning Demonstration"); } // Create starting state IState state = new TicTacToeState(); TicTacToeState tttState = state as TicTacToeState; // Create players one and two Agent playerOne = new Agent(); Agent playerTwo = new Agent(); // Wire player behaviors to state events TicTacToeState.WireEvents(tttState, playerOne, playerTwo); // Conduct training if (!useInFile) { TicTacToeState.TrainZeroSum(training, !quiet, playerOne, playerTwo); } // Handle serialization if (useInFile) { Utilities.ReadInFile(inFile, playerOne, playerTwo); } if (useOutFile) { Utilities.WriteOutFile(outFile, playerOne); } // Determine victory, defeat, and cat's game events bool playerTwoVictory = false; Action <object, EventArgs> declareVictory = (object sender, EventArgs e) => playerTwoVictory = true; TicTacToeState.PlayerWinsO += declareVictory; bool playerTwoDefeat = false; Action <object, EventArgs> declareDefeat = (object sender, EventArgs e) => playerTwoDefeat = true; TicTacToeState.PlayerWinsX += declareDefeat; bool playerTwoDraw = false; Action <object, EventArgs> declareDraw = (object sender, EventArgs e) => playerTwoDraw = true; TicTacToeState.CatsGame += declareDraw; // Player competes with computer while (!playerTwoVictory && !playerTwoDraw && !playerTwoDefeat) { tttState = playerOne.Act(tttState.SuccessorsX) as TicTacToeState; // No need to GoalTest if game is over if (!playerTwoDraw) { tttState.GoalTest(); } if (!playerTwoVictory && !playerTwoDraw && !playerTwoDefeat) { // Display move options List <IState> options = tttState.SuccessorsO; if (!playerTwoDraw) { // Prompt the user TicTacToeState.PrintOptions(options); Console.Write("Please select a move: "); int moveIndex = Int32.Parse(Console.ReadLine()) - 1; // Assign the state tttState = options[moveIndex] as TicTacToeState; tttState.GoalTest(); } } // Select outcome if (playerTwoVictory) { Console.WriteLine("Human player wins!"); } if (playerTwoDefeat) { Console.WriteLine("Computer wins!"); } if (playerTwoDraw) { Console.WriteLine("Cat's game!"); } } }
public static void TrainZeroSum(long practiceGames, bool showOutput, Agent agentOne, Agent agentTwo) { // Create starting state IState state = new TicTacToeState(); TicTacToeState tttState = state as TicTacToeState; // Put agents in training mode agentOne.TrainingMode(1.0); agentTwo.TrainingMode(1.0); // Use repeated wins as a benchmark bool enoughTraining = false; long games = 0; int ticks = 0; bool dotPrinted = false; // Reset dotPrinted after it has moved on Action <object, EventArgs> resetDotPrinted = (object sender, EventArgs e) => dotPrinted = false; TicTacToeState.PlayerWinsX += resetDotPrinted; TicTacToeState.PlayerWinsO += resetDotPrinted; TicTacToeState.CatsGame += resetDotPrinted; // Begin training progress bar if (showOutput) { Console.Write("[ "); } // Watch each agent evolve while (!enoughTraining) { // Train the first agent tttState = agentOne.Act(tttState.SuccessorsX) as TicTacToeState; tttState.GoalTest(); games = agentOne.Victories + agentTwo.Victories + agentOne.Draws; // Account for every 1% of progress if (games % (practiceGames / 100) == 0 && !dotPrinted) { // Update competitiveness at quarters if (ticks % 25 == 0) { // Display quarter in progress bar if (showOutput) { Console.Write($"[{ticks}]"); } // Make each agent more competitive agentOne.TrainingMode((100.0 - ticks) / 100.0); agentTwo.TrainingMode((100.0 - ticks) / 100.0); } // Update ticks ticks += 1; // Don't include hundredth tick if (ticks < 100 && showOutput) { Console.Write("."); } dotPrinted = true; } // Check if total number of practices have been met if (games >= practiceGames) { enoughTraining = true; } // Train the second agent, assuming they are not sufficiently trained if (!enoughTraining) { tttState = agentTwo.Act(tttState.SuccessorsO) as TicTacToeState; tttState.GoalTest(); games = agentOne.Victories + agentTwo.Victories + agentOne.Draws; // Account for every 1% of progress if (games % (practiceGames / 100) == 0 && !dotPrinted) { // Update competitiveness at quarters if (ticks % 25 == 0) { // Display quarter in progress bar if (showOutput) { Console.Write($"[{ticks}]"); } // Make each agent more competitive agentOne.TrainingMode((100.0 - ticks) / 100.0); agentTwo.TrainingMode((100.0 - ticks) / 100.0); } // Update ticks ticks += 1; // Don't include hundredth tick if (ticks < 100 && showOutput) { Console.Write("."); } dotPrinted = true; } // Check if total number of practices have been met if (games >= practiceGames) { enoughTraining = true; } } } // End progress bar if (showOutput) { Console.WriteLine(" ]"); Console.WriteLine("\n"); } // Put agents in competitive mode agentOne.CompeteMode(); agentTwo.CompeteMode(); }