/* * private void Set_Can_Win(TicTacToeDecisionNode ticTacToeDecisionNode, Player originalPlayer) * { * if(ticTacToeDecisionNode.IsWinForOriginalPlayer) * { * ticTacToeDecisionNode.CanWinNode = true; * return; * } * * if(ticTacToeDecisionNode.CurrentPlayer.Letter == originalPlayer.Letter) * { * // if I am making the next move and any children is a winning move or a "killer move" it is also a killer move * foreach(var childNode in ChildNodes) * { * if(childNode.IsWinForOriginalPlayer || childNode.CanWinNode) * { * ticTacToeDecisionNode.CanWinNode = true; * return; * } * } * } * else * { * // if the other player is the next move and all of their children are killer moves, it is a killer move * // if any of them are not killer moves, then it is not a killer move * foreach (var childNode in ticTacToeDecisionNode.ChildNodes) * { * Set_Can_Win(childNode, originalPlayer); * if (childNode.CanWinNode == false) * { * ticTacToeDecisionNode.CanWinNode = false; * return; * } * } * ticTacToeDecisionNode.CanWinNode = true; * return; * } * } * * private void Set_Will_Lose(TicTacToeDecisionNode ticTacToeDecisionNode, Player playerForNode) * { * // No more child nodes, check these nodes * if (ticTacToeDecisionNode.GameState == GameState.Tie) * { * ticTacToeDecisionNode.IsLosingNodeForOriginalPlayer = false; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter == playerForNode.Letter) * { * ticTacToeDecisionNode.IsLosingNodeForOriginalPlayer = false; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter != playerForNode.Letter) * { * ticTacToeDecisionNode.IsLosingNodeForOriginalPlayer = true; * return; * } * * if (ticTacToeDecisionNode.GameState != GameState.InProgress && ticTacToeDecisionNode.ChildNodes.Count > 0) * { * throw new InvalidOperationException("Invalid state"); * } * * foreach (var childNode in ticTacToeDecisionNode.ChildNodes) * { * Set_Will_Lose(childNode, playerForNode); * * if (childNode.IsLosingNodeForOriginalPlayer == false) * { * ticTacToeDecisionNode.IsLosingNodeForOriginalPlayer = false; * return; * } * } * * ticTacToeDecisionNode.IsLosingNodeForOriginalPlayer = true; * } * * private void Set_Will_Win_Or_Tie(TicTacToeDecisionNode ticTacToeDecisionNode, Player playerForNode) * { * // No more child nodes, check these nodes * if (ChildNodes.Count == 0) * { * if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter == playerForNode.Letter) * { * ticTacToeDecisionNode.IsNonLosingNodeForOriginalPlayer = true; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter != playerForNode.Letter) * { * ticTacToeDecisionNode.IsNonLosingNodeForOriginalPlayer = false; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Tie) * { * ticTacToeDecisionNode.IsNonLosingNodeForOriginalPlayer = true; * return; * } * } * * if (ticTacToeDecisionNode.GameState != GameState.InProgress && ticTacToeDecisionNode.ChildNodes.Count > 0) * { * throw new InvalidOperationException("Invalid state"); * } * * foreach (var childNode in ticTacToeDecisionNode.ChildNodes) * { * Set_Will_Win_Or_Tie(childNode, playerForNode); * if (childNode.IsNonLosingNodeForOriginalPlayer == false) * { * ticTacToeDecisionNode.IsNonLosingNodeForOriginalPlayer = false; * return; * } * } * * ticTacToeDecisionNode.IsNonLosingNodeForOriginalPlayer = true; * } * * private static void Set_Will_Win(TicTacToeDecisionNode ticTacToeDecisionNode, Player originalPlayer) * { * // No more child nodes, check these nodes * if (ticTacToeDecisionNode.ChildNodes.Count == 0) * { * if (ticTacToeDecisionNode.GameState == GameState.Tie) * { * ticTacToeDecisionNode.IsWinForOriginalPlayer = false; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter != originalPlayer.Letter) * { * ticTacToeDecisionNode.IsWinForOriginalPlayer = false; * return; * } * else if (ticTacToeDecisionNode.GameState == GameState.Win && ticTacToeDecisionNode.WinningPlayer.Letter == originalPlayer.Letter) * { * ticTacToeDecisionNode.IsWinForOriginalPlayer = true; * return; * } * } * * if (ticTacToeDecisionNode.GameState != GameState.InProgress && ticTacToeDecisionNode.ChildNodes.Count > 0) * { * throw new InvalidOperationException("Invalid state"); * } * * foreach (var childNode in ticTacToeDecisionNode.ChildNodes) * { * Set_Will_Win(childNode, originalPlayer); * if(childNode.IsWinForOriginalPlayer == false) * { * ticTacToeDecisionNode.IsWinForOriginalPlayer = false; * return; * } * } * * ticTacToeDecisionNode.IsWinForOriginalPlayer = true; * } */ private void CreateChildNodes() { if (IsBoardInWinningState(ThisModel)) { // don't add child nodes GameState = GameState.Win; //CurrentPlayer = null; } else if (IsBoardFull(ThisModel)) { // don't add child nodes - game over with no winner GameState = GameState.Tie; //CurrentPlayer = null; } else { // there are still empty nodes GameState = GameState.InProgress; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (!ThisModel.Board.Squares[i, j].Played) { // Get the current player for the next turn SquareLetter nextLetter = SquareLetter.O; Player currentPlayer = ThisModel.Player1; if (CurrentPlayerLetter == ThisModel.Player1.Letter) { nextLetter = this.ThisModel.Player2.Letter; currentPlayer = this.ThisModel.Player2; } else { nextLetter = this.ThisModel.Player1.Letter; currentPlayer = this.ThisModel.Player1; } // create a new game state for hypothetical move var newGameState = new TicTacToeGameModel(ThisModel.Player1.PlayerType, ThisModel.Player2.PlayerType, ThisModel.Board, currentPlayer, i, j); var childNode = new TicTacToeDecisionNode(newGameState, !IsOriginalPlayer, OriginalLetter, nextLetter, i, j); ChildNodes.Add(childNode); } } } } }
public static MoveModel GetBestMove(TicTacToeGameModel model) { //get the best move for the current player TicTacToeGameModel fakeGameModel = null; try { fakeGameModel = new TicTacToeGameModel(model.Player1.PlayerType, model.Player2.PlayerType, model.Board, model.CurrentPlayer); } catch (Exception e) { Console.WriteLine("Unable to create game model"); throw e; } TicTacToeDecisionNode decisionNode = null; try { Player lastPlayer = fakeGameModel.Player1; //use last player as current player if (fakeGameModel.CurrentPlayer == fakeGameModel.Player1) { lastPlayer = fakeGameModel.Player2; } decisionNode = new TicTacToeDecisionNode(fakeGameModel, fakeGameModel.CurrentPlayer.Letter, lastPlayer.Letter); } catch (Exception e) { Console.WriteLine("Unable to create decision node"); throw e; } MoveModel bestMove = null; try { bestMove = decisionNode.GetBestMove(); } catch (Exception e) { Console.WriteLine("Unable to get best move"); throw e; } return(bestMove); }
private static void SetNodeOutcome(TicTacToeDecisionNode node, bool isForOriginalPlayer, SquareLetter originalLetter) { if (node.GameState == GameState.Win && node.WinningPlayer.Letter == originalLetter) { node.Score = 100; return; } else if (node.GameState == GameState.Win && node.WinningPlayer.Letter != originalLetter) { node.Score = -100; return; } else if (node.GameState == GameState.Tie) { node.Score = 0; return; } // check children if (isForOriginalPlayer) { // get max int max = int.MinValue; foreach (var childNode in node.ChildNodes) { SetNodeOutcome(childNode, !isForOriginalPlayer, originalLetter); max = Math.Max(max, childNode.Score); } node.Score = max; return; } else { // get min int min = int.MaxValue; foreach (var childNode in node.ChildNodes) { SetNodeOutcome(childNode, !isForOriginalPlayer, originalLetter); min = Math.Min(min, childNode.Score); } node.Score = min; return; } }