Пример #1
0
        public static List<Node> GenerateSuccessors(Board board, bool isBlack)
        {
            //Validate moves based on current state to generate new states

            var nodes = new List<Node>();


            //Generate # of valid moves
            var ValidMoves = GetNumberOfMoves(board);
            //Foreach valid move, generate a new node (evaluated in minimax)
            for (var i = 0; i < ValidMoves.Length; i++)
            {
                if (ValidMoves[i])
                {
                    var tempBoard = new Board(board.State);
                    //Make the move
                    tempBoard.AddToBoard(i, isBlack);
                    //Create a Node
                    var node = new Node();
                    node.Board = tempBoard;
                    nodes.Add(node);
                }
            }

            return nodes;
        }
Пример #2
0
        public int Search(Node node, int depth, bool maxPlayer)
        {
            if (depth == 0 || node.IsTerminalNode())
            {
                return Utility.Score(node);
            }

            if (maxPlayer)
            {
                int bestValue = Int32.MinValue;
                node.Children = Utility.GenerateSuccessors(node.Board, false);
                for (var i = 0; i < node.Children.Count; i++)
                {
                    var currentValue = Search(node.Children[i], depth - 1, false);
                    bestValue = Math.Max(bestValue, currentValue);
                }

                return bestValue;
            }

            else
            {
                int bestValue = Int32.MaxValue;
                node.Children = Utility.GenerateSuccessors(node.Board, true);
                for (var i = 0; i < node.Children.Count; i++)
                {
                    var currentValue = Search(node.Children[i], depth - 1, true);
                    bestValue = Math.Max(bestValue, currentValue);
                }
                return bestValue;
            }
        }
Пример #3
0
        //This method will search all the columns and return the best move for the AI to make.
        //Will run AlphaBeta or regular Minimax depending on user selection.
        public static int AiHelperMove(Board board, bool alphabeta, int depth)
        {
            var rows = board.State.GetLength(1) - 1;
            int bestValue = Int32.MinValue;
            int bestColumn = -1;

           
            if (alphabeta)
            {
                MiniMaxAb miniMaxAb = new MiniMaxAb();
                for (var i = 0; i <= rows; i++)
                {
                    var node = new Node();
                    var tempBoard = new Board(board.State);
                    if (tempBoard.ValidateMove(i))
                    {
                        tempBoard.AddToBoard(i, true);
                        node.Board = tempBoard;
                        var currentValue = miniMaxAb.Search(node, depth, Int32.MinValue, Int32.MaxValue, false);
                        if (currentValue >= bestValue)
                        {
                            bestValue = currentValue;
                            bestColumn = i;
                        }
                    }
                }
            }
            else
            {
                MiniMax miniMax = new MiniMax();
                for (var i = 0; i <= rows; i++)
                {
                    var node = new Node();
                    var tempBoard = new Board(board.State);
                    if (tempBoard.ValidateMove(i))
                    {
                        tempBoard.AddToBoard(i, true);
                        node.Board = tempBoard;
                        var currentValue = miniMax.Search(node, depth, false);
                        if (currentValue >= bestValue)
                        {
                            bestValue = currentValue;
                            bestColumn = i;
                        }
                    }
                }
            }

            
            return bestColumn;
        }
Пример #4
0
        //Search with alpha beta pruning
        public int Search(Node node, int depth, int alpha, int beta, bool maxPlayer)
        {
            if (depth == 0 || node.IsTerminalNode())
            {
                return Utility.Score(node);
            }

            if (maxPlayer)
            {
                int bestValue = Int32.MinValue;
                node.Children = Utility.GenerateSuccessors(node.Board, false);
                for (var i = 0; i < node.Children.Count; i++)
                {
                    bestValue = Math.Max(bestValue, Search(node.Children[i], depth - 1, alpha, beta, false));
                    alpha = Math.Max(bestValue, bestValue);
                    if (beta <= alpha)
                    {
                        break;
                    }
                }

                return alpha;
            }

            else
            {
                int bestValue = Int32.MaxValue;
                node.Children = Utility.GenerateSuccessors(node.Board, true);
                for (var i = 0; i < node.Children.Count; i++)
                {
                    bestValue = Math.Min(bestValue, Search(node.Children[i], depth - 1, alpha, beta, true));
                    beta = Math.Min(beta, bestValue);
                    if (beta <= alpha)
                    {
                        break;
                    }
                }
                return beta;
            }
        }
