New Town, Rajarhat Kolkata-700156 1 Search Process! Searching is defined as a sequence of steps that transforms the initial state to the goal state. To do a search process, the following are needed: The initial state description of the problem A set of legal operators that changes the state. The final or goal state. The searching process in AI can be classified into two types: 1. Brute Forcw Search/ Uniformed Search/ Blind Search 2. Heuristic Search/ Informed Search Uniformed/ Brute Force/Blind Search! A uniformed search algorithm is one that do not have any domain specific knowledge. They use information like initial state, final state and a set of logical operators. this search should proceed in a systemic way by exploring nodes in some predetermined orders. It can be classified in to two search technologies: 1. Breadth First search 2. Depth First Search Depth First Search! Depth first search works by taking a node, checking its neighbors, expanding the first node it finds among the neighbors, checking if that expanded node is our destination, and if not, continue exploring more nodes. The above explanation is probably confusing if this is your first exposure to depth first search. I hope the following demonstration will help more. Using our same search tree, let's find a path between nodes A and F: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 2 Step 0 Let's start with our root/goal node: We will be using two lists to keep track of what we are doing - an Open list and a Closed List. An Open list keeps track of what you need to do, and the Closed List keeps track of what you have already done. Right now, we only have our starting point, node A. We haven't done anything to it yet, so let's add it to our Open list. Open List: A Closed List: <empty> Step 1 Now, let's explore the neighbors of our A node. To put another way, let's take the first item from our Open list and explore its neighbors: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 3 Node A's neighbors are the B and C nodes. Because we are now done with our A node, we can remove it from our Open list and add it to our Closed List. You aren't done with this step though. You now have two new nodes B and C that need exploring. Add those two nodes to our Open list. Our current Open and Closed Lists contain the following data: Open List: B, C Closed List: A Step 2 Our Open list contains two items. For depth first search and breadth first search, you always explore explore the first item from our Open list. The first item in our Open list is the B node. B is not our destination, so let's explore its neighbors: Because I have now expanded B, I am going to remove it from the Open list and add it to the Closed List. Our new nodes are D and E, and we add these nodes to the beginning of our Open list: Open List: D, E, C Closed List: A, B Step 3 Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 4 You should start to see a pattern forming. Because D is at the beginning of our Open List, we expand it. D isn't our destination, and it does not contain any neighbors. All you do in this step is remove D from our Open List and add it to our Closed List: Open List: E, C Closed List: A, B, D Step 4 We now expand the E node from our Open list. E is not our destination, so we explore its neighbors and find out that it contains the neighbors F and G. Remember, F is our target, but we don't stop here though. Despite F being on our path, we only end when we are about to expand our target Node - F in this case: Our Open list will have the E node removed and the F and G nodes added. The removed E node will be added to our Closed List: Open List: F, G, C Closed List: A, B, D, E Step 5 We now expand the F node. Since it is our intended destination, we stop: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 5 We remove F from our Open list and add it to our Closed List. Since we are at our destination, there is no need to expand F in order to find its neighbors. Our final Open and Closed Lists contain the following data: Open List: G, C Closed List: A, B, D, E, F The final path taken by our depth first search method is what the final value of our Closed List is: A, B, D, E, F. Breadth First Search! In depth first search, newly explored nodes were added to the beginning of your Open list. In breadth first search, newly explored nodes are added to the end of your Open list. For example, here is our original search tree: The above explanation is probably confusing if this is your first exposure to depth first search. I hope the following demonstration will help more. Using our same search tree, let's find a path between nodes A and F: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 6 Step 0 Let's start with our root/goal node: We will be using two lists to keep track of what we are doing - an Open list and a Closed List. An Open list keeps track of what you need to do, and the Closed List keeps track of what you have already done. Right now, we only have our starting point, node A. We haven't done anything to it yet, so let's add it to our Open list. Open List: A Closed List: <empty> Step 1 Now, let's explore the neighbors of our A node. To put another way, let's take the first item from our Open list and explore its neighbors: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 7 Node A's neighbors are the B and C nodes. Because we are now done with our A node, we can remove it from our Open list and add it to our Closed List. You aren't done with this step though. You now have two new nodes B and C that need exploring. Add those two nodes to our Open list. Our current Open and Closed Lists contain the following data: Open List: B, C Closed List: A Step 2 Our Open list contains two items. For depth first search and breadth first search, you always explore explore the first item from our Open list. The first item in our Open list is the B node. B is not our destination, so let's explore its neighbors: Because I have now expanded B, I am going to remove it from the Open list and add it to the Closed List. Our new nodes are D and E, and we add these nodes to the beginning of our Open list: Open List: D, E, C Closed List: A, B Step 3 Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 8 You should start to see a pattern forming. Because D is at the beginning of our Open List, we expand it. D isn't our destination, and it does not contain any neighbors. All you do in this step is remove D from our Open List and add it to our Closed List: Open List: E, C Closed List: A, B, D Step 4 We now expand the E node from our Open list. E is not our destination, so we explore its neighbors and find out that it contains the neighbors F and G. Remember, F is our target, but we don't stop here though. Despite F being on our path, we only end when we are about to expand our target Node - F in this case: Our Open list will have the E node removed and the F and G nodes added. The removed E node will be added to our Closed List: Open List: F, G, C Closed List: A, B, D, E Step 5 We now expand the F node. Since it is our intended destination, we stop: Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 9 We remove F from our Open list and add it to our Closed List. Since we are at our destination, there is no need to expand F in order to find its neighbors. Our final Open and Closed Lists contain the following data: Open List: G, C Closed List: A, B, D, E, F The final path taken by our depth first search method is what the final value of our Closed List is: A, B, D, E, F. Iterative Deepening Depth-First Search! Iterative deepening depth-first search (IDDFS) is a state space search strategy in which a depth- limited search is run repeatedly, increasing the depth limit with each iteration until it reaches d, the depth of the shallowest goal state. On each iteration, IDDFS visits the nodes in the search tree in the same order as depth-first search, but the cumulative order in which nodes are first visited, assuming no pruning, is effectively breadth-first. IDDFS combines depth-first search's space-efficiency and breadth-first search's completeness (when the branching factor is finite). It is optimal when the path cost is a non-decreasing function of the depth of the node. The space complexity of IDDFS is O(bd), where b is the branching factor and d is the depth of shallowest goal. Since iterative deepening visits states multiple times, it may seem wasteful, but it Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 10 turns out to be not so costly, since in a tree most of the nodes are in the bottom level, so it does not matter much if the upper levels are visited multiple times. The main advantage of IDDFS in game tree searching is that the earlier searches tend to improve the commonly used heuristics, such as the killer heuristic and alpha-beta pruning, so that a more accurate estimate of the score of various nodes at the final depth search can occur, and the search completes more quickly since it is done in a better order. For example, alpha-beta pruning is most efficient if it searches the best moves first. A second advantage is the responsiveness of the algorithm. Because early iterations use small values for d, they execute extremely quickly. This allows the algorithm to supply early indications of the result almost immediately, followed by refinements as d increases. When used in an interactive setting, such as in a chess-playing program, this facility allows the program to play at any time with the current best move found in the search it has completed so far. This is not possible with a traditional depth-first search. The time complexity of IDDFS in well-balanced trees works out to be the same as Depth-first search: O(bd). In an iterative deepening search, the nodes on the bottom level are expanded once, those on the next to bottom level are expanded twice, and so on, up to the root of the search tree, which is expanded d + 1 times.[1] So the total number of expansions in an iterative deepening search is All together, an iterative deepening search from depth 1 to depth d expands only about 11% more nodes than a single breadth-first or depth-limited search to depth d, when b = 10. The higher the branching factor, the lower the overhead of repeatedly expanded states, but even when the branching factor is 2, iterative deepening search only takes about twice as long as a complete Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 11 breadth-first search. This means that the time complexity of iterative deepening is still O(b d ), and the space complexity is O(bd). In general, iterative deepening is the preferred search method when there is a large search space and the depth of the solution is not known. Informed Search! It is not difficult to see that uninformed search will pursue options that lead away from the goal as easily as it pursues options that lead to wards the goal. For any but the smallest problems this leads to searches that take unacceptable amounts of time and/or space. Informed search tries to reduce the amount of search that must be done by making intelligent choices for the nodes that are selected for expansion. This implies the existence of some way of evaluating the likelyhood that a given node is on the solution path. In general this is done using a heuristic function. Hill Climbing! Hill climbing is a mathematical optimization technique which belongs to the family of local search. It is relatively simple to implement, making it a popular first choice. Although more advanced algorithms may give better results, in some situations hill climbing works just as well. Hill climbing can be used to solve problems that have many solutions, some of which are better than others. It starts with a random (potentially poor) solution, and iteratively makes small changes to the solution, each time improving it a little. When the algorithm cannot see any improvement anymore, it terminates. Ideally, at that point the current solution is close to optimal, but it is not guaranteed that hill climbing will ever come close to the optimal solution. For example, hill climbing can be applied to the traveling salesman problem. It is easy to find a solution that visits all the cities but will be very poor compared to the optimal solution. The algorithm starts with such a solution and makes small improvements to it, such as switching the order in which two cities are visited. Eventually, a much better route is obtained. Hill climbing is used widely in artificial intelligence, for reaching a goal state from a starting node. Choice of next node and starting node can be varied to give a list of related algorithms. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 12 Mathematical description Hill climbing attempts to maximize (or minimize) a function f(x), where x are discrete states. These states are typically represented by vertices in a graph, where edges in the graph encode nearness or similarity of a graph. Hill climbing will follow the graph from vertex to vertex, always locally increasing (or decreasing) the value of f, until a local maximum (or local minimum) xm is reached. Hill climbing can also operate on a continuous space: in that case, the algorithm is called gradient ascent (or gradient descent if the function is minimized).*. Variants In simple hill climbing, the first closer node is chosen, whereas in steepest ascent hill climbing all successors are compared and the closest to the solution is chosen. Both forms fail if there is no closer node, which may happen if there are local maxima in the search space which are not solutions. Steepest ascent hill climbing is similar to best-first search, which tries all possible extensions of the current path instead of only one. Stochastic hill climbing does not examine all neighbors before deciding how to move. Rather, it selects a neighbor at random, and decides (based on the amount of improvement in that neighbor) whether to move to that neighbor or to examine another. Random-restart hill climbing is a meta-algorithm built on top of the hill climbing algorithm. It is also known as Shotgun hill climbing. It iteratively does hill-climbing, each time with a random initial Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 13 condition x 0 . The best x m is kept: if a new run of hill climbing produces a better xm than the stored state, it replaces the stored state. Random-restart hill climbing is a surprisingly effective algorithm in many cases. It turns out that it is often better to spend CPU time exploring the space, than carefully optimizing from an initial condition. Local Maxima A problem with hill climbing is that it will find only local maxima. Unless the heuristic is convex, it may not reach a global maximum. Other local search algorithms try to overcome this problem such as stochastic hill climbing, random walks and simulated annealing. Ridges A ridge is a curve in the search place that leads to a maximum, but the orientation of the ridge compared to the available moves that are used to climb is such that each move will lead to a smaller point. In other words, each point on a ridge looks to the algorithm like a local maximum, even though the point is part of a curve leading to a better optimum. Plateau Another problem with hill climbing is that of a plateau, which occurs when we get to a "flat" part of the search space, i.e. we have a path where the heuristics are all very close together. This kind of flatness can cause the algorithm to cease progress and wander aimlessly. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 14 Pseudo code Hill Climbing Algorithm currentNode = startNode; loop do L = NEIGHBORS(currentNode); nextEval = -INF; nextNode = NULL; for all x in L if (EVAL(x) > nextEval) nextNode = x; nextEval = EVAL(x); if nextEval <= EVAL(currentNode) //Return current node since no better neighbors exist return currentNode; currentNode = nextNode; Best-First Search! Best-first search is a search algorithm which explores a graph by expanding the most promising node chosen according to a specified rule. Judea Pearl described best-first search as estimating the promise of node n by a "heuristic evaluation function f(n) which, in general, may depend on the description of n, the description of the goal, the information gathered by the search up to that point, and most important, on any extra knowledge about the problem domain." Some authors have used "best-first search" to refer specifically to a search with a heuristic that attempts to predict how close the end of a path is to a solution, so that paths which are judged to be closer to a solution are extended first. This specific type of search is called greedy best-first search. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 15 Efficient selection of the current best candidate for extension is typically implemented using a priority queue. Examples of best-first search algorithms include the A* search algorithm, and in turn, Dijkstra's algorithm (which can be considered a specialization of A*). Best-first algorithms are often used for path finding in combinatorial search. Code open = initial state while open != null do 1. Pick the best node on open. 2. Create open's successors 3. For each successor do: a. If it has not been generated before: evaluate it, add it to OPEN, and record its parent b. Otherwise: change the parent if this new path is better than previous one. done A* Algorithm! A* (pronounced "A star") is a best-first graph search algorithm that finds the least-cost path from a given initial node to one goal node (out of one or more possible goals). It uses a distance-plus-cost heuristic function (usually denoted f(x)) to determine the order in which the search visits nodes in the tree. The distance-plus-cost heuristic is a sum of two functions: the path-cost function (usually denoted g(x), which may or may not be a heuristic) and an admissible "heuristic estimate" of the distance to the goal (usually denoted h(x)). The path-cost function g(x) is the cost from the starting node to the current node. The h(x) part of the f(x) function must be an admissible heuristic; that is, it must not overestimate the distance to the goal. Thus for an application like routing, h(x) might represent the straight-line Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 16 distance to the goal, since that is physically the smallest possible distance between any two points (or nodes for that matter). If the heuristic h satisfies the additional condition for every edge x, y of the graph (d denoting the length of that edge) then h is called monotone or consistent. In this case A* can be implemented more efficiently roughly speaking, no node needs to be processed more than once (see closed set below) and in fact A* is equivalent to running Dijkstra's algorithm with the reduced cost d'(x,y): = d(x,y) h(x) + h(y). The algorithm was first described in 1968 by Peter Hart, Nils Nilsson, and Bertram Raphael. This algorithm has been generalized into a bidirectional heuristic search algorithm; see bidirectional search. Properties Like breadth-first search, A* is complete in the sense that it will always find a solution if there is one. If the heuristic function h is admissible, meaning that it never overestimates the actual minimal cost of reaching the goal, then A* is itself admissible (or optimal) if we do not use a closed set. If a closed set is used, then h must also be monotonic (or consistent) for A* to be optimal. This means that for any pair of adjacent nodes x and y, where d(x,y) denotes the length of the edge between them, we must have: This ensures that for any path X from the initial node to x: where L(.) denotes the length of a path, and Y is the path X extended to include y. In other words, it is impossible to decrease (total distance so far + estimated remaining distance) by extending a path to include a neighboring node. (This is analogous to the restriction to nonnegative edge weights in Dijkstra's algorithm.) Monotonicity implies admissibility when the heuristic estimate at any goal node Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 17 itself is zero, since (letting P = (f,v 1 ,v 2 ,....,v n ,g) be a shortest path from any node f to the nearest goal g): A* is also optimally efficient for any heuristic h, meaning that no algorithm employing the same heuristic will expand fewer nodes than A*, except when there are multiple partial solutions where h exactly predicts the cost of the optimal path. Even in this case, for each graph there exists some order of breaking ties in the priority queue such that A* examines the fewest possible nodes. Why A* is admissible and computationally optimal A* is both admissible and considers fewer nodes than any other admissible search algorithm with the same heuristic, because A* works from an optimistic estimate of the cost of a path through every node that it considers optimistic in that the true cost of a path through that node to the goal will be at least as great as the estimate. But, critically, as far as A* knows, that optimistic estimate might be achievable. When A* terminates its search, it has, by definition, found a path whose actual cost is lower than the estimated cost of any path through any open node. But since those estimates are optimistic, A* can safely ignore those nodes. In other words, A* will never overlook the possibility of a lower-cost path and so is admissible. Suppose now that some other search algorithm B terminates its search with a path whose actual cost is not less than the estimated cost of a path through some open node. Algorithm B cannot rule out the possibility, based on the heuristic information it has, that a path through that node might have a lower cost. So while B might consider fewer nodes than A*, it cannot be admissible. Accordingly, A* considers the fewest nodes of any admissible search algorithm that uses a no more accurate heuristic estimate. This is only true when A* uses a consistent heuristic. Otherwise, A* is not guaranteed to expand fewer nodes than another search algorithm with the same heuristic. Complexity Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 18 The time complexity of A* depends on the heuristic. In the worst case, the number of nodes expanded is exponential in the length of the solution (the shortest path), but it is polynomial when the search space is a tree, there is a single goal state, and the heuristic function h meets the following condition: | h(x) h * (x) | = O(logh * (x)) Where h * is the optimal heuristic, i.e. the exact cost to get from x to the goal. In other words, the error of h should not grow faster than the logarithm of the perfect heuristic h * that returns the true distance from x to the goal. More problematic than its time complexity is A*s memory usage. In the worst case, it must also remember an exponential number of nodes. Several variants of A* have been developed to cope with this, including iterative deepening A* (IDA*), memory-bounded A* (MA*) and simplified memory bounded A* (SMA*) and recursive best-first search (RBFS). Dominance property Let A 1 and A 2 be admissible algorithms with heuristic estimation functions h*1 and h*2. A 1 is said to be more informed than A 2 whenever h*1(n)>h*2(n) for all n. A 1 is said to dominate A 2 . Completeness Conditions Algorithm A is complete if it always trminates with a solution when one exists. MinMax Algorithm! There are plenty of applications for AI, but games are the most interesting to the public. Nowadays every major OS comes with some games. So it is no surprise that there are some algorithms that were devised with games in mind. The Min-Max algorithm is applied in two player games, such as tic-tac-toe, checkers, chess, go, and so on. All these games have at least one thing in common, they are logic games. This means that they can be described by a set of rules and premisses. With them, it is possible to know from a given point in the game, what are the next available moves. So they also share other characteristic, they Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 19 are full information games. Each player knows everything about the possible moves of the adversary. Before explaining the algorithm, a brief introduction to search trees is required. Search trees are a way to represent searches. The squares are known as nodes and they represent points of the decision in the search. The nodes are connected with branches. The search starts at the root node, the one at the top of the figure. At each decision point, nodes for the available search paths are generated, until no more decisions are possible. The nodes that represent the end of the search are known as leaf nodes. There are two players involved, MAX and MIN. A search tree is generated, depth-first, starting with the current game position upto the end game position. Then, the final game position is evaluated from MAXs point of view, as shown in Figure 1. Afterwards, the inner node values of the tree are filled bottom-up with the evaluated values. The nodes that belong to the MAX player receive the maximun value of its children. The nodes for the MIN player will select the minimun value of its children. MinMax (GamePosition game) { return MaxMove (game); } MaxMove (GamePosition game) { if (GameEnded(game)) { return EvalGameState(game); } else { best_move < - {}; Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 20 moves <- GenerateMoves(game); ForEach moves { move <- MinMove(ApplyMove(game)); if (Value(move) > Value(best_move)) { best_move < - move; } } return best_move; } } MinMove (GamePosition game) { best_move <- {}; moves <- GenerateMoves(game); ForEach moves { move <- MaxMove(ApplyMove(game)); if (Value(move) > Value(best_move)) { best_move < - move; } } return best_move; } So what is happening here? The values represent how good a game move is. So the MAX player will try to select the move with highest value in the end. But the MIN player also has something to say about it and he will try to select the moves that are better to him, thus minimizing MAXs outcome. Optimisation However only very simple games can have their entire search tree generated in a short time. For most games this isnt possible, the universe would probably vanish first. So there are a few optimizations to add to the algorithm. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 21 First a word of caution, optimization comes with a price. When optimizing we are trading the full information about the games events with probabilities and shortcuts. Instead of knowing the full path that leads to victory, the decisions are made with the path that might lead to victory. If the optimization isnt well choosen, or it is badly applied, then we could end with a dumb AI. And it would have been better to use random moves. One basic optimization is to limit the depth of the search tree. Why does this help? Generating the full tree could take ages. If a game has a branching factor of 3, which means that each node has tree children, the tree will have the folling number of nodes per depth: The sequence shows that at depth n the tree will have 3^n nodes. To know the total number of generated nodes, we need to sum the node count at each level. So the total number of nodes for a tree with depth n is sum (0, n, 3^n). For many games, like chess that have a very big branching factor, this means that the tree might not fit into memory. Even if it did, it would take to long to generate. If each node took 1s to be analyzed, that means that for the previous example, each search tree would take sum (0, n, 3^n) * 1s. For a search tree with depth 5, that would mean 1+3+9+27+81+243 = 364 * 1 = 364s = 6m! This is too long for a game. The player would give up playing the game, if he had to wait 6m for each move from the computer. The second optimization is to use a function that evaluates the current game position from the point of view of some player. It does this by giving a value to the current state of the game, like counting the number of pieces in the board, for example. Or the number of moves left to the end of the game, or anything else that we might use to give a value to the game position. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 22 Instead of evaluating the current game position, the function might calculate how the current game position might help ending the game. Or in another words, how probable is that given the current game position we might win the game. In this case the function is known as an estimation function. This function will have to take into account some heuristics. Heuristics are knowledge that we have about the game, and it can help generate better evaluation functions. For example, in checkers, pieces at corners and sideways positions cant be eaten. So we can create an evaluation function that gives higher values to pieces that lie on those board positions thus giving higher outcomes for game moves that place pieces in those positions. One of the reasons that the evaluation function must be able to evalute game positions for both players is that you dont know to which player the limit depth belongs. However having two functions can be avoided if the game is symetric. This means that the loss of a player equals the gains of the other. Such games are also known as ZERO-SUM games. For these games one evalution function is enough, one of the players just have to negate the return of the function. The revised algorithm is: MinMax (GamePosition game) { return MaxMove (game); } MaxMove (GamePosition game) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MAX); } else { best_move < - {}; moves <- GenerateMoves(game); ForEach moves { move <- MinMove(ApplyMove(game)); Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 23 if (Value(move) > Value(best_move)) { best_move < - move; } } return best_move; } } MinMove (GamePosition game) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MIN); } else { best_move <- {}; moves <- GenerateMoves(game); ForEach moves { move <- MaxMove(ApplyMove(game)); if (Value(move) > Value(best_move)) { best_move < - move; } } return best_move; } } Even so the algorithm has a few flaw, some of them can be fixed while other can only be solved by choosing another algorithm. One of flaws is that if the game is too complex the answer will always take too long even with a depth limit. One solution it limit the time for search. If the time runs out choose the best move found until the moment. A big flaw is the limited horizon problem. A game position that appears to be very good might turn out very bad. This happens because the algorithm wasnt able to see that a few game moves ahead the Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 24 adversary will be able to make a move that will bring him a great outcome. The algorithm missed that fatal move because it was blinded by the depth limit. Speeding the Algorithm There are a few things can still be done to reduce the search time. Take a look at figure 2. The value for node A is 3, and the first found value for the subtree starting at node B is 2. So since the B node is at a MIN level, we know that the selected value for the B node must be less or equal than 2. But we also know that the A node has the value 3, and both A and B nodes share the same parent at a MAX level. This means that the game path starting at the B node wouldnt be selected because 3 is better than 2 for the MAX node. So it isnt worth to pursue the search for children of the B node, and we can safely ignore all the remaining children. This all means that sometimes the search can be aborted because we find out that the search subtree wont lead us to any viable answer. This optimization is know as alpha-beta cuttoffs and the algorithm is as follows: 1. Have two values passed around the tree nodes: i)the alpha value which holds the best MAX value found; ii)the beta value which holds the best MIN value found. 2. At MAX level, before evaluating each child path, compare the returned value with of the previous path with the beta value. If the value is greater than it abort the search for the current node; 3. At MIN level, before evaluating each child path, compare the returned value with of the previous path with the alpha value. If the value is lesser than it abort the search for the current node. Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 25 Full pseudocode for MinMax with alpha-beta cuttoffs. MinMax (GamePosition game) { return MaxMove (game); } MaxMove (GamePosition game, Integer alpha, Integer beta) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MAX); } else { best_move < - {}; moves <- GenerateMoves(game); ForEach moves { move <- MinMove(ApplyMove(game), alpha, beta); if (Value(move) > Value(best_move)) { best_move < - move; alpha <- Value(move); } // Ignore remaining moves if (beta > alpha) return best_move; } return best_move; } } MinMove (GamePosition game) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MIN); } else { Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 26 best_move < - {}; moves <- GenerateMoves(game); ForEach moves { move <- MaxMove(ApplyMove(game), alpha, beta); if (Value(move) > Value(best_move)) { best_move < - move; beta <- Value(move); } // Ignore remaining moves if (beta < alpha) return best_move; } return best_move; } } How better does a MinMax with alpha-beta cuttoffs behave when compared with a normal MinMax? It depends on the order the search is searched. If the way the game positions are generated doesnt create situations where the algorithm can take advantage of alpha-beta cutoffs then the improvements wont be noticible. However, if the evaluation function and the generation of game positions leads to alpha-beta cuttoffs then the improvements might be great. Alpha-Beta Cutoff With all this talk about search speed many of you might be wondering what this is all about. Well, the search speed is very important in AI because if an algorithm takes too long to give a good answer the algorithm may not be suitable. For example, a good MinMax algorithm implementation with an evaluation function capable to give very good estimatives might be able to search 1000 positions a second. In tourament chess each player has around 150 seconds to make a move. So it would probably be able to analyze 150 000 positions during that period. But in chess each move has around 35 possible branchs! In the end the Artificial Intelli gence Techno India College of Technology New Town, Rajarhat Kolkata-700156 27 program would only be able to analyze around 3, to 4 moves ahead in the game. Even humans with very few pratice in chess can do better than this. But if we use MinMax with alpha-beta cutoffs, again a decent implementation with a good evaluation function, the result behaviour might be much better. In this case, the program might be able to double the number of analyzed positions and thus becoming a much toughter adversary. Example Example of a board with the values estimated for each position. The game uses MinMax with alpha-beta cutoffs for the computer moves. The evaluation function is an weighted average of the positions occupied by the checker pieces. The figure shows the values for each board position. The value of each board position is multiplied by the type of the piece that rests on that position, described in first table.