Ejemplo n.º 1
0
        /// <summary>
        /// Perform the CPU's Move
        /// </summary>
        /// <param name="random">Make a random move?</param>
        private void makeCPUsMove(int OsRow, int OsCol, bool random = false)
        {
            int row = 0, col = 0;

            // If to make a random move
            if (random)
            {
                Random rand = new Random();
                row = rand.Next(0, 4);
                col = rand.Next(0, 5);
                // pictureBox_click(Controls["pic" + row.ToString() + col.ToString()], new EventArgs());
            }
            // Else make a move based on Alpha-Beta Search
            else
            {
                GameTreeNode gtn = new GameTreeNode(gameBoard, OsRow, OsCol);
                gtn.NextTurn = (State)Turn;
                SearchTree gt = new SearchTree();
                gtn.Text = "Root";
                GameTreeNode newMove;
                if (gt.insertNode(gtn))
                {
                    newMove = gt.immResult;
                }
                else
                {
                    newMove = gt.getNextBestMove();
                    //gt.ShowDialog();
                }
                row = newMove.Row;
                col = newMove.Column;
            }
            // Perform a click operation at on the PictureBox
            pictureBox_click(Controls["pic" + row.ToString() + col.ToString()], new EventArgs());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Recursively expand nodex till the depth is met
        /// </summary>
        /// <param name="tn">TreeNode to expand</param>
        /// <param name="depth">Depth till which to expand</param>
        public void ExpandNode(TreeNode tn, int depth)
        {
            // If depth is reached return
            if (depth <= 0)
            {
                return;
            }

            GameTreeNode gtn = (GameTreeNode)tn;

            // Expand the node only if the Board of the node is Incomplete, otherwise no need to expand
            if (gtn.NodeBoard.getBoardStatus() == Status.Incomplete)
            {
                // Clear previous nodes, if any
                gtn.Nodes.Clear();

                // Generate the child nodes for the given node
                gtn.Nodes.AddRange(generateSubTree(gtn));
            }

            foreach (TreeNode child in gtn.Nodes)
            {
                // Expand node for each of the child nodes in the current node
                ExpandNode(child, depth - 1);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generates child nodes for the given node
        /// </summary>
        /// <param name="selectedNode">Node for which the child nodes are to be generated</param>
        /// <returns>Returns the list of generated child nodes</returns>
        private GameTreeNode[] generateSubTree(GameTreeNode selectedNode)
        {
            List <GameTreeNode> gtns = new List <GameTreeNode>();

            // Get the current board
            Board currentBoard = new Board(selectedNode.NodeBoard);

            // For each possible moves available on the board, generate a child node
            // and add it to the list of child nodes
            for (int i = 0; i < Globals.ROWS; ++i)
            {
                for (int j = 0; j < Globals.COLS; ++j)
                {
                    if (currentBoard[i, j] == State.N)
                    {
                        Board temp = new Board(currentBoard);
                        // Create a possible move upon the current board
                        temp[i, j] = selectedNode.NextTurn;

                        // Generate a child node with the possible board and mark down the
                        // position at which the new move is made
                        GameTreeNode childNode = new GameTreeNode(temp, i, j);
                        childNode.NextTurn = (State)((int)selectedNode.NextTurn % 2 + 1);

                        // Enlist the child node
                        gtns.Add(childNode);
                    }
                }
            }

            // Return the list of nodes
            return(gtns.ToArray());
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Performs the maximum search at the given depth i.e. Maximizes the chance for X
        /// </summary>
        /// <param name="state">The current state</param>
        /// <param name="alpha">The alpha value for the state</param>
        /// <param name="beta">The beta value for the state</param>
        /// <returns>Estimated value for the give state</returns>
        private static int MaxValue(GameTreeNode state, int alpha, int beta)
        {
            // if Terminal-test(state) then return utitly(state)
            if (state.Nodes.Count == 0)
            {
                return(utility(state));
            }

            // v = -Inf
            state.Value = Globals.MININT;

            // Foreach action in state.Actions do
            foreach (GameTreeNode action in state.Nodes)
            {
                // v <- Max(v, MinValue(Result(s, a), alpha, beta))
                state.Value = Math.Max(state.Value, MinValue(action, alpha, beta));

                // Pruning steps
                if (state.Value >= beta)
                {
                    return(state.Value);
                }
                alpha = Math.Max(alpha, state.Value);
            }

            // Return state value
            return(state.Value);
        }
Ejemplo n.º 5
0
        private static int MinValue(GameTreeNode state, int alpha, int beta)
        {
            // if Terminal-test(state) then return utitly(state)
            if (state.Nodes.Count == 0)
            {
                return(utility(state));
            }

            // v = +Inf;
            state.Value = Globals.MAXINT;

            // Foreach action in state.Actions do
            foreach (GameTreeNode child in state.Nodes)
            {
                // v <- Max(v, MinValue(Result(s, a), alpha, beta))
                state.Value = Math.Min(state.Value, MaxValue(child, alpha, beta));

                // Pruning steps
                if (state.Value <= alpha)
                {
                    return(state.Value);
                }
                beta = Math.Min(beta, state.Value);
            }

            // Return state value
            return(state.Value);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Initializes the Minimax Search i.e. the Alpha Beta Search Algorithm
        /// </summary>
        /// <param name="state">The current state of the tree i.e the root node of the minimax tree</param>
        /// <returns>The next possible best move</returns>
        public static GameTreeNode MinMax(GameTreeNode state)
        {
            // Gets the maximum value for the root node
            int bestValue = MaxValue(state, Globals.MININT, Globals.MAXINT);

            // Find the node with maximum value in the list of childs of the root node
            foreach (GameTreeNode action in state.Nodes)
            {
                if (action.Value == bestValue)
                {
                    return(action);
                }
            }

            // By default return the first child of the root
            return((GameTreeNode)state.Nodes[0]);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Initializes the Minimax Search i.e. the Alpha Beta Search Algorithm
        /// </summary>
        /// <param name="state">The current state of the tree i.e the root node of the minimax tree</param>
        /// <returns>The next possible best move</returns>
        public static GameTreeNode MinMax(GameTreeNode state)
        {
            // Gets the maximum value for the root node
            int bestValue = MaxValue(state, Globals.MININT, Globals.MAXINT);

            // Find the node with maximum value in the list of childs of the root node
            foreach (GameTreeNode action in state.Nodes)
            {
                if (action.Value == bestValue)
                {
                    return action;
                }
            }

            // By default return the first child of the root
            return (GameTreeNode)state.Nodes[0];
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Create the first root node expands the root node
        /// </summary>
        /// <param name="gtn">The root game node</param>
        /// <returns>Returns true if immediate move is possible, otherwise false</returns>
        public bool insertNode(GameTreeNode gtn)
        {
            // Clear the previous nodes, if any
            GameTree.Nodes.Clear();

            // Add the root node to tree
            GameTree.Nodes.Add(gtn);

            // Immediate move is explained below
            // If immediate move is available return true
            if (immediateResult(new GameTreeNode(gtn.NodeBoard, gtn.Row, gtn.Column)))
                return true;

            // Else start expanding the nodes from the root to the given depth
            ExpandNode(gtn, getDepth(gtn.NodeBoard.numberOfEmptyStates()));

            // And return false for not immediate moves
            return false;
        }
Ejemplo n.º 9
0
        /// <summary>
        /// The utility function calculates the value of the give node in the tree
        /// </summary>
        /// <param name="state">The node to be evaluated</param>
        /// <returns>Either +200 for X, -200 for O or appropriate evaluated value</returns>
        private static int utility(GameTreeNode state)
        {
            switch (state.NodeBoard.getBoardStatus())
            {
            // Success for X, return +200
            case Status.Success:
                return(200);

            // Success for O i.e. Failure for X, return -200
            case Status.Failure:
                return(-200);

            // Incomplete do Eval for the state
            case Status.Incomplete:
                return(state.evaluate());
            }
            // Draw return 0
            return(0);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Immediate move allows the CPU to mark down the Board with a winning move without expanding and working
        /// on Alpha Beta Search tree. This move facilitates quicker performance and more accuracy and more winning
        /// chance for X
        /// </summary>
        /// <param name="gtn">Node for which the immediate move is to be calculated</param>
        /// <returns></returns>
        private bool immediateResult(GameTreeNode gtn)
        {
            // Mark down the node for X's move
            gtn.NextTurn = State.X;

            // Generate list of immediate moves
            gtn.Nodes.AddRange(generateSubTree(gtn));
            foreach (TreeNode child in gtn.Nodes)
            {
                // If the immediate move results in success, return true
                if (((GameTreeNode)child).NodeBoard.getBoardStatus() == Status.Success)
                {
                    immResult = (GameTreeNode)child;
                    return(true);
                }
            }

            // Return false otherwise
            return(false);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Create the first root node expands the root node
        /// </summary>
        /// <param name="gtn">The root game node</param>
        /// <returns>Returns true if immediate move is possible, otherwise false</returns>
        public bool insertNode(GameTreeNode gtn)
        {
            // Clear the previous nodes, if any
            GameTree.Nodes.Clear();

            // Add the root node to tree
            GameTree.Nodes.Add(gtn);

            // Immediate move is explained below
            // If immediate move is available return true
            if (immediateResult(new GameTreeNode(gtn.NodeBoard, gtn.Row, gtn.Column)))
            {
                return(true);
            }

            // Else start expanding the nodes from the root to the given depth
            ExpandNode(gtn, getDepth(gtn.NodeBoard.numberOfEmptyStates()));

            // And return false for not immediate moves
            return(false);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Performs the maximum search at the given depth i.e. Maximizes the chance for X
        /// </summary>
        /// <param name="state">The current state</param>
        /// <param name="alpha">The alpha value for the state</param>
        /// <param name="beta">The beta value for the state</param>
        /// <returns>Estimated value for the give state</returns>
        private static int MaxValue(GameTreeNode state, int alpha, int beta)
        {
            // if Terminal-test(state) then return utitly(state)
            if (state.Nodes.Count == 0) return utility(state);

            // v = -Inf
            state.Value = Globals.MININT;

            // Foreach action in state.Actions do
            foreach (GameTreeNode action in state.Nodes)
            {
                // v <- Max(v, MinValue(Result(s, a), alpha, beta))
                state.Value = Math.Max(state.Value, MinValue(action, alpha, beta));

                // Pruning steps
                if (state.Value >= beta)
                    return state.Value;
                alpha = Math.Max(alpha, state.Value);
            }

            // Return state value
            return state.Value;
        }
Ejemplo n.º 13
0
        private static int MinValue(GameTreeNode state, int alpha, int beta)
        {
            // if Terminal-test(state) then return utitly(state)
            if (state.Nodes.Count == 0) return utility(state);

            // v = +Inf;
            state.Value = Globals.MAXINT;

            // Foreach action in state.Actions do
            foreach (GameTreeNode child in state.Nodes)
            {
                // v <- Max(v, MinValue(Result(s, a), alpha, beta))
                state.Value = Math.Min(state.Value, MaxValue(child, alpha, beta));

                // Pruning steps
                if (state.Value <= alpha)
                    return state.Value;
                beta = Math.Min(beta, state.Value);
            }

            // Return state value
            return state.Value;
        }
Ejemplo n.º 14
0
 /// <summary>
 /// Perform the CPU's Move
 /// </summary>
 /// <param name="random">Make a random move?</param>
 private void makeCPUsMove(int OsRow, int OsCol, bool random = false)
 {
     int row = 0, col = 0;
     // If to make a random move
     if (random)
     {
         Random rand = new Random();
         row = rand.Next(0, 4);
         col = rand.Next(0, 5);
         // pictureBox_click(Controls["pic" + row.ToString() + col.ToString()], new EventArgs());
     }
     // Else make a move based on Alpha-Beta Search
     else
     {
         GameTreeNode gtn = new GameTreeNode(gameBoard, OsRow, OsCol);
         gtn.NextTurn = (State)Turn;
         SearchTree gt = new SearchTree();
         gtn.Text = "Root";
         GameTreeNode newMove;
         if (gt.insertNode(gtn))
             newMove = gt.immResult;
         else
         {
             newMove = gt.getNextBestMove();
             //gt.ShowDialog();
         }
         row = newMove.Row;
         col = newMove.Column;
     }
     // Perform a click operation at on the PictureBox
     pictureBox_click(Controls["pic" + row.ToString() + col.ToString()], new EventArgs());
 }
Ejemplo n.º 15
0
 /// <summary>
 /// The utility function calculates the value of the give node in the tree
 /// </summary>
 /// <param name="state">The node to be evaluated</param>        
 /// <returns>Either +200 for X, -200 for O or appropriate evaluated value</returns>
 private static int utility(GameTreeNode state)
 {
     switch (state.NodeBoard.getBoardStatus())
     {
             // Success for X, return +200
         case Status.Success:
             return 200;
             // Success for O i.e. Failure for X, return -200
         case Status.Failure:
             return -200;
             // Incomplete do Eval for the state
         case Status.Incomplete:
             return state.evaluate();
     }
     // Draw return 0
     return 0;
 }
Ejemplo n.º 16
0
 /// <summary>
 /// Constructor: Initializes the variables
 /// </summary>
 public SearchTree()
 {
     immResult = new GameTreeNode();
     GameTree  = new GameTreeNode();
 }
Ejemplo n.º 17
0
 /// <summary>
 /// Constructor: Initializes the variables
 /// </summary>
 public SearchTree()
 {
     immResult = new GameTreeNode();
     GameTree = new GameTreeNode();
 }
Ejemplo n.º 18
0
        /// <summary>
        /// Immediate move allows the CPU to mark down the Board with a winning move without expanding and working
        /// on Alpha Beta Search tree. This move facilitates quicker performance and more accuracy and more winning
        /// chance for X
        /// </summary>
        /// <param name="gtn">Node for which the immediate move is to be calculated</param>
        /// <returns></returns>
        private bool immediateResult(GameTreeNode gtn)
        {
            // Mark down the node for X's move
            gtn.NextTurn = State.X;

            // Generate list of immediate moves
            gtn.Nodes.AddRange(generateSubTree(gtn));
            foreach (TreeNode child in gtn.Nodes)
            {
                // If the immediate move results in success, return true
                if (((GameTreeNode)child).NodeBoard.getBoardStatus() == Status.Success)
                {
                    immResult = (GameTreeNode)child;
                    return true;
                }
            }

            // Return false otherwise
            return false;
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Generates child nodes for the given node
        /// </summary>
        /// <param name="selectedNode">Node for which the child nodes are to be generated</param>
        /// <returns>Returns the list of generated child nodes</returns>
        private GameTreeNode[] generateSubTree(GameTreeNode selectedNode)
        {
            List<GameTreeNode> gtns = new List<GameTreeNode>();

            // Get the current board
            Board currentBoard = new Board(selectedNode.NodeBoard);

            // For each possible moves available on the board, generate a child node
            // and add it to the list of child nodes
            for (int i = 0; i < Globals.ROWS; ++i)
                for (int j = 0; j < Globals.COLS; ++j)
                    if (currentBoard[i, j] == State.N)
                    {
                        Board temp = new Board(currentBoard);
                        // Create a possible move upon the current board
                        temp[i, j] = selectedNode.NextTurn;

                        // Generate a child node with the possible board and mark down the
                        // position at which the new move is made
                        GameTreeNode childNode = new GameTreeNode(temp, i, j);
                        childNode.NextTurn = (State)((int)selectedNode.NextTurn % 2 + 1);

                        // Enlist the child node
                        gtns.Add(childNode);
                    }

            // Return the list of nodes
            return gtns.ToArray();
        }