Пример #5
0
        //Same as above, except it returns a Tuple with both Black and White scores.
        public static Tuple<int, int> FinalScore(Node node)
        {
            var row = node.Board.State.GetLength(0);
            var col = node.Board.State.GetLength(1);
            var BlackScore = 0;
            var WhiteScore = 0;
            node.Board.ResetVisited();
            //Console.WriteLine("\n");
            //Console.WriteLine("Scoring The following Board");
            //node.Board.PrintState();

            for (var i = 0; i < row; i++)
            {
                for (var j = 0; j < col; j++)
                {
                    //Get first piece found
                    if (node.Board.State[i, j] != null)
                    {
                        var piece = node.Board.State[i, j];

                        //Get list of Adjacent pieces
                        var adjacentPieces = GetAdjacentPieces(piece, node.Board);

                        //Compare piece to each adj piece, if its diag/or not, and add up score
                        foreach (var tuple in adjacentPieces)
                        {
                            //If piece has been visited or is another color, skip it.
                            if (tuple.Item2 != null && !tuple.Item2.Visited)
                            {
                                if (tuple.Item1) //if true, its a diagonal score
                                {
                                    if (piece.IsBlack && tuple.Item2.IsBlack)
                                    {
                                        BlackScore++;
                                        piece.Visited = true;
                                    }
                                    else if (!piece.IsBlack && !tuple.Item2.IsBlack)
                                    {
                                        WhiteScore++;
                                        piece.Visited = true;
                                    }
                                }
                                else //Its a normal position worth 2 points
                                {
                                    if (piece.IsBlack && tuple.Item2.IsBlack)
                                    {
                                        BlackScore += 2;
                                        piece.Visited = true;
                                    }
                                    else if (!piece.IsBlack && !tuple.Item2.IsBlack)
                                    {
                                        WhiteScore += 2;
                                        piece.Visited = true;
                                    }
                                }
                            }
                        }


                    }
                }
            }
            return Tuple.Create(WhiteScore, BlackScore);
        }
Пример #6
0
        static void Main(string[] args)
        {
            //Following is setup for AI and board
            Console.WriteLine("Welcome to Simacogo! You are Player 1, Color white.");
            Console.WriteLine("At any time, type 'exit' to leave the game!");
            Console.WriteLine("----------------------------------------------------------");
            Console.WriteLine("\n");
            Console.WriteLine("Enter # of plies for AI to search to? (numeric only)");
            var depth = Int32.Parse(Console.ReadLine()); //AI lookahead value

            Console.WriteLine("\n");
            Console.WriteLine("Enable Alpha Beta Pruning? (True or False)");
            var alphabeta = Boolean.Parse(Console.ReadLine()); //AI lookahead value

            Console.WriteLine("\n");
            Console.WriteLine("Enter board width? (numeric only)");
            var width = Int32.Parse(Console.ReadLine()); //Board width

            Console.WriteLine("Enter board height? (numeric only)");
            var height = Int32.Parse(Console.ReadLine()); //Board height

            Console.WriteLine("\n");
            Board board = new Board(width, height);
            bool humanTurn = true;
            bool runProgram = true;
            while (!board.IsFull() && runProgram)
            {
                if (humanTurn)
                {
                    Console.WriteLine("--------------------Begin Human Turn-----------------------------------");
                    Console.WriteLine("Please type the column you want to drop a piece into and press enter. (1-9)");
                    string enteredValue = Console.ReadLine();
                    if (enteredValue.Equals("exit"))
                    {
                        runProgram = false;
                        break;
                    }
                    int colValue = Int32.MinValue;
                    Int32.TryParse(enteredValue, out colValue);
                    if (colValue > 0 && colValue < 10 && board.ValidateMove(colValue-1))
                    {
                        //Get column from User && Create new piece and enter it in the board at deepest possible position in column.
                        board.AddToBoard(colValue-1, false);
                        board.PrintState();

                        var node = new Node();
                        node.Board = board;
                        var score = Utility.FinalScore(node);
                        Console.WriteLine("\n");
                        Console.WriteLine("Current Score: \n");
                        Console.WriteLine("Human: " + score.Item1);
                        Console.WriteLine("AI " + score.Item2);
                        Console.WriteLine("--------------------End Human Turn----------------------");
                        Console.WriteLine("\n");
                        humanTurn = !humanTurn;
                    }
                    else
                    {
                        Console.WriteLine("Invalid selection, please try again.");
                    }

                    
                }
                else
                {
                    Console.WriteLine("--------------------Begin AI Turn--------------------");
                    //Let AI player pick position
                    //Update Board
                    //AI Runs either Miniax or MinimaxAB depending on user selection.
                    var bestMove = Utility.AiHelperMove(board, alphabeta, depth);

                    board.AddToBoard(bestMove, true);
                    board.PrintState();
                    var node = new Node();
                    node.Board = board;
                    var score = Utility.FinalScore(node);
                    Console.WriteLine("\n");
                    Console.WriteLine("Current Score: \n");
                    Console.WriteLine("Human: " + score.Item1);
                    Console.WriteLine("AI " + score.Item2);
                    Console.WriteLine("\n");
                    Console.WriteLine("--------------------End AI Turn----------------------");
                    humanTurn = !humanTurn;
                }
            }

            Console.WriteLine("\n");
            Console.WriteLine("Gameboard is Full!");
            Console.WriteLine("\n");
            var finalNode = new Node();
            var tempBoard = new Board(board.State);
            finalNode.Board = tempBoard;
            var finalScore = Utility.FinalScore(finalNode);
            Console.WriteLine("Final Board");
            Console.WriteLine("\n");
            board.PrintState();
            Console.WriteLine("\n");
            Console.WriteLine("Final Score Is: ");
            Console.WriteLine("Human: " + finalScore.Item1);
            Console.WriteLine("AI: " + finalScore.Item2);

            Console.WriteLine("Thank you for playing Simacogo! Application will close in 5 seconds.");

            
            System.Threading.Thread.Sleep(5000);



        }