/// <summary> /// Fonction qui retourne le prochain coup de l'IA /// </summary> /// <param name="color"></param> /// <returns></returns> public Tuple <int, int> GetNextMove(int color) { GameState currentState = new GameState(board.GetBoard(), color); AlphaBeta(currentState, MAXDEPTH, 1, currentState.GetEvaluation()); return(bestMove); }
/// <summary> /// Method to test the IA is complying with Othello rules /// BROKEN (does not work) /// Probably that putting random pawns all over the board is not a good way to /// initialize a playable board /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuTestIA_Click(object sender, RoutedEventArgs e) { Referee = new OthelloLib.Board(); if ((lbIABlack.SelectedIndex == -1) || (tournamentPlayers.Count == 0)) { return; } IPlayable.IPlayable testBlackPlayer = (IPlayable.IPlayable)Activator.CreateInstance(tournamentPlayers[lbIABlack.SelectedIndex].GetType()); UI.Title = "TEST RUNNING"; Tuple <int, int> move; bool blackTurn = true; int percent = 0; for (int t = 0; t < 100; t++) { // generate a random board position int[,] testBoard = getRandomBoard(); move = Referee.GetNextMove(testBoard, 5, blackTurn); if (move.Item1 != -1) { testBlackPlayer.PlayMove(move.Item1, move.Item2, blackTurn); //verify Referee.PlayMove(move.Item1, move.Item2, blackTurn); int[,] board1 = testBlackPlayer.GetBoard(); int[,] board2 = Referee.GetBoard(); if (boardCompare(board1, board2)) { percent++; } UI.Title += "."; } else { percent++; UI.Title += "X"; } System.Threading.Thread.Sleep(30); } UI.Title = $"TEST COMPLETE ({percent}%)"; }
/// <summary> /// This method will perform the game loop /// NOTE: it is required for this method to be async to allow for await /// otherwise it will lock the main(UI) thread and the game status is not /// visually updated (refreshed) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void MenuStartGame_Click(object sender, RoutedEventArgs e) { if ((tournamentBlackPlayer == null) || (tournamentWhitePlayer == null)) { System.Windows.MessageBox.Show("You NEED 2 IAs to play a match!"); return; } // to prevent crash with some IA when playing a second time tournamentBlackPlayer = (IPlayable.IPlayable)Activator.CreateInstance(tournamentPlayers[lbIABlack.SelectedIndex].GetType()); tournamentWhitePlayer = (IPlayable.IPlayable)Activator.CreateInstance(tournamentPlayers[lbIAWhite.SelectedIndex].GetType()); RestartGame(); Referee = new OthelloLib.Board(); int[,] refBoard = (Referee as OthelloLib.Board).GetBoard(); int[,] board1 = refBoard; //tournamentBlackPlayer.GetBoard(); // PLAYER 1 int[,] board2 = refBoard; //tournamentWhitePlayer.GetBoard(); // PLAYER 2 team1.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)); team2.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)); Tuple <int, int> playerMove = null; int passCount = 0; bool testPlayer1, testPlayer2; bool whitePlays = false; IPlayable.IPlayable activePlayer = tournamentBlackPlayer; // player 1 begins playing black //GAME LOOP while (boardCompare(refBoard, board1) && boardCompare(refBoard, board2) && (passCount < 2)) { int totalScore = Referee.GetBlackScore() + Referee.GetWhiteScore(); await Task.Delay(whitePlays? 100 : 100); // slow down game speed try { playerMove = activePlayer.GetNextMove(refBoard, 5, whitePlays); } catch (Exception ex) { Console.WriteLine(ex.Message + "\n\n" + ex.StackTrace); } // check move validity if (playerMove == null) { System.Windows.MessageBox.Show($" {activePlayer.GetName()} a renvoyé un coup NULL\nFIN DE LA PARTIE"); return; } if ((playerMove.Item1 == PASS) && (playerMove.Item2 == PASS)) { Console.WriteLine("PASS"); passCount++; ///TODO verify if no move was possible (no playable move otherwise display a msg or throw something if ((Referee as OthelloLib.Board).GetPossibleMoves(whitePlays).Count != 0) { System.Windows.MessageBox.Show($" {activePlayer.GetName()} a passé son tour de manière illégale\nFIN DE LA PARTIE"); return; } } else { passCount = 0; Console.WriteLine($"{activePlayer.GetName()}: {(char)('A' + playerMove.Item1)}{1 + playerMove.Item2}"); // check validity if ((Referee as OthelloLib.Board).IsPlayable(playerMove, whitePlays)) { Console.WriteLine($"Coup valide de {activePlayer}"); // play the move for both players and referee Referee.PlayMove(playerMove.Item1, playerMove.Item2, whitePlays); testPlayer1 = tournamentBlackPlayer.PlayMove(playerMove.Item1, playerMove.Item2, whitePlays); // no verification here testPlayer1 = tournamentWhitePlayer.PlayMove(playerMove.Item1, playerMove.Item2, whitePlays); // no verification here // compare boards for validity refBoard = (Referee as OthelloLib.Board).GetBoard(); board1 = tournamentBlackPlayer.GetBoard(); board2 = tournamentWhitePlayer.GetBoard(); testPlayer1 = boardCompare(refBoard, board1); testPlayer2 = boardCompare(refBoard, board2); if (testPlayer1 && testPlayer2) // the move is valid { PlayMove(playerMove.Item1, playerMove.Item2); UI.Title = $"BLACK:{Referee.GetBlackScore()} WHITE:{Referee.GetWhiteScore()}"; //System.Windows.MessageBox.Show("."); await Task.Delay(delay); } else if (!testPlayer1) { System.Windows.MessageBox.Show($"Board state of {tournamentBlackPlayer.GetName()}is incorrect"); throw new Exception($"Board state of {tournamentBlackPlayer.GetName()}is incorrect"); } else if (!testPlayer2) { System.Windows.MessageBox.Show($"Board state of {tournamentWhitePlayer.GetName()}is incorrect"); throw new Exception($"Board state of {tournamentWhitePlayer.GetName()} is incorrect"); } } else { Console.WriteLine($"COUP INVALIDE {(char)(playerMove.Item1+'A')}{playerMove.Item2+1}"); if (whitePlays == true) { team2.Foreground = new SolidColorBrush(Color.FromRgb(255, 100, 100)); System.Windows.MessageBox.Show($"COUP INVALIDE de {tournamentWhitePlayer.GetName()} {(char)playerMove.Item1 + 'A'}{playerMove.Item2 + 1}\nFIN DE LA PARTIE"); return; } else { team1.Foreground = new SolidColorBrush(Color.FromRgb(255, 100, 100)); System.Windows.MessageBox.Show($"COUP INVALIDE de {tournamentBlackPlayer.GetName()} {(char)(playerMove.Item1 + 'A')}{playerMove.Item2 + 1}\nFIN DE LA PARTIE"); return; } } } // SWAP players and color whitePlays = !whitePlays; activePlayer = (activePlayer == tournamentBlackPlayer) ? tournamentWhitePlayer : tournamentBlackPlayer; } // end of GAMELOOP }