private void newGameToolStripMenuItem_Click(object sender, EventArgs e) { _game = new TicTacToeGame(NeededForWin); s_moves.Clear(); CurrentPlayer = TicTacToeValue.x; tslMoveCount.Text = ""; Refresh(); }
public static LabeledState <GameState, TicTacToeValue> ParsePosition(string position, Func <GameState, double[]> inputTransform) { string[] components = position.Split(new string[] { "\r\n", " " }, StringSplitOptions.RemoveEmptyEntries); GameState gameState = GameState.Parse(components[0], components[3], components[6]); double[] output = new double[3]; output[0] = double.Parse(components[0 * 3 + 2]); output[1] = double.Parse(components[1 * 3 + 2]); output[2] = double.Parse(components[2 * 3 + 2]); var probabilities = new TicTacToeValue(output); return(new LabeledState <GameState, TicTacToeValue>(gameState, inputTransform(gameState), output, probabilities)); }
public VisualNode AddMove(int x, int y, TicTacToeValue currentPlayer) { string nodeKey = Constants.GetKey(x, y); if (nodes.ContainsKey(nodeKey)) { return(null); } VisualNode newNode = new VisualNode(x, y, currentPlayer); nodes.Add(nodeKey, newNode); return(newNode); }
public GameAction GenerateAction(GameState state) { var actions = TicTacToeGame.Instance.GetAllowedActions(state); var states = actions.Select(action => TicTacToeGame.Instance.Play(state, action)); var predictions = states.Select(Network.Evaluate).Select(prediction => prediction.Probabilities); foreach (var prediction in predictions) { Console.WriteLine($"{string.Join(" ", prediction)}"); } int best = TicTacToeValue.FindBest(predictions, state.CurrentPlayer); return(actions.ElementAt(best)); }
private void TraverseBoard(VisualNode node, NodeLocation direction, Action <VisualNode> runAction) { // flag all the nodes on the winDirection var currentNode = nodes[Constants.GetKey(node.X, node.Y)]; TicTacToeValue nodeValue = node.Value; // traverse all nodes of the same value while (currentNode.Value == nodeValue) { runAction(currentNode); string nodeKey = Constants.MapDirectionToComputation[direction](currentNode.X, currentNode.Y); // continue on the direction, if there is anything there. if (nodes.ContainsKey(nodeKey)) { currentNode = nodes[nodeKey]; } else { break; } } }
private bool PlaceMove(VisualNode move) { if (_game.GameEnded) { return false; } if (move == null) { MessageBox.Show("Cannot place the move there!"); return false; } s_moves.Push(move); tslMoveCount.Text = $"Move: {s_moves.Count}"; Refresh(); NodeLocation winDirection; if (_game.IsWinningMove(move, out winDirection)) { _game.GameEnded = true; // Mark the wining nodes. _game.MarkWinningNodes(move, winDirection); Refresh(); #if !COMPUTER_AGAINST_ITSELF MessageBox.Show($"Winner is player {CurrentPlayer}!!!"); #else if (CurrentPlayer == TicTacToeValue.x) winX++; else winO++; if (s_moves.Count > maxMove) maxMove = s_moves.Count; if (s_moves.Count < minMove) minMove = s_moves.Count; label3.Text = $"X: {winX}, O: {winO}, min:{minMove}, max:{maxMove}"; #endif _game = new TicTacToeGame(NeededForWin); s_moves.Clear(); CurrentPlayer = TicTacToeValue.x; tslMoveCount.Text = ""; Refresh(); #if COMPUTER_AGAINST_ITSELF PlaceAIMove(); #endif return true; } else { ChangePlayer(); #if COMPUTER_AGAINST_ITSELF PlaceAIMove(); #endif } Application.DoEvents(); return false; }
private void ChangePlayer() { CurrentPlayer = CurrentPlayer == TicTacToeValue.o ? TicTacToeValue.x : TicTacToeValue.o; }
public VisualNode(int x, int y, TicTacToeValue value) { X = x; Y = y; Value = value; }
public VisualNode GetAIMove(TicTacToeValue currentPlayer) { if (nodes.Count == 0) { return(AddMove(15, 15, currentPlayer)); } string myMove = string.Empty; // figure out all the empty nodes outthere. HashSet <string> positions = GetEmptyNeighBours(); // we are going to count (-1, 1) based on the counts for each position. // we don't need to actually place the move, just compute the neighbours we need to check for. Dictionary <string, int> mapPositionContributions = new Dictionary <string, int>(); int bestX = 0, bestO = 0; foreach (var position in positions) { int currentX, currentY; Constants.GetCoordinates(position, out currentX, out currentY); // find all the nei int positionValues = 0; // consider it neutral for now. positionValues = Max(CountOnDirection(NodeLocation.TopCenter, currentX, currentY, currentPlayer), CountOnDirection(NodeLocation.Left, currentX, currentY, currentPlayer), CountOnDirection(NodeLocation.TopLeft, currentX, currentY, currentPlayer), CountOnDirection(NodeLocation.TopRight, currentX, currentY, currentPlayer)); // keep a running total of best X and best O positions if (positionValues >= 0 && positionValues > bestX) { bestX = positionValues; } if (positionValues <= 0 && positionValues < bestO) { bestO = positionValues; } Debug.WriteLine($"Computed value {position}={positionValues}"); mapPositionContributions[position] = positionValues; } Debug.WriteLine($"Best X postion has value {bestX}, Best O position has value {bestO}"); // we now need to figure out the win move. int bestMoveCount; if (currentPlayer == TicTacToeValue.o) { //if we have a tie, prefer to win the game! if (Math.Abs(bestO) == Math.Abs(bestX)) { bestMoveCount = bestO; } else { bestMoveCount = Math.Abs(bestO) > Math.Abs(bestX) ? bestO : bestX; } } else { //if we have a tie, prefer to win the game! if (Math.Abs(bestO) == Math.Abs(bestX)) { bestMoveCount = bestX; } else { bestMoveCount = Math.Abs(bestX) > Math.Abs(bestO) ? bestX : bestO; } } Random r = new Random((int)DateTime.Now.Ticks); var possibleMoves = mapPositionContributions.Where(pair => pair.Value == bestMoveCount); myMove = possibleMoves.Skip(r.Next(possibleMoves.Count() - 1)).First().Key; Debug.WriteLine($"The best move for {currentPlayer} is {myMove}"); int x = 0, y = 0; Constants.GetCoordinates(myMove, out x, out y); return(AddMove(x, y, currentPlayer)); }
private int CountOnDirection(NodeLocation direction, int currentX, int currentY, TicTacToeValue currentPlayer) { int countForX = CountOnBothDirectionsUsingBoard(direction, currentX, currentY, TicTacToeValue.x); int countForO = CountOnBothDirectionsUsingBoard(direction, currentX, currentY, TicTacToeValue.o); return(currentPlayer == TicTacToeValue.x ? countForX - countForO : countForO - countForX); }
private int CountOnBothDirectionsUsingBoard(NodeLocation direction, int currentX, int currentY, TicTacToeValue currentPlayer) { var moveFirstDir = CountOnSingleDirectionUsingBoard(direction, currentX, currentY, currentPlayer); var moveSecondDir = CountOnSingleDirectionUsingBoard(direction.GetReverseDirection(), currentX, currentY, currentPlayer); int count = moveFirstDir.countPerDirection + moveSecondDir.countPerDirection; // this is the case where we have something like: o x _ x x o // there is no point to put an o in there as that can never ever be a winning move from x if (count <= 3 && (moveFirstDir.endsWithOpponentMove && moveSecondDir.endsWithOpponentMove)) { count = 0; } if (count >= 4) { count *= count; } else if (count >= 3) { count *= 2; } if (count >= 2 && !moveFirstDir.endsWithOpponentMove) { count++; } if (count >= 2 && !moveSecondDir.endsWithOpponentMove) { count++; } return(count); }
private AIMove CountOnSingleDirectionUsingBoard(NodeLocation direction, int currentX, int currentY, TicTacToeValue currentPlayer) { AIMove move = new AIMove(); //int count = 0; string nodeKey = Constants.MapDirectionToComputation[direction](currentX, currentY); if (!nodes.ContainsKey(nodeKey)) { return(move); } TraverseBoard(nodes[nodeKey], direction, (node) => { if (node.Value == currentPlayer) { move.countPerDirection++; } else { move.endsWithOpponentMove = true; } // check to see if there is a next neighbor string nk = Constants.MapDirectionToComputation[direction](node.X, node.Y); if (!nodes.ContainsKey(nk)) { move.endsWithOpponentMove = false; } else { if (nodes[nk].Value != currentPlayer) { move.endsWithOpponentMove = true; } } }); return(move); }