Vous êtes sur la page 1sur 27

Artificial Intelli gence

Techno India College of Technology


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.

Vous aimerez peut-être aussi