Professional Documents
Culture Documents
AI
AI
AI
Contents
Unit 1:
1.1 Introduction to AI
1.2 AI problems
1.3 AI techniques
1.4 Level of model
1.5 Criteria for success
1.6 Problem, problem spaces and searches
1.7 Production system characteristics
1.8 Issues in design of search programs
3
5
7
13
15
18
30
33
Unit 2 :
2.1 Game AI
2.2 Types of AI
2.3 Chasing and evading
2.4 Backtracking
2.5 Strategical AI
2.6 How to create strategical AI in games
36
37
40
44
47
49
Unit 3:
3.1 Game AI
3.2 Importance of good game AI
3.3 Difference between Game AI and Academic AI
3.4 Deterministic & Non-deterministic
55
55
61
62
Unit 4:
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
Unit 5:
5.1 Future for AI in games
64
78
85
90
102
106
107
110
114
ARTIFICIAL INTELLIGENCE
UNIT-I
1.1 Introduction to AI
The field of artificial intelligence, or AI, attempts to understand intelligent
entities. Thus, one reason to study it is to learn more about ourselves. But
unlike philosophy and psychology, which are also concerned with intelligence,
AI strives to build intelligent entities as well as understand them. Another
reason to study AI is that these constructed intelligent entities are interesting
and useful in their own right. AI has produced many significant and impressive
products even at this early stage in its development. Although no one can
predict the future in detail, it is clear that
computers with human-level intelligence (or better) would have a huge impact
on our everyday lives and on the future course of civilization.
AI addresses one of the ultimate puzzles. How is it possible for a slow, tiny
brain, whether biological or electronic, to perceive, understand, predict, and
manipulate a world far larger and more complicated than itself? How do we go
about making something with those properties? These are hard questions, but
unlike the search for faster-than-light travel or an antigravity device,the
researcher in AI has solid evidence that the quest is possible. All the
researcher has to do is look in the mirror to see an example of an intelligent
system.
AI is one of the newest disciplines. It was formally initiated in 1956, when
the name was coined, although at that point work had been under way for
about five years. Along with modern genetics, it is regularly cited as the "field
I would most like to be in" by scientists in other disciplines. A student in
physics might reasonably feel that all the good ideas have already been taken
by Galileo, Newton, Einstein, and the rest, and that it takes many years of
study before one can contribute new ideas. AI, on the other hand, still has
openings for a full-time Einstein.
For over 2000 years, philosophers have tried to understand how seeing,
learning, remembering, and reasoning could, or should,be done.' The advent
of usable computers in the early 1950s turned the learned but armchair
speculation concerning these mental faculties into a real experimental and
theoretical discipline.Many felt that the new "Electronic Super-Brains" had
unlimited potential for intelligence. "Faster Than Einstein" was a typical
headline. But as well as providing a vehicle for creating artificially intelligent
entities, the computer provides a tool for testing theories of intelligence, and
many theories failed to withstand the testa case of "out of the armchair,
into the fire." AI has turned out to be more difficult than many at first
imagined, and modem ideas are much richer, more subtle, and more
interesting as a result.
3
AI currently encompasses a huge variety of subfields, from generalpurpose areas such as perception and logical reasoning, to specific tasks such
as playing chess, proving mathematical theorems, writing poetry, and
diagnosing diseases. Often, scientists in other fields move gradually into
artificial intelligence, where they find the tools and vocabulary to systematize
and automate the intellectual tasks on which they have been working all their
lives. Similarly, workers in AI can choose to apply their methods to any area of
human intellectual endeavor. In this sense, it is truly a universal field.
1.1.1 Definitions of Artificial Intelligence
The definitions vary along two main dimensions. The ones on top are
concerned
with thought processes and reasoning, whereas the ones on the bottom
address behavior. Also,the definitions on the left measure success in terms of
human performance, whereas the ones on the right measure against an ideal
concept of intelligence, which we will call rationality.
"The exciting new effort to make computers think . . . machines with minds, in
the full and literal sense" (Haugeland, 1985)
"[The automation of] activities that we associate with human thinking,
activities such as decision-making, problem solving, learning..."(Bellman,
1978)
"The art of creating machines that perform functions that require intelligence
when performed by people" (Kurzweil, 1990)
"The study of how to make computers do things at which, at the moment,
people are better" (Rich and Knight, 1991 )
"The study of mental faculties through the use of computational models"
(Charniak and McDermott, 1985)
"The study of the computations that make it possible to perceive, reason, and
act" (Winston, 1992)
"A field of study that seeks to explain and emulate intelligent behavior in
terms of computational processes" (Schalkoff, 1990)
"The branch of computer science that is concerned with the automation of
intelligent behavior" (Luger and Stubblefield, 1993)
1.2 AI Problems
There are four essentially different types of problems
Singlestate problems,
Multiple-state problems,
Contingency problems, and
Exploration problems
Let the world contain just two locations. Each location may or may not
contain dirt, and the agent may be in one location or the other. There are 8
possible world states, as shown in figure 1.1. The agent has three possible
actions in this version of the vacuum world: Left, Right, and Suck.Assume, for
the moment, that sucking is 100% effective. The goal is to clean up all the
dirt. That is, the goal is equivalent to the state set {7,8}.
Fig 1.1 The eight possible states of the simplified vacuum World
First, suppose that the agent's sensors give it enough information to tell
exactly which state it is in (i.e., the world is accessible); and suppose that it
knows exactly what each of its actions does. Then it can calculate exactly
which state it will be in after any sequence of actions. For example, if its initial
state is 5, then it can calculate that the action sequence [Right,Suck] will get
to a goal state. This is the simplest case, which we call a single-state
problem.
Second, suppose that the agent knows all the effects of its actions, but
has limited access to the world state. For example, in the extreme case, it
may have no sensors at all. In that case, it knows only that its initial state is
one of the set {1,2,3,4,5,6,7,8}. One might suppose that the agent's
predicament is hopeless, but in fact it can do quite well. Because it knows
what its actions do, it can, for example, calculate that the action Right will
cause it to be in one of the states {2,4,6,8}. In fact, the agent can discover
that the action sequence [Right,Suck,Left,Suck] is guaranteed to reach a goal
state no matter what the start state. To summarize: when the world is not fully
accessible, the agent must reason about sets of states that it might get to,
rather than single states. We call this a multiple-state problem.
Although it might seem different, the case of ignorance about the effects
of actions can be treated similarly. Suppose, for example, that the
environment appears to be nondeterministic in that it obeys Murphy's Law:
the so-called Suck action sometimes deposits dirt on the carpet but only if
there is no dirt there already. For example, if the agent knows it is in state 4,
then it knows that if it sucks, it will reach me of the states {2,4}. For any
known initial state, however, there is an action sequence that is guaranteed to
reach a goal state.
Sometimes ignorance prevents the agent from finding a guaranteed
solution sequence. Suppose, for example, that the agent is in the Murphy's
Law world, and that it has a position sensor and a local dirt sensor, but no
sensor capable of detecting dirt in other squares. Suppose further that the
sensors tell it that it is in one of the states {1,3}. The agent might formulate
the action sequence [Suck,Right,Suck]. Sucking would change the state to one
of {5,7}, and moving right would then change the state to one of {6,8}. If it is
in fact state 6, then the action sequence will succeed, but if it is state 8, the
plan will fail. If the agent had chosen the simpler action sequence [Suck], it
would also succeed some of the time, but not always. It turns out there is no
fixed action sequence that guarantees a solution to this problem.
Obviously, the agent does have a way to solve the problem starting from
one of {1,3}: first suck, then move right, then suck only if there is dirt there.
Thus, solving this problem requires sensing during the execution phase.
Notice that the agent must now calculate a whole tree of actions, rather than
a single action sequence. In general, each branch of the tree deals with a
possible contingency that might arise. For this reason, we call this a
contingency problem.
Finally, consider the plight of an agent that has no information about the
effects of its actions. This is somewhat equivalent to being lost in a strange
country with no map at all, and is the hardest task faced by an intelligent
6
1.3 AI Techniques
According to the area of research, different techniques are applied:
Finite State Morphology
Parsing and Generation Techniques
Techniques for Speech Synthesis
Hidden Markov models
Kernel methods
Bayesian networks etc.
Let us discuss about two techniques briefly in this context.
1.3.1 Hidden Markov models
Some words have very simple pronunciation models.For example : Take the
word "tomato," you say [tow mey tow] and I say [tow maa tow]. The alternative
pronunciations are specified as a Markov model. In general, a Markov model is
a way of describing a process that goes through a series of states. The model
describes all the possible paths through the state space and assigns a
probability to each one. The probability of transitioning from the current state
to another one depends only on the current state, not on any prior part of the
path.
Fig 1.2 Two pronunciation models of the word "tomato." The top one accounts
for dialect differences. The bottom one does that and also accounts for a
coarticulation effect.
The top of Figure 1.2 is a Markov model with seven states (circles), each
corresponding to the production of a phone. The arrows denote allowable
transitions between states, and each transition has a probability associated
with it. There are only two possible paths through the model, one
corresponding to the phone sequence [t ow m ey t ow] and the other to [t ow
m aa t ow]. The probability of a path is the product of the probabilities on the
arcs that make up the path. In this case, most of the arc probabilities are 1
and we have
P([towmeytow] ("tomato") = P([towmaatow] ("tomato") = 0.5
Fig., 1.3 An HMM for the phone [m]. Each state has several possible
outputs, each with its own probability.
P([Cl,C\,C4, C4, C6, C6] | [m]) =
(0.3 x 0.7 x 0.9 x 0.1 x 0.4 x 0.6) x (0.5 x 0.5 x 0.7 x 0.7 x 0.5 x 0.5) +
(0.3 x 0.7 x 0.1 x 0.4 x 0.4 x 0.6) x (0.5 x 0.5 x 0.7 x 0.1 x 0.5 x 0.5)
= 0.0001477
We see that the loops in the phone model allow the model to represent both
fast and slow speech, a very important source of variation. The multiple
vector quantization values on each state represent other sources of variation.
Altogether, this makes for a fairly powerful model. The hard part is getting
good probability values for all the parameters.
there is a directed link to X. Let pa(X) denote the set of parents of X, then the
conditional independence property can be represented as follows:
at the central site. The same methodology could be used to update the
network based on new data. First, the new data is tested for how well it fits
with the local model. If there is an acceptable statistical fit, the observation is
used to update the local conditional probability estimates. Otherwise, it is also
transmitted to the central site to update the appropriate conditional
probabilities (of cross terms). Finally, a collective BN can be obtained by
taking the union of nodes and edges of the local BNs and the nonlocal BN,
along with the conditional probabilities from the appropriate BNs. Probabilistic
inference can now be performed based on this collective BN. Note that
transmitting the local BNs to the central site would involve a significantly
lower communication as compared to transmitting the local data.
It is quite evident that learning probabilistic relationships between
variables that belong to a single local site is straightforward and does not
pose any additional difficulty as compared to a centralized approach.2 The
important objective is to correctly identify the coupling between variables that
belong to two (or more) sites. These correspond to the edges in the graph that
connect variables between two sites and the conditional probability(ies) at the
associated node(s). In the following, we describe our approach to selecting
observations at the local sites that are most likely to be evidence of strong
coupling between variables at two different sites.
Selection of samples for transmission to global site
For simplicity, we will assume that the data is distributed between two
sites and will illustrate the approach using the BN in Figure 1. The extension of
this approach to more than two sites is straightforward. Let us denote by A
and B the variables in the left and right groups, respectively, in Figure 1. We
assume that the observations for A are available at site A, whereas the
observations for B are available at a different site B. Furthermore, we assume
that there is a common feature (key or index) that can be used to associate
a given observation in site A to a corresponding observation in site B.
Naturally, V = A B.
At each local site, a local Bayesian network can be learned using only
samples
in this site. This would give a BN structure involving only the local variables at
each site and the associated conditional probabilities. Let p A(.) and pB(.)
denote the estimated probability function involving the local variables. This is
the product of the conditional probabilities as indicated by (2). Since p A(x),
pB(x) denote the probability or likelihood of obtaining observation x at sites A
and B, we would call these probability functions the likelihood functions l A(.)
and lB(.), for the local model obtained at sites A and B, respectively. The
observations at each site are ranked based on how well it fits the local model,
using the local likelihood functions. The observations at site A with large
13
Therefore, an observation {A = a, T = t, E = e, X = x, D = d, S = s, L = l,
B = b} with low likelihood at both sites A and B; i.e. for which both P(A) and
P(B) are small, is an indication that both P(A | nb(A)) and P(B | nb(B)) are large
for that observation (since observations with small P(V) are less likely to
occur). Notice from (5) and (7) that the terms common to both P(A | nb(A))
and P(B | nb(B)) are precisely the conditional probabilities that involve
variables from both sites A and B. In other words, this is an observation that
indicates a coupling of variables between sites A and B and should hence be
transmitted to a central site to identify the specific coupling links and the
associated conditional probabilities.
In a sense, our approach to learning the cross terms in the BN involves a
selective sampling of the given dataset that is most relevant to the
identification of coupling between the sites. This is a type of importance
sampling, where we select the observations that have high conditional
probabilities corresponding to the terms involving variables from both sites.
Naturally, when the values of the different variables (features) from the
different sites, corresponding to these selected observations are pooled
together at the central site, we can learn the coupling links as well as
14
that when several psychologists were given the opportunity to converse the
program via a terminal; they diagnosed its behavior as paranoid.
2.
To enable computers to understand human reasoning. For
example, for a computer to be able to read a newspaper story and then
answer a question, such as why did the terrorists kill the hostages? its
program must be able to simulate the reasoning processes of people.
3.
To enable people to understand computer reasoning. In many
circumstances, people are reluctant to rely on computer unless they can
understand how the machine arrived at its result. If the computers reasoning
process is similar to that of people, then producing an acceptable explanation
is much easier.
4.
To exploit what knowledge we can glean from people. Since
people are the best-known performers of most of tasks with which we are
dealing, it makes a lot of sense to look to them for clues as to how to proceed.
This last motivation is probably the most pervasive of the four. It
motivated
Several early systems that attempted to produce intelligent behavior by
imitating people at the level of individual neurons. For example of this, see
the early theoratical work of McCulloch and Pits[1943], the work on
perceptrons originally developed by Frank Rosenblatt but best described in
Perceptron [minsky and Papert, 1969] and Design for a Brain[Ashby, 1952]. It
proves impossible, however, to produce even minimally intelligent behavior
with such simple devices. One reason was that there were severe theoretical
limitations, to the particular neural, net architecture that was being used.
More recently, several new neural net architectures have been proposed.
These structures are not subject to same theoretical limitations as were
perceptrons. These new architectures are loosely called connectionist, and
they have been used as a basis for several learning and problem-solving
programs. Also, we consider that while human brain are highly parallel
devices, most current computing devices are essentially serial engines. A
highly successful parallel technique may be computationally interactable on a
serial computer. But recently, partly because of the existence of the new
family of parallel cognitive model, as well as because of general promise of
parallel computing, there is low substantial design of massively parallel
machines to support AI programs.
Human cognitive theory have also influenced AI to look for higher-levels
(i.e, far above the neural level), theories that do not require massive
parallelism for their implementation. An early example of this approach can
be seen in GPS. This same approach can also be seen in much current work in
natural language understanding. The failure of straightforward syntactic
parsing mechanisms to make much of a dent in the problem of interpreting
English sentences has led many people who are interested in natural
16
meaning for the word "think." In the early days of the debate, some
philosophers thought that the question of thinking machines could be settled
by means of linguistic analysis of the kind hinted at earlier. If we define "think"
to mean something like "make decisions or deliberations by means of an
organic, natural brain," then we must conclude that computers cannot think.
Ultimately, the linguistic community will come to a decision that suits its need
to communicate clearly, but the decision will not tell us much about the
capabilities of machines.
Alan Turing, in his famous paper "Computing Machinery and Intelligence"
(Turing, 1950), suggested that instead of asking "Can machines think?" we
should instead ask if they can pass a behavioral test (which has come to be
called the Turing Test) for intelligence. He conjectured that by the year 2000, a
computer with a storage of 10 9 units could be programmed well enough to
have a conversation with an interrogator for 5 minutes and have a 30%
chance of fooling the interrogator into thinking it was human. Although we
would certainly not claim that anything like general, human-level intelligence
will be achieved by that time, his conjecture may not be that far off the truth.
Turing also examined a wide variety of possible objections to the possibility of
intelligent machines, including virtually all of those that have been raised in
the 44 years since his paper appeared.
Some of the objections can be overcome quite easily. For example, Lady
Ada Lovelace, commenting on Babbage's Analytical Engine, says, "It has no
pretensions to originate anything. It can do whatever we know how to order it
to perform." This objection, that computers can only do what they are told to
do and are therefore not capable of creativity, is commonly encountered even
today. It is refuted simply by noting that one of the things we can tell them to
do is to learn from their experience. For example, Samuel's checker-playing
program performed very poorly with its original programming. However, it
was able to learn, over the course of a few days of self-play, to play checkers
far better than Samuel himself. One can try to preserve Lady Lovelace's
objection by maintaining that the program's ability to learn originated
in Samuel, and so too did its checker-playing ability. But then one would also
be led to say that Samuel's creativity originated in his parents, and theirs
originated in their parents, and so on.
The "argument from disability" takes the form of a claim, usually
unsupported, to the effect that "a machine can never do X." As examples of X,
Turing lists the following:
Be kind, resourceful, beautiful, friendly, have initiative, have a sense of
humor, tell right from wrong, make mistakes, fall in love, enjoy strawberries
and cream, make someone fall in love with it, learn from experience, use
18
words properly, be the subject of its own thought, have as much diversity of
behavior as man, do something really new.
Turing suggests that scepticism of this nature arises from experience of
machines as devices for carrying out repetitive tasks requiring little sensory
and no reasoning ability. He points to the fact that in the late 1940s, the
general population found it difficult to believe that machines could find
numerical solutions of equations or predict ballistic trajectories. Even today,
however, many technically literate people do not believe that machines can
learn.
The supposed inability to make mistakes presents an interesting problem
when considering the Turing Test. Certainly, instantaneous and correct
answers to long division problems would be a giveaway, and some attempt to
simulate human fallibility would be required. But this is not a mistake in the
normal sense, because the program is doing exactly what its designer
intended. Something more akin to human mistakes will arise when intractable
problems are involved. For example, given only a small amount of time to find
a chess move, the computer must essentially guess that its move is correct.
Similarly, a program that is trying to induce hypotheses from a small amount
of data is bound to make mistakes when using such hypotheses for prediction.
When unavoidably irrational behavior on the part of the computer matches
corresponding failings of humans, this provides evidence that similar
mechanisms are in operation. Rational behavior, on the other hand, provides
much weaker constraints on mechanisms.
What Turing calls the mathematical objection concerns the proven
inability of computers to answer certain questions. In-practice objections
center on the so-called "argument from informality," which claims that
intelligent behavior cannot be captured by formal rules.The final, and most
interesting, objection claims that even if computers behave as intelligently as
humans, they still will not be intelligent.
1.6 Problem spaces and searches
A problem consists of four parts:
the initial state,
a set of operators,
a goal test function,
and a path cost function.
The environment of the problem is represented by a state space.
A path through the state space from the initial state to a goal state is a
solution.
We can distinguish problems so-called, toy problems, which are intended
19
to illustrate or exercise various problem-solving methods, and so-called realworld problems, which tend to be more difficult and whose solutions people
actually care about.In this section, we will give examples of both. By nature,
toy problems can be given a concise, exact description. This means that they
can be easily used by different researchers to compare the performance of
algorithms. Real-world problems, on the other hand, tend not to have a single
agreed-upon description, but we will attempt to give the general flavor of
their formulations.
1.6.1 Toy problems
i) The 8-puzzIe
The 8-puzzle, an instance of which is shown in Figure 3.4, consists of a
3x3 board with eight numbered tiles and a blank space. A tile adjacent to the
blank space can slide into the space.The object is to reach the configuration
shown on the right of the figure. One important trick is to notice that rather
than use operators such as "move the 3 tile into the blank space," it is more
sensible to have operators such as "the blank space changes places with the
tile to its left." This is because there are fewer of the latter kind of operator.
This leads us to the following formulation:
States: a state description specifies the location of each of the eight tiles in
one of the nine squares. For efficiency, it is useful to include the location of
the blank.
Operators: blank moves left, right, up, or down.
Goal test: state matches the goal configuration as shown in figure.
Path cost: each step costs 1, so the path cost is just the length of the path.
the next. The 8-puzzle and its larger cousin, the 15-puzzle, are the standard
test problems for new search algorithms in Al.
ii) The 8-queens problem
The goal of the 8-queens problem is to place eight queens on a
chessboard such that no queen attacks any other. (A queen attacks any piece
in the same row, column or diagonal.) Figure shows an attempted solution
that fails: the queen in the rightmost column is attacked by the queen at top
left.
22
The majority of work in the area of search has gone into finding the right
search strategy for a problem. In our study of the field we will evaluate
strategies in terms of four criteria:
There are six search strategies that come under the heading of
uninformed search. The term means that they have no information about the
number of steps or the path cost from the current state to the goalall they
can do is distinguish a goal state from a nongoal state. Uninformed search is
also sometimes called blind search.
Consider again the route-finding problem. From the initial state in Arad,
there are three actions leading to three new states: Sibiu, Timisoara, and
Zerind. An uninformed search has no preference among these, but a more
clever agent might notice that the goal, Bucharest, is southeast of Arad, and
that only Sibiu is in that direction, so it is likely to be the best choice.
Strategies that use such considerations are called informed search strategies
or heuristic search strategies. Not surprisingly, uninformed search is less
effective than informed search. Uninformed search is still important, however,
because there are many problems for which there is no additional information
to consider.
The six uninformed search strategies are distinguished by the order in
which nodes are expanded. It turns out that this difference can matter a great
deal, as we shall shortly see.
Breadth-first search
One simple search strategy is a breadth-first search. In this strategy,
the root node is expanded first, then all the nodes generated by the root node
are expanded next, and then their successors, and so on. In general, all the
nodes at depth d in the search tree are expanded before the nodes at depth d
+ 1. Breadth-first search can be implemented by calling the GENERAL-SEARCH
algorithm with a queuing function that puts the newly generated states at the
end of the queue, after all the previously generated states:
function BREADTH-FlRST-SEARCH(problem) returns a solution or failure
return GENERAL-SEARCH( problem,ENQUEUE-AT-END)
24
25
can be goal-checked and expanded per second, and that a node requires 100
bytes of storage. Many puzzle-like problems fit roughly within these
assumptions (give or take a factor of 100) when run on a modern personal
computer or workstation.
Fig 1.9 Time and memory requirements for breadth-first search. The figure
shown assumes the branching factor b=10; 1000 nodes/ second; 100 bytes/
node
There are two lessons to be learned from Figure 1.9. First, the memory
requirements are a bigger problem for breadth-first search than the execution
time. Most people have the patience to wait 18 minutes for a depth 6 search
to complete, assuming they care about the answer, but not so many have the
111 megabytes of memory that are required. And although 31 hours would
not be too long to wait for the solution to an important problem of depth 8,
very few people indeed have access to the 11 gigabytes of memory it would
take. Fortunately, there are other search strategies that require less memory.
The second lesson is that the time requirements are still a major factor. If your
problem has a solution at depth 12, then (given our assumptions) it will take
35 years for an uninformed search to find it. Of course, if trends continue then
in 10 years, you will be able to buy a computer that is 100 times faster for the
same price as your current one. Even with that computer, however, it will still
take 128 days to find a solution at depth 12and 35 years for a solution at
depth 14. Moreover, there are no other uninformed search strategies that fare
any better. In general, exponential complexity search problems cannot be
solved for any but the smallest instances.
Uniform cost search
Breadth-first search finds the shallowest goal state, but this may not always
be the least-cost solution for a general path cost function. Uniform cost
search modifies the breadth-first strategy by always expanding the lowestcost node on the fringe (as measured by the path cost g(n)), rather than the
26
27
Fig 1.10 A route-finding problem, (a) The state space, showing the cost for
each operator, (b) Progression of the search. Each node is labelled with g(n).
At the next step, the goal node with g = 10 will be selected.
Depth-first search
Depth-first search always expands one of the nodes at the deepest level
of the tree. Only when the search hits a dead end (a nongoal node with no
expansion) does the search go back and expand nodes at shallower levels.
This strategy can be implemented by GENERAL-SEARCH with a queuing
function that always puts the newly generated states at the front of the
queue. Because the expanded node was the deepest, its successors will be
even deeper and are therefore now the deepest. The progress of the search is
illustrated in Figure 1.11.
Depth-first search has very modest memory requirements. As the figure
shows, it needs to store only a single path from the root to a leaf node, along
with the remaining unexpanded sibling nodes for each node on the path. For a
state space with branching factor b and maximum depth m, depth-first search
requires storage of only bm nodes, in contrast to the b d that would be required
by breadth-first search in the case where the shallowest goal is at depth d.
Using the same assumptions as Figure 1.9, depth-first search would require 12
28
Figure 1.11 Depth-first search trees for a binary search tree. Nodes at depth 3
are assumed to have no successors.
space. Breadth-first search would still have to look at all the paths of length d
- 1 before considering any of length d. Depth-first search is still O(b m) in the
worst case. The drawback of depth-first search is that it can get stuck going
down the wrong path. Many problems have very deep or even infinite search
trees, so depth-first search will never be able to recover from an unlucky
choice at one of the nodes near the top of the tree. The search will always
continue downward without backing up, even when a shallow solution exists.
Thus, on these problems depth-first search will either get stuck in an infinite
29
loop and never return a solution, or it may eventually find a solution path that
is longer than the optimal solution. That means depth-first search is neither
complete nor optimal. Because of this, depth-first search should be avoided
for search trees with large or infinite maximum depths.
It is trivial to implement depth-first search with GENERAL-SEARCH:
function DEPTH-FlRST-SEARCH(problem) returns a solution, or failure
GENERAL-SEARCH(problem,ENQUEUE-AT-FRONT)
then depth 1, then depth 2, and so on. The algorithm is shown in Figure 1.12.
In effect, iterative deepening combines the benefits of depth-first and
breadth-first search. It is optimal and complete, like breadth-first search, but
has only the modest memory requirements of depth-first search. The order of
expansion of states is similar to breadth-first, except that some states are
expanded multiple times. Figure 1.13 shows the first four iterations of
ITERATIVE-DEEPENING-SEARCH on a binary search tree. Iterative deepening
search may seem wasteful, because so many states are expanded multiple
times. For most problems, however, the overhead of this multiple expansion is
actually rather small.
function iTERATiVE-DEEPENiNG-SEARCH(praWem) returns a solution sequence
inputs: problem, a problem
for depth < 0 to do
if DEPTH-LlMITED-SEARCH(proWem, depth) succeeds then return its result
end
return failure
Figure 1.12 The iterative deepening search algorithm
31
Intuitively, the reason is that in an exponential search tree, almost all of the
nodes are in the bottom level, so it does not matter much that the upper
levels are expanded multiple times. Recall that the number of expansions in a
depth-limited search to depth d with branching factor b is
1+b+b2+....+bd-2+bd-1+bd
To make this concrete, for b = 10 and d = 5. the number is
1 + 10+100+1,000+10,000+ 100,000= 111,111
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. So the
total number of expansions in an iterative deepening search is
(d + 1)1 + (d)b + (d- \)b2 + + 3bd-2 + 2bd-1 + bd
Again, for b = 10 and d = 5 the number is
6 + 50 + 400 + 3,000 + 20,000+100,000= 123,456
All together, an iterative deepening search from depth 1 all the way down
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 breadth-first search. This means that the time complexity
of iterative deepening is still O(bd), 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.
Bidirectional search
The idea behind bidirectional search is to simultaneously search both forward
from the initial state and backward from the goal, and stop when the two
searches meet in the middle (Figure 1.14). For problems where the branching
factor is b in both directions, bidirectional search can make a big difference. If
we assume as usual that there is a solution of depth d, then the solution will
be found in O(2bd/2) = O(bd/2) steps, because the forward and backward
searches each have to go only half way. To make this concrete: for b = 10 and
d = 6, breadth-first search generates 1,111,111 nodes, whereas bidirectional
search succeeds when each direction is at depth 3, at which point 2,222
nodes have been generated. This sounds great in theory. Several issues need
to be addressed before the algorithm can be implemented.
The main question is, what does it mean to search backwards from the
32
33
2.
The answer to the first question is yes. Consider the following definitions
of classes of production system. A monotonic production system is a
production system is one in which this is not true. A partially commutative
production system is a production system with the property that if the
application of a particular sequence of rules transform state x into state y
then any permutation of those rules that is allowable also transforms state x
into state y. A commutative production system is a production system that is
both monotonic and partially commutative.
The significance of these categories of production system lies in the
relationship between categories and appropriate implementation strategies.
But before discussing relationship, it might be helpful to make the meanings
of the definitions cleverer by showing how they relate to specific problems.
Thus we arrive at the second question above, which asked whether there
is interesting relationship between classes of production systems and classes
of problems. For any solvable problem, there exist an infinite number of
production systems that describe way to find solutions. Some will be more
34
natural or efficient than others. Any problem that can be solved by any
production system can be solved by a commutative one, but the commutative
one may be so unwieldy as to be practically useless. It may use individual
states to represent entire sequence of applications of rules of a simpler, non
commutative system. So in a formal sense there is no relationship between
kinds of problem and kinds of production systems since all problems can be
solved by all kind of production systems. But in a practical sense, there
definitely is such a relationship between kinds of problem and kinds of
systems that lend themselves naturally to describing those problems. To see
this let us look at a few examples. The table below shows the four categories
of production systems produced by dichotomies, monotonic versus nonmonotonic and partially commutative versus nonpartially commutative, along
with some problems that can naturally be solved by each type of system.
Partially commutative
Not
partially
commutative
Monotonic
Theorem proving
Chemical synthesis
Non-monotonic
Robot navigation
Bridge
35
building the tree explicitly and then searching it, most search programs
represent the tree implicitly in the rules and generate explicitly only those
parts that they decide to explore. Throughout our discussion of search
methods, it is important to keep in mind this distinction between implicit
search trees and explicit partial trees that are actually constructed by the
search program.
by first filling 4-gallon jug and then the 3-gallon one or by filling them in
opposite order. Since the order does not matter, continuing to process both
these nodes would be redundant. This example also illustrates another
problem that often arises when the search process operate as a tree walk. On
the third level, the node (0,0) appears.(In fact it appears twice). But this is the
same as the top node of the tree, which has already been expanded. Those
two path have not gotten Us anywhere. So we would like to eliminate them
and continue only along the other branches.
The waste of effort that arises when the same node is generated more
than once can be avoided at the price of additional bookkeeping. Instead of
traversing a search tree, we traverse a directed graph. This graph differs from
a tree in that several paths may come together at a node. The graph
corresponding to the above tree is:
Any tree search procedure that keeps track of all the nodes that have
been generated so far can be converted to a graph search procedure by
action performed each time a node is generated. Notice that of the two
systematic search procedures we have discussed so far, this requirement that
nodes be kept track of it met by breadth-first search but not depth-first
search. But, of course, depth-first search could be modified, at the expense of
additional storage, to retain in memory nodes that have been expanded and
then backed-up over. Since all nodes are saved in the search graph, we must
use the following algorithm instead of simply adding a new node to the graph.
39
UNIT II
1- Roaming AI
2- Behavioral AI
3- Strategic AI
1- Roaming AI: It models the movement of game objects. i.e. the decisions
made by game objects that determine how they roam around in a virtual
game world.
40
2- Behavioral AI: This type of gaming AI uses a mixture of all three roaming AI
algorithms to give game objects specific behaviors. eg. if you want the alien or enemy
to chase sometimes, evade other times, follow a pattern some other times, and may be
even act randomly every once in a while. behavioral AI can also be used to alter the
difficulty of the game. eg. You would like to favor a chasing algorithm more than
random or patterned movement to make the aliens or enemies more aggressive in the
higher levels of a game.
3- Strategic AI: Any AI designed to play a game with a fixed set of well defined rules
is known as strategic AI. eg. a computer controlled chess player would use strategic
AI to determine each move based on trying to improve the chances of winning the
game.
Strategic AI tend to vary more based on the nature of the game because it is so tightly
linked to the rules of the game.
Example:
The prototypes of two games have been created integrating roaming,
behavioral and strategic AI: Family Guy Strategy game based on themes from
the television cartoon Family Guy. This game is trying to provide another
way for Family Guy fans to pass the time until a new episode or another movie
is created. This game is a combination of few smaller games merged as
levels. These individual levels depict particular Family Guy episodes or the
movie and elaborated to create a way for a Family Guy fan to take part in a
particular event. The objective of the game is to navigate the family
(FatherPeter, Mother-Lois, Daughter-Meg, Son-Chris, Baby-Stewie, Dog-Brian)
41
through their hometown of Quahog to reach the Quahog Airport for a family
vacation to Milwaukee. Each different level displays different characters and
different types of gameplay. Level 1 (Lois Hunter) This level is based off of the
game called Deer Hunter. he only character in this level is Lois. When the
level is started Lois automatically appears on the screen and starts moving in
a random direction. The goal of the level is to click on Lois as many times as
possible to get a high score. Each time the player clicks on Lois the score
increases by ten points. Also, each time the player clicks on her she jumps to
a random position on the screen and starts moving in a random direction. Her
speed increases slightly each time you click on her as well which increases
the difficulty of playing. After about 1.5 seconds Lois direction changes
automatically to prevent predictability. The level ends after a counter runs out
of time and if the players score is high enough then the player goes to the
next level. If not, then this level restarts and the player tries again. Level 2
(Peter vs. The Giant Chicken) Peter vs. The Giant Chicken In two episodes
Peter battles The Giant Chicken. The theme of this level is a spoof off of
Mortal Kombat, an old school fighting game which involves handto-hand
combat. At the beginning of the level Peter and The Giant Chicken start off on
different sides of the screen. The player controls Peter using the arrow keys.
The Giant Chicken is set to randomly move about the level and to react in an
attack or block when the player (Peter) is too close. Other features in this level
include a health counter, life counter, and a timer. If either Peter or The Giant
Chicken has 0 health then that character will lose a life and then the two
players will restart at their original positions, thus starting a new round. There
is a maximum of three rounds and 30 seconds allowed for each. To pass this
level, the player must beat The Giant Chicken two times or else if The Giant
Chicken wins twice then the level restarts all of the counters and the player
must go through it all again. Ong Bak: Quest of the Thai Warrior Action game
based on the movie Ong Bak. Sacred incarnation of Buddha, you must
retrieve this statue head in order to regain the protection for your village, time
is running out. While searching the world for the sacred head of Ong Bak you
will travel to many exciting and different places. Ting from Pradu is an
incredibly gifted fighter who has honed his skills and abilities over a lifetime.
He has been named a protector of the village and has sworn to retrieve the
sacred head of Ong Bak. Although he upholds his teaching to fight only when
absolutely necessary, he will need all his skill in order to save the village from
disaster. It was decided that the game should be implemented as a sidescrolling fighting game with AI components. The tracking system for all
characters of the game is based off chasing and evading tactics. Several
markers were set in place to log each movement and corresponding (x,y)
coordinates. These markers were set on the main character and enemies. By
using a chance variable with the probability of 75%, the enemy moves
towards the player character analyzing the distance and (x,y) coordinates of
the characters. These coordinates are taken from the collision boxes created
42
for each sprite. With the probability of 25%, the enemy moves away from the
player in a random direction to simulate the evasion.
Features
The following components have been integrated into the engine of both
games:
completed storylines;
developed levels, character sprites, worlds, and AI;
multiplayer environment;
ability to chose a path in the game; ability to change level difficulty;
penalty for cheating, etc. Our games run on the Windows platform and
require DirectX 8 or higher compatible graphics card with at least 16MB of
video memory (preferably 32 MB or more). These games also require a
monitor that is capable of 1024x768 viewing resolution. The characters
are rendered in a 2D format. Figures 2.1 and 2.2 give some screenshots of
these games.
43
Figure 2.1: Game screenshots from Ong Bak: single enemy, and group attack
44
Figure 2.2: Game screenshots from Family Guy: Lois Hunter, and Peter vs. The
Giant Chicken
2.3 Chasing and evading
The chasing and evading problem (evading is virtually the opposite of
chasing) consists of 3 parts: the decision to initiate a chase or evade, the
effecting the chase or evade, and obstacle avoidance.
The environment can be either tiled or continuous
tile-based: the game domain is divided into discrete tiles, and the
player's position is represented by integers, the position is fixed to a discrete
tile, movement goes tile by tile, the number of directions in which the player
can make is limited, and characters appear to move faster when moving along
a diagonal path
45
46
// path initialization
for ( currStep = 0; currStep < kMaxPathLength; currStep++ )
{
pathRows[currStep] = pathCols[currStep] = -1;
}
currStep = 0;
pathRows[currStep] = currRow;
pathCols[currStep] = currCol;
currStep++;
// bresenham algorithm
if ( daltaCol > deltaRow )
{
fraction = deltaRow * 2 - daltaCol;
while ( currCol != endCol )
{
if ( fraction >= 0 )
{
currRow += stepRow; fraction -= deltaCol;
}
currCol += stepCol;
fraction += deltaRow;
pathRow[currentStep] = currRow; pathCol[currentStep++] = currCol;
}
}
else
{
fraction = deltaCol * 2 - daltaRow; while ( currRow != endRow )
{
if ( fraction >= 0 )
{
currCol += + stepCol;
fraction -= deltaRow;
}
currRow += stepRow;
fraction += deltaCol;
pathRow[currentStep] = currRow;
pathCol[currentStep++] = currCol;
}
}
// line-of-sight chasing
left = right = false;
v = vRotate2D( -predator.fOrientation, prey.vPosition - predator.vPosition );
v.normalize( );
if ( v.x < -TOL )
{
left = true;
}
else if ( v.x > TOL )
{
right = true;
}
predator.setThrusters(left, right);
The unit vector v points from the predator directly toward the prey.
If the x-position of the prey, in term s of the predator's local coordinate
system , is negative, the prey is somewhat to the starboard side of the
predator (turn right); if the prey's x-coordinate is positive, it is somewhat
on the port side of the predator (turn left).
The predator always head directly toward the prey and most likely end up
right behind it, unless it is moving so fast that it overshoots the prey, in
which case it will loop around and head toward the prey again.
To prevent overshooting, use speed control logic to allow the predator to
slow down as it gets closer to the prey.
Heading directly toward the prey is not always the shortest path in terms
of range to target, or, perhaps, time to target.
48
2.4 Backtracking
Backtracking is a general algorithm for finding all (or some) solutions to
some computational problems, notably constraint satisfaction problems, that
incrementally builds candidates to the solutions, and abandons each partial
candidate c ("backtracks") as soon as it determines that c cannot possibly be
completed to a valid solution.
The classic textbook example of the use of backtracking is the eight
queens puzzle, that asks for all arrangements of eight chess queens on a
standard chessboard so that no queen attacks any other. In the common
backtracking approach, the partial candidates are arrangements of k queens
in the first k rows of the board, all in different rows and columns. Any partial
solution that contains two mutually attacking queens can be abandoned.
Backtracking can be applied only for problems which admit the concept of
a "partial candidate solution" and a relatively quick test of whether it can
possibly be completed to a valid solution. It is useless, for example, for
locating a given value in an unordered table. When it is applicable, however,
backtracking is often much faster than brute force enumeration of all
complete candidates, since it can eliminate a large number of candidates with
a single test.
Backtracking is an important tool for solving constraint satisfaction
problems, such as crosswords, verbal arithmetic,Sudoku, and many other
puzzles. It is often the most convenient technique for parsing, for
the knapsack problem and other combinatorial optimization problems. It is
also the basis of the so-called logic programming languages such
as Icon, Planner and Prolog.
Backtracking depends on user-given "black box procedures" that define
the problem to be solved, the nature of the partial candidates, and how they
are extended into complete candidates. It is therefore a metaheuristic rather
than a specific algorithm although, unlike many other meta-heuristics, it is
guaranteed to find all solutions to a finite problem in a bounded amount of
time.
2.4.1 Constraint Satisfaction problem
A constraint satisfaction problem (or CSP) is a special kind of problem
that satisfies some additional structural properties beyond the basic
requirements for problems in general. In a CSP, the states are defined by the
values of a set of variables and the goal test specifies a set of constraints
that the values must obey. For example, the 8-queens problem can be viewed
49
as a CSP in which the variables are the locations of each of the eight queens;
the possible values are squares on the board; and the constraints state that
no two queens can be in the same row, column or diagonal. A solution to a
CSP specifies values for all the variables such that the constraints are
satisfied.Many kinds of design and scheduling problems can be expressed as
CSPs, so they form a very important subclass. CSPs can be solved by generalpurpose search algorithms, but because of their special structure, algorithms
designed specifically for CSPs generally perform much better.
Constraints come in several varieties. Unary constraints concern the value
of a single variable. For example, the variables corresponding to the leftmost
digit on any row of acryptarithmetic puzzle are constrained not to have the
value 0. Binary constraints relate pairs of variables. The constraints in the 8queens problem are all binary constraints. Higher-order constraints involve
three or more variablesfor example, the columns in the cryptarithmetic
problem must obey an addition constraint and can involve several variables.
Finally, constraints can be absolute constraints, violation of which rules out a
potential solution, or preference constraints that say
which solutions are preferred.
Each variable Vi in a CSP has a domain Di, which is the set of possible
values that the variable can take on. The domain can be discrete or
continuous. In designing a car, for instance, the variables might include
component weights (continuous) and component manufacturers (discrete). A
unary constraint specifies the allowable subset of the domain, and a binary
constraint between two variables specifies the allowable subset of the crossproduct of the two domains. In discrete CSPs where the domains are finite,
constraints can be represented simply by enumerating the allowable
combinations of values. For example, in the 8-queens problem, let V1 be the
row that the first queen occupies in the first column, and let V2 be the row
occupied by the second queen in the second column. The domains of V1 and
V2 are {1,2,3,4,5,6,7,8}. The no-attack constraint linking V1 and V2 can be
represented by a set of pairs of allowable values for V1 and V2: {{1,3}, (1,4),
{1,5},... ,(2,4), (2,5),...} and so on. Altogether, the no-attack constraint
between V\ and Vi rules out 22 of the 64 possible combinations. Using this
idea of enumeration, any discrete CSP can be reduced to a binary CSP.
Constraints involving continuous variables cannot be enumerated in this
way, and solving continuous CSPs involves sophisticated algebra. In this
chapter, we will handle only discrete, absolute, binary (or unary) constraints.
Such constraints are still sufficiently expressive to handle a wide variety of
problems and to introduce most of the interesting solution methods.
Let us first consider how we might apply a general-purpose search
50
algorithm to a CSP. The initial state will be the state in which all the variables
are unassigned. Operators will assign a value to a variable from the set of
possible values. The goal test will check if all variables are assigned and all
constraints satisfied. Notice that the maximum depth of the search tree is
fixed at n, the number of variables, and that all solutions are at depth n. We
are therefore safe in using depth-first search, as there is no danger of going
too deep and no arbitrary depth limit is needed.
In
the
most
naive
implementation, any unassigned
i
i
variable in a given state can be
assigned a value by an operator, in
which case the branching factor would be as high as |Di | or 64 in the 8-queens
problem. A better approach is to take advantage of the fact that the order of
variable assignments makes no difference to the final solution. Almost all CSP
algorithms therefore generate successors by choosing values for only a single
variable at each node. For example, in the 8-queens problem, one can assign
a square for the first queen at level 0, for the second queen at level 1, and so
on. This results in a search space of size |Di|, or 88 in the 8-queens problem. A
straight forward depth-first search will examine all of these possibilities.
Because CSPs include as special cases some well-known NP-complete
problems such as 3SAT,
we cannot expect to do better than exponential complexity in the worst case.
In most real problems, however, we can take advantage of the problem
structure to eliminate a large fraction of the search space. The principal
source of structure in the problem space is that, in CSPs, the goal test is
decomposed into a set of constraints on variables rather than being a "black
box.
Depth-first search on a CSP wastes time searching when constraints have
already been violated. Because of the way that the operators have been
defined, an operator can never redeem a constraint that has already been
violated. For example, suppose that we put the first two queens in the top
row. Depth-first search will examine all 8 6 possible positions for the remaining
six queens before discovering that no solution exists in that subtree. Our first
improvement is therefore to insert a test before the successor generation step
to check whether any constraint has been violated by the variable
assignments made up to this point. The resulting algorithm, called
backtracking search, then backtracks to try something else.
Backtracking also has some obvious failings. Suppose that the squares
chosen for the first six queens make it impossible to place the eighth queen,
because they attack all eight squares in the last column. Backtracking will try
all possible placings for the seventh queen, even though the problem is
already rendered unsolvable, given the first six choices. Forward checking
avoids this problem by looking ahead to detect unsolvability. Each time a
51
variable is instantiated, forward checking deletes from the domains of the asyet-uninstantiated variables all of those values that conflict with the variables
assigned so far. If any of the domains becomes empty, then the search
backtracks immediately. Forward checking often runs far faster than
backtracking and
is very simple to implement.
Forward checking is a special case of arc consistency checking. A state
is arc-consistent if every variable has a value in its domain that is consistent
with each of the constraints on that variable. Arc consistency can be achieved
by successive deletion of values that are inconsistent with some constraint. As
values are deleted, other values may become inconsistent because they relied
on the deleted values. Arc consistency therefore exhibits a form of
constraint propagation, as choices are gradually narrowed down. In some
cases, achieving arc consistency is enough to solve the problem completely
because the domains of all variables are reduced to singletons. Arc
consistency is often used as a preprocessing step, but can also be used during
the search.
2.5 Strategy AI
The strategic AI itself is most common in real-time strategy (RTS) games but has
been making its way more and more into tactical FPS games. The player-controlled
commander can be its own system or set up as an empty entity-one that does not have
a place or graphic in the world but is updated and thinks.
The commanders are going to be guided by hierarchical rules systems and FSMs,
which govern elements such as resource gathering, researching up the tech tree,
building the army, and so on. For the most part, this basic upkeep of the game
elements does not require much actual thought. What does require intelligence is the
interactions with the other players.
Governing these interactions (or warfare) is where the real meat and potatoes
lie with strategic AI. The commander needs to explore the game map to find the
player, identify key points of interest such as choke points, build defenses, and
analyze other player's defenses. How one would do this is not obvious but can be
made easier with decision maps.
Decision Maps
Decision maps are two-dimensional arrays approximating the game map. Each cell in
the array corresponds to a region in the game and is filled with important information
about the region. These maps are used to help your strategic AI make meaningful
decisions about the game as a whole.
52
Resource Maps
Resource maps contain information about where the resources are laid out in a
strategy game. Knowing where on the maps resources are concentrated can influence
many decisions that a commander will make. Where to deploy expansions or satellite
bases (resources near the commanders base), where the enemy is likely to deploy its
expansions (resources near their base) and places likely to be contested (resources in
the middle).
Getting a count of potential available resources also influences which units are
supported and how to deploy the army. If resources are scarce, each unit must be used
more carefully, because replacements are less likely. If resources are plentiful, it opens
up the strategies of massing cheap units or building powerful units.
Objective Maps
These maps are filled with information about the goals of the commander-for
example, locations of enemy bases, the positions of map objectives (blow something
up, protect something, hack something, etc.), and key units of the commanders army
(main base, hero units, etc). Tracking this information guides the use of the
commander's army. Points that need to be protected should be surrounded with
defensive structures, and a contingent of units should always be near these points.
Attack objectives will be sought out and defenses tested. Analysis of defenses around
targets must be undertaken to figure out the optimal way to overcome them. This
leads to the backbone of military games-conflict maps.
Conflict Maps
Conflict maps (see Figure 2.3) are used and updated far more often than the previous
maps. Conflict maps keep track of where battle occurs throughout the level.
Whenever one of the commanders units engages in a fight with an enemy, the unit
will update the conflict map with key information:
When the enemy attacks, the AI will be able to determine whether the
defenses deployed are effective, whether the defenses are engaged or
53
ignored, and whether conflict arises close to defensive objectives. This can
lead to the AI changing the layout and composition of its defenses.
2.3 An example of how a conflict map might look laid over a view of the
terrain. The darker the red, the more conflicts encountered.
54
Ensuring that the decision maps are maintained quickly is not too hard. You can
do so by putting the decision map system into its own thread. Indeed, each AI
controlled player should have its own thread to handle its own set of decisions maps.
The real performance gain happens if all of the entities are already broken up into
multiple threads. The decision map threads only need to handle the requests from the
parallelized entity update messages.
2.6 How to Create Strategically AI in Games
The biggest challenge in computer strategy games is the creation of a fun
computer opponent. The hardest element of "fun" is "good". For the Artificial
Intelligence to be good, it must do much of what a human player would do: situational
& map analysis, resource allocation, and strategy execution. Yhe framework and
some of the strategies which are developed at Activision in the development of games
such as Dark Reign: The Future Of War, Battlezone, Civilization: Call To Power, and
others are given here.
A relatively large number of high profile military strategy games was developed
by Ian Lane Davis, which includes: Dark Reign includes The Future Of War,
Battlezone, and Civilization: Call To Power.Perhaps the hardest part of developing
strategy games is the design and implementation of the Artificial Intelligence. This
model first breaks down the AI tasks into Tactical AI and Strategic AI, and then
further breaks down the Strategic AI into three parts: Analysis, Resource Allocation,
and High Level AI (personality).
Problem Definition
Before describing the details of the Dark Reign Model, let us define the
context of the problem and solutions. To generate a successful computer
opponent in a strategy game (or any computer game, for that matter), it
important to focus on what the developers true goal is:
Davis First Law of Computer Game AI: The goal of any AI is to lose the game.
This may seem counter-intuitive! Most programmers and researchers want to
develop algorithms and approaches that are optimal and perfect. There are
two problems, however. The first problem is that optimal is always hard and
often impossible. In classic games, such as chess and checkers, all players
can see the entire board at once, whereas in most modern computer strategy
games all players (including the computer) have incomplete knowledge of the
location and composition of the opponents pieces. And while its true that the
AI players can cheat knowledge, its very hard to hide that cheating from
players, and if the cheating is obvious, the game is not fun. Incomplete
knowledge precludes optimal decision-making. Furthermore, in comparison to
55
tradition games, the number of pieces, the number of types of pieces, and the
number of actions available to each piece are colossal. Optimal solutions such
as game trees [Tanimoto87] that try to predict several moves ahead (useful
for tic-tac-toe, and some other small games) are inappropriate and infeasible
due to the relatively enormous branching factor.
The second problem with trying to make an optimal and perfect AI player
is that, even if it were possible, it would be undesirable. Although most
players want a challenging AI opponent, nobody likes to lose all the time. The
goal is to make the player feel threatened, but then to make the player feel as
if she has heroically fought off a superior enemy [Millar96]. Frequently this
involves pushing the player to the edge and then intentionally backing off.
Such a tactic makes the player feel like they just barely held off the enemy
horde, but sent them fleeing with a to-the-lastman defense.
Fortunately or not, its easy enough to create an AI player that will lose a
game. The trick is to make an opponent that can create an exciting ebb and
flow of power. Towards this end, the computer player needs to be able to play
a devastatingly good game, and be able to back off when needed. The AI
must dynamically evaluate its situation, formulate a plan, and execute it. As a
final wrinkle, the AI system must be straightforward to use, as the games
level designers are often non-technical.
a team, only one unit moves at once. The fundamental difference between an
RTS game and a Turn-Based game for an AI developer is that in a TurnBased
game the feedback for any decision is immediate: if you decide to move a
unit, that unit can be moved before anything else happens. However, in an
RTS, you can (and often have to) separate strategic troop and resource
commitment decisions from the tactical/low-level actions of units, whereas in
a Turn-Based game there is no such distinction.
Strategic AI
The goal of the Dark Reign Model for Strategic AI is to allow the creation of
computer opponents that respond to changes in fortune and circumstance. If
a computer opponent can retreat and regroup when things look bleak or
recognize a weakness in the enemys position and attack it,then the gameplay
can be vastly improved. To create this dynamic gameplay, our strategic AI
consists of three modules, an analysis module, a resource allocation module,
and a high level AI module. The first two modules performance is defined by
a set of parameters called an AI Personality (AIP, pronounced "ape"), and the
third module is a logical system which is responsible for changing AIPs when
new situations arise, and for triggering special actions based on certain
events occurring.Each module requires a different kind of AI techniques, and
each is described below.
Analysis Module
The ultimate goal of the analysis module is to define the current strategic
goals and rate them by priority. The strategic goals can include exploration,
reconnaissance, base construction, defensive goals, and offensive goals. In
Dark Reign, the goals were geographically defined: the map was divided into a
number of regions and each region has some offensive, defensive,
information, and/or resource values. These values are combined to make
some overall priority for each region. The analysis system would simply tell
the resource allocation system which areas troops should be sent to (and the
tactical AI handles attacks). Civilization: Call To Power, the goals are targetoriented, which means that each enemy city or unit can become its own goal.
Each goal is still rated by several values. The contribution of each value to the
importance of a goal is set by the level designer through an AIP configuration
file.
The question is "How do we arrive at these values, and what techniques
are useful?" We need to know things such as how far each spot on the map is
from our empire, how far each spot is from the enemy bases, which areas of
the map are dangerous, and which areas can we reach from which other
areas. These are map analysis problems, which are quite similar to computer
vision problems, and our solutions come from that realm (see [Davis96] for
applications of the following techniques in computer vision).
57
Figure 2.5. Resource Allocation: Here we have four units (resources) and
five targets (goals).
Matching problem
Matching problem is a bit more involved for a few main reasons. First,
each task (strategic goal) can requirea different amount of resources (troop
strength composition) to accomplish. Second, each resource (group of our
units) can have a different ability to satisfy each goal (troop strength and
composition). Third, some tasks are more important than others. Also, if we
cannot commit enough resources to a task to fully achieve the goal of that
task, we do not want to commit any units (an insufficient force) to that task.
Thus, we are not concerned with just committing the maximum amount of
resources to tasks, but we also prefer to achieve the most important strategic
goals before the less important ones. Two more wrinkles are that a single
groups forces could be split between two tasks, and/or a single task could be
tackled by forces from a number of different groups.
There are many possible solutions to this problem. Our solutions tend to
be variants on network flow solutions [see Sedgewick92]. Not only are all of
the goals ranked in priority, but all of the matches between troops and goals
are ranked, too. The largest term in the matchs scores is the raw goal priority,
but the appropriateness of a particular unit type and the distance from each
59
unit to the goal (for example) also contribute. This helps a unit right next to
medium priority target choose that goal instead of a high priority one very far
away. We run a greedy network flow bipartite matching algorithm to
commitroops to particular goals. In an RTS such as Dark Reign, after the full
graph is matched as best as we can, we send all the troops on their way. For a
Turn-Based game, in which one decision can immediately affect our next
decision, as soon as one goal is satisfied (has enough troops) we send them
immediately, and then update some of the other matches based on the
results of our action.
60
UNIT III
3.1 GAME AI
At its most basic level, artificial intelligence consists of emulating the
behavior of other players or the entities (that is, all the elements of the game
that can act or be acted upon-from players to missiles to health pickups) they
represent. The key concept is that the behavior is simulated. In other words,
AI for games is more artificial and less intelligence. The system can be as
simple as a rules-based system or as complex as a system designed to
challenge a player as the commander of an opposing army.
3.2.3 Decision-making
The core concept behind AI is decision making. To execute these choices, the
intelligent system needs to be able to affect the entities using the AI system. You can
organize this execution in either an AI push or an entity pull strategy.
AI push systems tend to isolate the AI system as a separate element of the game
architecture. Such a strategy often takes on the form a separate thread or threads in
which the AI spends its time calculating the best choices given the game options.
When the AI makes a decision, that decision is then broadcast to the entities involved.
This approach works best in real-time strategy games, where the AI is concerned with
the big picture.
Entity pull systems work best for games with simple entities. In these games, the
entities call on the AI system when the entity thinks, or updates itself. This
approach works very well in systems with large numbers of entities that do not need
to think very often, such as shooters. This system can also benefit from multithreading techniques, but it requires some extra planning
3.2.4 Basic Perceptions
For the AI to make meaningful decisions, it needs some way of perceiving its
environment. In simpler systems, this perception can be a simple check on the
position of the player entity. As systems become more demanding, entities need to
identify key features of the game world, such as viable paths to walk through, coverproviding terrain, and areas of conflict.
The challenge for designers and developers is to come up with a way to identify key
features important to the intelligence system. For example, cover can be
predetermined by the level designers or can be pre-computed when a map is loaded or
compiled. Some elements must be evaluated on the fly, such as conflict maps and
imminent threats.
3.2.5 Rules-Based Systems
The most basic form an intelligent system can take is that of a rules-based system.
This system stretches the term artificial intelligence. A set of preset behaviors is
used to determine the behavior of game entities. With a variety of actions, the overall
result can be a behavior system that is not obvious although there is very little actual
intelligence involved.
A good example of a rules-based system is a Black Jack dealer (either video
Black Jack or real Black Jack). The dealer has a simple rule that it follows: Always hit
when the cards add up to 17 or less. To the average player, the perception is that the
dealer is playing competitively. The player will imagine a more competent adversary
62
than the one he or she faces (unless the house advertises the rule that the dealers play
by).
The classic application of this system is Pac-Man. Four ghosts plagued the player.
Each ghost followed a simple rule set. One ghost was always to turn left, another was
always to turn right, one turned in a random direction, and the last turned toward the
player. Individually, the ghosts would be easy to figure out, and the player would be
able to handily avoid them. As a group, the pattern of their movement appears to be a
complex, coordinated search party hunting the player. In reality, the only one that
even checks the player's position is the last one.
Visual representation of the rule set governing Pac-Man ghosts, where arrows
represent the decisions that will be made.
As this example suggests, rules do not need to be hard-coded: They can be based
on perceived states (as the last ghost was) or on editable parameters of the entity.
Variables such as aggression, courage, range of sight, and rate of thinking can all lead
to more diverse entity behavior, even within a rules-based system. Rules-based
systems are the simplest structure for an AI. More complex intelligent systems are
built upon and governed by a series of conditional rules. In tactical games, rules
govern which tactics to use. In strategy games, rules govern build orders and how to
react to conflicts. Rules-based systems are the foundation of AI.
3.2.6 Finite State Machines as AI
A finite state machine (FMS) is a way of conceptualizing and implementing an entity
that has distinct states throughout its life. A statecan represent physical conditions
that the entity is in, or it can represent emotional states that the entity can exhibit. In
this example, emotional states are nothing like a true AIs emotional states but
predetermined behavior models that fit into the context of the game.
Here are common examples of states for an AI system for a game with stealth
elements:
63
Layout of the states in a typical FSM, where arrows represent the possible changes in
state
Idle. In this state, the entity is passively standing around or walking along a
set path. Perceptions are low. Player sounds are not often checked for. Only if
this entity is attacked or sees a player directly in front of it will its state
change to a higher level of awareness.
Aware. This entity is actively searching for intruders. It checks often for the
sounds of the player and sees farther and wider than an idle entity. This entity
will move to the Intrigued state if it notices something out of place (something
to check for), such as open doors, unconscious bodies, or spent bullet casings.
Intrigued. This entity is aware that something is up. To demonstrate this
behavior, the entity will abandon its normal post or path and move to areas of
interest, such as the aforementioned open doors or bodies. If a player is seen,
the entity goes to the Alert state.
Alert. In this state, the entity has become aware of the player and will go
through the actions of hunting down the player: moving into range of attack,
alerting fellow guards, sounding alarms, and finding cover. When the entity is
within range of the enemy, it switches to the Aggressive state.
Aggressive. This is the state where the enemy has engaged in combat with
the player. The entity attacks the player when it can and seeks cover between
rounds of attack (based on attack cool-downs or reloading). The entity only
leaves this state if the enemy is killed (return to normal), if the enemy moves
out of firing range (go back to the Alert stage), or if the entity dies (go to the
Dead state). If the entity becomes low on health, it may switch to the Fleeing
state, depending on the courage of the specific entity.
Fleeing. In this state, the entity tries to run from combat. Depending on the
game, there may be a secondary goal of finding health or leaving the play
64
area. When the entity finds health, it may return to the Alert state and resume
combat. An entity that leaves is merely deleted.
Dead. In some games, the state of death may not be completely idle. Death
or dying can have the entity cry out, alerting nearby entities, or go into a
knocked-out state, where it can later be revived by a medic (and returned to a
state of Alert).
There are at least two simple ways to implement an FMS within the entity system.
One is to have each state be a variable that can be checked (often through a massive
switch statement). The other is to use function pointers (in the C language) or virtual
functions (in the C++ and other object-oriented languages).
3.2.7 Adaptive AI
The previous sections discussed methods for designing intelligence systems that fit
into the predefined events of a game. For most games, this is adequate as long as the
designs were thorough and there is a clear understanding of the goals of the intelligent
entities. When a game calls for more variability and a better, more dynamic adversary
for the player, the AI may need to be able to grow and adapt on its own.
Adaptive AI is used commonly in fighting games and strategy games, in which the
mechanics are deep and the options for gameplay are innumerable. To provide a
constant challenge for the player without the player eventually figuring out the
optimal strategy to defeat the computer, the AI needs to be able to learn and adapt.
3.2.8 Prediction
The ability to effectively anticipate an opponents next move is crucial in an adaptive
system. Different methods can be used, such as past-pattern recognition (covered in a
future article) or random guess, to determine the next action to take.
One basic method for adaptation is to keep track of past decisions and evaluate their
success. The AI system keeps a record of choices a player has made in the past. Past
decisions must be evaluated in some manner. (e.g. in fighting games, the advantage
gained or lost-health lost or time advantage-can be the measure for success.)
Additional information about the situation can be gathered to give the decisions some
context, such as relative health, previous actions, and position in the level (people
play differently when their backs are to the wall).
This history can be evaluated to determine the success of previous actions and
whether a change in tactics is required. Until the list of past actions is built, general
tactics or random actions can be used to guide the actions of the entity. This system
can tie into rules-based systems and different states.
65
In a tactical game, past history can decide the best tactics to use against a player team,
such as defensive, offensive, berserk, or some balanced means of play. In a strategy
game, the optimal composition of units in an army can be discovered on a per-player
basis. In games where the AI is controlling supportive characters for the player, the
adaptive AI can better complement the player's natural style by learning the way the
player acts.
The rampant progress of technology makes nearly every game a new beginning.
Even though some basics of the game engine will probably stay the same during a
games development, constant feature and schedule revisions will make creating a
subsystem such as AI something like shooting at a quickly moving target. AI is very
dependent on concrete details of the game environment, which is the main reason why
its often added as one of the last subsystems. In fact, early tech demos rarely feature
it.
There are other reasons why AI is usually shifted to the end of the development
process: Customers value great AI, and bad AI behavior can lead to negative reviews
in the media. A game has to generate money in the end, however, and AI simply does
not have the highest priority from a marketing point of view. Humans are very visual
animals, and a beautiful sunset is much easier to sell than any particularly clever
reasoning capabilities of an opponent.
In addition, early milestone demonstrations for the publisher, press presentations,
and other hype-generating events do not promote inclusion of a globally/consistently
good AI, but instead focus on one or two absolutely unexpected but genius outcomes
of revolutionary new and complex AI procedures (did you spot the ironic tone?) that
provide the necessary wows. Although long-term fun with the game certainly is
important as well, market mechanisms will make it very difficult for AI to receive
equal ranking with features such as graphics and physics. Things might get even more
difficult if the games market should finally turn into a real mass market. Markets such
as persistent online game worlds, on the other hand, may increasingly promote a focus
on consistently good AI because players continuously evaluate these games, gaining
much more insight on mechanics, and they can continuously decide to pay or quit.
Surveys indicate that the percentage of CPU (central processing unit) cycles that
developers are allowed to burn on AI computations is steadily growing. This might be
because the speed of graphics cards has been increasing much faster than that of the
CPU, which frees up lots of resources. Anyway, these additional resources are much
needed for AI computations and open up many possibilities for more sophisticated AI.
66
If you ask an AI researcher what he thinks of EI, he will respond that it's in-a-rut,
plugging algorithms around without truly understanding what they mean, and so on. If
you ask a game development practician what he thinks of AI textbooks, she will
respond that it's impractical, incomprehensive, mathematical and hazy. EI is
development, engineering intelligence-like artifacts. AI is analysis, research into
intelligence-like artifacts. EI is sensing, AI is intuition. EI is results, AI is insights. EI
is sales, AI is grants. EI is standardization, AI is anarchy. Few EI people manage to
get published in AI journals (too boring), few AI people manage to get published in EI
publications (too impractical).
It's important to realize that research and development are two sides of the same
brain, just like feeling and thinking, perceiving and judging, introversion and
extraversion, disorder and order, plasticity and stability, fun and work, yin and yang.
These are dichotomies, and Chris Lofting's web site has much on this topic. The
crucial insight is in the fact that the optimum lies in the balance and collaboration
between the two, not in either extreme. Of course, researchers often think that there is
too much development, and developers often think that there is too much research.
Every salesman peddles his own goods.
67
68
At least until recently, another factor that has limited game AI development is the
fact that developers have been focusing most of their attention on graphics quality. As
it turns out, such focus on developing better and faster graphics techniques, including
hardware acceleration, might now afford more resources to be allocated toward
developing better, more sophisticated AI. This fact, along with the pressure to produce
the next hit game, is encouraging game developers to more thoroughly explore
nondeterministic techniques.
69
UNIT- IV
4.1 Pathfinding
Knowing how to get from point A to point B is something many games require.
Whether youre designing a deep turn-based strategy tactics RPG or a simple puzzle
game, navigating your game world often requires more intelligence from your game
characters than merely pointing towards a goal and moving in a straight line.
You wouldnt want the units in your game to walk through walls. Nor would
players permit units to bump into walls and get stuck when a way around an obstacle
is clearly visible. Theres nothing more frustrating than a real time strategy games
units being unable to make their way to a target location.
This is where pathfinding algorithms come in. Pathfinding is the basic building
block of most game A.I. (artificial intelligence), and with a little help from the proper
code your game will be that much smarter for it.
To get to their goal, your game entities may have to walk around obstacles, find
their way though a dungeon maze or drive around the city streets. It isnt enough
to eventually arrive at the destination via some frustratingly circuitous path - the route
they take should be the shortest possible route.
Solving this problem isnt a trivial task, but it is worth the effort. Enemies that
choose wisely can often appear nearly intelligent. Your players will appreciate that
things just work and will be able to focus on strategy and tactics instead of
worrying about having the babysit broken AI.
The standard method that a majority of games use for pathfinding is called A*,
which is pronounced a star.
4.1.1 The Origins of Pathfinding AI: Dijkstras Algorithm
In the fifties, a mathematician named Edsger Dijkstra worked out a method for
calculating efficient routes that could be applied to any hypethetical situation
requiring an automated choice between many possible steps.
It is often used in the example of trucks going from stop to stop over long distances,
when shipments had to be picked up from various locations along the way. Choosing
the most efficient route would save money.
4.1.2 The Problem With Dijkstras Algorithm
Dijkstras algorithm works great, but has the drawback of being naively implemented
- it doesnt use any special heuristics for choosing the most likely candidates first, and
so the solution is only known after each and every possible location is tested.
70
A* algorithm
In the example with a concave obstacle, A* finds a path as good as what Dijkstras
algorithm found:
71
Dijkstras algorithm
The secret to its success is that it combines the pieces of information that
Dijkstras algorithm uses (favoring vertices that are close to the starting
point) and information that Greedy Best-First-Search uses (favoring vertices that are
close to the goal). In the standard terminology used when talking about
A*, g(n) represents the exact cost of the path from the starting point to any vertex n,
and h(n) represents the heuristic estimated cost from vertex n to the goal. In the above
diagrams, the yellow (h) represents vertices far from the goal and teal ( g) represents
vertices far from the starting point. A* balances the two as it moves from the starting
point to the goal. Each time through the main loop, it examines the vertex n that has
the lowest f(n) = g(n) + h(n).
4.1.4 A* heuristics
The heuristic can be used to control A*s behavior.
At one extreme, if h(n) is 0, then only g(n) plays a role, and A* turns into
Dijkstras algorithm, which is guaranteed to find a shortest path.
If h(n) is always lower than (or equal to) the cost of moving from n to the
goal, then A* is guaranteed to find a shortest path. The lower h(n) is, the
more node A* expands, making it slower.
If h(n) is exactly equal to the cost of moving from n to the goal, then A* will
only follow the best path and never expand anything else, making it very
72
fast. Although you cant make this happen in all cases, you can make it
exact in some special cases. Its nice to know that given perfect
information, A* will behave perfectly.
If h(n) is sometimes greater than the cost of moving from n to the goal,
then A* is not guaranteed to find a shortest path, but it can run faster.
At the other extreme, if h(n) is very high relative to g(n), then only h(n) plays a role,
and A* turns into Greedy Best-First-Search.
So we have an interesting situation in that we can decide what we want to get out
of A*. At exactly the right point, well get shortest paths really quickly. If were too
low, then well continue to get shortest paths, but itll slow down. If were too high,
then we give up shortest paths, but A* will run faster.
In a game, this property of A* can be very useful. For example, you may find that
in some situations, you would rather have a good path than a perfect path. To shift
the balance between g(n) and h(n), you can modify either one.
4.1.5 Speed or Accuracy
A*s ability to vary its behavior based on the heuristic and cost functions can be
very useful in a game. The tradeoff between speed and accuracy can be exploited to
make your game faster. For most games, you dont really need the best path between
two points. You just need something thats close. What you need may depend on
whats going on in the game, or how fast the computer is.
Suppose your game has two types of terrain, Flat and Mountain, and the
movement costs are 1 for flat land and 3 for mountains, A* is going to search three
times as far along flat land as it does along mountainous land. This is because
its possible that there is a path along flat terrain that goes around the mountains. You
can speed up A*s search by using 1.5 as the heuristic distance between two map
spaces. A* will then compare 3 to 1.5, and it wont look as bad as comparing 3 to 1. It
is not as dissatisfied with mountainous terrain, so it wont spend as much time trying
to find a way around it. Alternatively, you can speed up up A*s search by decreasing
the amount it searches for paths around mountainsjust tell A* that the movement
cost on mountains is 2 instead of 3. Now it will search only twice as far along the flat
terrain as along mountainous terrain. Either approach gives up ideal paths to get
something quicker.
The choice between speed and accuracy does not have to be static. You can
choose dynamically based on the CPU speed, the fraction of time going into
pathfinding, the number of units on the map, the importance of the unit, the size of the
group, the difficulty level, or any other factor. One way to make the tradeoff dynamic
73
is to build a heuristic function that assumes the minimum cost to travel one grid space
is 1 and then build a cost function that scales:
If alpha is 0, then the modified cost function will always be 1. At this setting,
terrain costs are completely ignored, and A* works at the level of simple
passable/unpassable grid spaces. If alpha is 1, then the original cost function will be
used, and you get the full benefit of A*. You can set alpha anywhere in between.
You should also consider switching from the heuristic returning
the absolute minimum cost to returning the expected minimum cost. For example, if
most of your map is grasslands with a movement cost of 2 but some spaces on the
map are roads with a movement cost of 1, then you might consider having the
heuristic assume no roads, and return 2 * distance.
The choice between speed and accuracy does not have to be global. You can
choose some things dynamically based on the importance of having accuracy in some
region of the map. For example, it may be more important to choose a good path near
the current location, on the assumption that we might end up recalculating the path or
changing direction at some point, so why bother being accurate about the faraway part
of the path? Or perhaps its not so important to have the shortest path in a safe area of
the map, but when sneaking past an enemy village, safety and quickness are essential.
4.1.6 Scale
A* computes f(n) = g(n) + h(n). To add two values, those two values need to be at
the same scale. If g(n) is measured in hours and h(n) is measured in meters, then A* is
going to consider g or h too much or too little, and you either wont get as good paths
or you A* will run slower than it could.
4.1.7 Exact Heuristics
If your heuristic is exactly equal to the distance along the optimal path, youll see A*
expand very few nodes, as in the diagram shown in next topics. Whats happening
inside A* is that it is computing f(n) = g(n) + h(n) at every node. When h(n) exactly
matches g(n), the value of f(n) doesnt change along the path. All nodes not on the right
path will have a higher value of f than nodes that are on the right path. Since A*
doesnt consider higher-valued f nodes until it has considered lower-valued f nodes, it
never strays off the shortest path.
4.1.8 Precomputed exact heuristic
74
One way to construct an exact heuristic is to precompute the length of the shortest
path between every pair of points. This is not feasible for most game maps. However,
there are ways to approximate this heuristic:
Fit a coarse grid on top of the fine grid. Precompute the shortest path
between any pair of coarse grid locations.
Precompute the shortest path between any pair of waypoints. This is a
generalization of the coarse grid approach.
Then add in a heuristic h' that estimates the cost of going from any location to
nearby waypoints. (The latter too can be precomputed if desired.) The final heuristic
will be:
h(n) = h'(n, w1) + distance(w1, w2) + h'(w2, goal)
or if you want a better but more expensive heuristic, evaluate the above with all
pairs w1,w2 that are close to the node and the goal, respectively.
4.1.9 Linear exact heuristic
In a special circumstance, you can make the heuristic exact without precomputing
anything. If you have a map with no obstacles and no slow terrain, then the shortest
path from the starting point to the goal should be a straight line.
If youre using a simple heuristic (one which does not know about the obstacles
on the map), it should match the exact heuristic. If it doesnt, then you may have a
problem with scale or the type of heuristic you chose.
On a grid, there are well-known heuristic functions to use.
Use the distance heuristic that matches the allowed movement:
75
Multiply the distance in steps by the minimum cost for a step. For example, if youre
measuring in meters, the distance is 3 squares, and each square is 15 meters, then the
heuristic would return 3 15 = 45 meters. If youre measuring in time, the distance is
3 squares, and each square takes at least 4 minutes to cross, then the heuristic would
return 3 4 = 12 minutes. The units (meters, minutes, etc.) returned by the heuristic
should match the units used by the cost function.
4.1.10 Manhattan distance
The standard heuristic for a square grid is the Manhattan distance. Look at your cost
function and find the minimum cost D for moving from one space to an adjacent
space. In the simple case, you can set D to be 1. The heuristic on a square grid where
you can move in 4 directions should be D times the Manhattan distance:
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy)
How do you pick D? Use a scale that matches your cost function. For the best paths,
and an admissible heuristic, set D to the lowest cost between adjacent squares. In
the absence of obstacles, and on terrain that has the minimum movement cost D,
moving one step closer to the goal should increase g by D and decrease h by D. When
you add the two, f (which is set to g + h) will stay the same; thats a sign that the
heuristic and cost function scales match. You can also give up optimal paths to make
A* run faster by increasing D, or by decreasing the ratio between the lowest and
highest edge costs.
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
Here we compute the number of steps you take if you cant take a diagonal, then
subtract the steps you save by using the diagonal. There are min(dx, dy) diagonal steps,
and each one costs D2 but saves you 2D non-diagonal steps.
When D = 1 and D2 = 1, this is called the Chebyshev distance. When D = 1 and D2 =
sqrt(2), this is called the octile distance.
Patrick Lester has a different way of writing this heuristic, using an explicit cases
for dx > dy vs dx < dy. The above code has the same test but its hidden inside the call
to min.
4.1.12 Euclidean distance
If your units can move at any angle (instead of grid directions), then you should
probably use a straight line distance:
function heuristic(node) =
dx = abs(node.x - goal.x)
77
dy = abs(node.y - goal.y)
return D * sqrt(dx * dx + dy * dy)
However, if this is the case, then you may have trouble with using A* directly because
the cost function g will not match the heuristic function h. Since Euclidean distance is
shorter than Manhattan or diagonal distance, you will still get shortest paths, but A*
will take longer to run:
Do not do this! This definitely runs into the scale problem. The scale of g and h need
to match, because youre adding them together to form f. When A* computes f(n) =
g(n) + h(n), the square of distance will be much higher than the cost g and you will end
up with an overestimating heuristic. For longer distances, this will approach the
extreme of g(n) not contributing to f(n), and A* will degrade into Greedy Best-FirstSearch:
78
To attempt to fix this you can scale the heuristic down. However, then you run into the
opposite problem: for shorter distances, the heuristic will be too small compared
to g(n)and A* will degrade into Dijkstras algorithm.
If, after profiling, you find the cost of the square root is significant, either use a fast
square root approximation with Euclidean distance or use the diagonal distance as an
approximation to Euclidean.
4.1.13 Multiple goals
If you want to search for any of several goals, construct a heuristic h'(x) that is the
minimum of h1(x), h2(x), h3(x), ... where h1, h2, h3 are heuristics to each of the nearby
spots.
If you want to search for spot near a single goal, ask A* search to find a path to the
center of the goal area. While processing nodes from the OPEN set, exit when you
pull a node that is near enough.
79
Tiles in f values
The quick hack to work around this problem is to either adjust the g or h values. The
tie breaker needs to be deterministic with respect to the vertex (i.e., it shouldnt just be
a random number), and it needs to make the f values differ. Since A* sorts by f value,
making them different means only one of the equivalent f values will be explored.
One way to break ties is to nudge the scale of h slightly. If we scale it downwards,
then f will increase as we move towards the goal. Unfortunately, this means that A*
will prefer to expand vertices close to the starting point instead of vertices close to the
goal. We can instead scale h upwards slightly (even by 0.1%). A* will prefer to
expand vertices close to the goal.
heuristic *= (1.0 + p)
The factor p should be chosen so that p <(minimum cost of taking one step)/(expected
maximum path length). Assuming that you dont expect the paths to be more than
1000 steps long, you can choose p = 1/1000. (Note that this slightly breaks
80
admissibility of the heuristic but in games it almost never matters.) The result of
this tie-breaking nudge is that A* explores far less of the map than previously:
81
Steven van Dijk suggests that a more straightforward way to do this would to pass h to
the comparison function. When the f values are equal, the comparison function would
break the tie by looking at h.
Another way to break ties is to add a deterministic random number to the heuristic or
edge costs. (One way to choose a deterministic random number is to compute a hash
of the coordinates.) This breaks more ties than adjusting h as above. Thanks to Cris
Fuhrman for suggesting this.
A different way to break ties is to prefer paths that are along the straight line from the
starting point to the goal:
dx1 = current.x - goal.x
dy1 = current.y - goal.y
dx2 = start.x - goal.x
dy2 = start.y - goal.y
cross = abs(dx1*dy2 - dx2*dy1)
heuristic += cross*0.001
This code computes the vector cross-product between the start to goal vector and the
current point to goal vector. When these vectors dont line up, the cross product will
be larger. The result is that this code will give some slight preference to a path that
82
lies along the straight line path from the start to the goal. When there are no obstacles,
A* not only explores less of the map, the path looks very nice as well:
83
Alternate map representations can solve the problem by reducing the number
of nodes in the graph. Collapsing multiple nodes into one, or by remove all but
the important nodes. Rectangular Symmetry Reduction is a way to do this on
84
square grids; also look at framed quad trees. Hierarchical pathfinding uses a
high level graph with few nodes to find most of the path, then a low level
graph with more nodes to refine the path.
Some approaches leave the number of nodes alone but reduce the number of
nodes visited. Jump Point Search skips over large areas of nodes that would
contain lots of ties; its designed for square grids. Skip links add shortcut
edges that skip over areas of the map. The AlphA* algorithm adds some
depth-first searching to the usual breadth-first behavior of A*, so that it can
explore a single path instead of processing all of them simultaneously.
Fringe Search (PDF) solves the problem instead by making node processing
fast. Instead of keeping the OPEN set sorted and visiting nodes one at a time,
it processes nodes in batches, expanding only the nodes that have low fvalues. This is related to the HOT queues approach.
4.2 Flocking and Stearing
Flocking move in cohesive groups rather than independently, grazing in a
flock rather than walking aimlessly.
classic flocking has elegantly 3 simple rules:
Cohesion: have each unit steer toward the average position of its
neighbors
Alignment: have each unit steer so as to align itself to the average
heading of its neighbors.
Separation: have each unit steer to avoid hitting its neighbors
Treating the units as rigid bodies enables you to take care of orientation
rather than use particles to represent the units which you don't have to worry
about rotation.
The visibility arc is defined by 2 parameters: the arc radius (r) and the
angle ()
large radius will allow the unit to see m ore of the group and results in a m
ore cohesive flock, a smaller radius tends to increase the likelihood of
temporarily lose sight of their neighbors and results in a larger flock with
possible detached units which need to be re-join, navigating around
obstacles also can cause a flock to break up.
and angle measures the field of view of each unit, a view of 360
degree is easier to implement but the resulting flocking behavior might be
somewhat unrealistic, a m ore com m on field of view is having a distinct
blind spot behind each unit, the very narrow field of view will degenerate
a flock into units that one follows another and form a curved line.
Steer model: each rule makes a small contribution to the total steering force
and the net result is applied to the unit, require some tuning to make sure no
single rule dominates, tuning is done by trial and error.
We want the avoidance rule steering force contribution to be small when
the units are far away from each other, but we want the avoidance rule
85
alignment rule:
if ( doFlock && (n > 0) )
{
vAve = vAve / n;
u = vAve;
u.normalize( );
v = units[i].vVelocity;
v.normalize( );
w = vRotate2D(-units[i].fOrientation, u);
if ( w.x < 0 ) m = -1;
if ( w.x > 0 ) m = 1;
if ( fabs(v * u) < 1 )
{
fs.x += m * steeringForce * acos(v * u) / pi;
}
}
separation rule:
for ( j = 1; j < maxNumUnits; j++ )
{
if ( inView )
{
if ( d.magnitude( ) <= units[i].fLength * radiusFactor )
{
pAve += units[j].vPosition; vAve += units[j].vVelocity;
}
elsif ( d.magnitude() <= units[i].fLength*separationFactor )
{
if ( w.x < 0 ) m = -1; if ( w.x > 0 ) m = 1;
fs.x += m * steeringForce * (units[i].fLength *
separationFactor) / d.magnitude( );
}
}
}
Obstacle avoidance:
Simple idealization of an obstacle: cycle
Outfit our units with virtual feelers, they will stick out in front of the units,
and if they hit something, this will be an indication to the units to turn.
The vector v, represent the feeler, the vector a is the difference between
the unit's and the obstacle's positions, project a onto v by taking their do
product and produce vector p, subtract vector p from a yields vector b, to test
whether v intersects the circle somewhere we need to test 2 conditions: the
magnitude of p must be less than the magnitude of v, and the magnitude of b
87
88
Cohesion
Keeps boids together as a group.
Each boid moves in the direction of the average position of its neighbors.
Compute the direction to the average position of local flock mates and
steer in that direction.
Alignment
Drives boids to head in the same direction with similar velocities (velocity
matching).
Calculate average velocity of flock mates in neighborhood and steer towards
that velocity.
89
Obstacle Avoidance
Allows the flock to avoid obstacles by steering away from approaching
objects.
Reynolds uses the method shown below:
Assume a cylindrical line of sight
Compute cylinder-sphere intersection and veer away from any objects in
path.
Goal Seeking
Drives the flock in the direction of a target/goal.
Each boid determines the direction to the goal and then steers in that
direction
(Note: this is basically the same as cohesion).
90
Match: In this first phase, the left-hand sides of all productions are
matched against the contents of working memory. As a result a conflict
set is obtained, which consists of instantiations of all satisfied productions.
An instantiation of a production is an ordered list of working memory
elements that satisfies the left-hand side of the production.
91
Using a set of assertions, which collectively form the working memory, and a
set of rules that specify how to act on the assertion set, a rule-based system
can be created. Rule-based systems are fairly simplistic, consisting of little
more than a set of if-then statements, but provide the basis for so-called
expert systems which are widely used in many fields. The concept of an
expert system is this: the knowledge of an expert is encoded into the rule set.
When exposed to the same data, the expert system AI will perform in a similar
manner to the expert.
Rule-based systems are a relatively simple model that can be adapted to
any number of problems. As with any AI, a rule-based system has its strengths
as well as limitations that must be considered before deciding if its the right
technique to use for a given problem. Overall, rule-based systems are really
only feasible for problems for which any and all knowledge in the problem
area can be written in the form of if-then rules and for which this problem area
is not large. If there are too many rules, the system can become difficult to
maintain and can suffer a performance hit.
To create a rule-based system for a given problem, you must have (or
create) the following:
A set of facts to represent the initial working memory. This should be anything
relevant to the beginning state of the system.
A set of rules. This should encompass any and all actions that should be taken
within the scope of a problem, but nothing irrelevant. The number of rules in
the system can affect its performance, so you dont want any that arent
needed.
A condition that determines that a solution has been found or that none
exists. This is necessary to terminate some rule-based systems that find
themselves in infinite loops otherwise.
92
93
(II) Backward-Chaining
In other problems, a goal is specified and the AI must find a way to
achieve that specified goal. For example, if there is an epidemic of a certain
disease, this AI could presume a given individual had the disease and attempt
94
ideal.
If neither is dominant, the number of facts in the working memory may
help the decision. If all (relevant) facts are already known, and the purpose of
the system is to find where that information leads, forward-chaining should be
selected. If, on the other hand, few or no facts are known and the goal is to
find if one of many possible conclusions is true, use backward-chaining.
(III) Improving Efficiency of Forward Chaining
Forward-chaining systems, as powerful as they can be if well designed,
can become cumbersome if the problem is too large. As the rule-base and
working memory grow, the brute-force method of checking every rule
condition against every assertion in the working memory can become quite
computationally expensive. Specifically, the computational complexity if the
order of RA^C, where R is the number of rules, C is the approximate number
of conditions per rule, and A is the number of assertions in working memory.
With this exponential complexity, for a rule-base with any real rules, the
system will perform quite slowly.
There are ways to reduce this complexity, thus making a system of this
nature far more feasible for use with real problems. The most effective such
solution to this is the Rete algorithm. The Rete algorithm reduces the
complexity by reducing the number of comparisons between rule conditions
and assertions in the working memory. To accomplish this, the algorithm
stores a list of rules matched or partially matched by the current working
memory. Thus, it avoids unnecessary computations in re-checking the already
matched rules (they are already activated) or un-matched rules (their
conditions cannot be satisfied under the existing assertions in the working
memory). Only when the working memory changes does it re-check the rules,
and then only against the assertions added or removed from working memory.
All told, this method drops the complexity to O(RAC), linear rather than
exponential.
The Rete algorithm, however, requires additional memory to store the state of
the system from cycle to cycle. The additional memory can be considerable,
but may be justified for the increased speed efficiency. For large problems in
which speed is a factor, the Rete method is justified. For small problems, or
those in which speed is not an issue but memory is, the Rete method may not
be the best option. Another unfortunate shortcoming of the Rete method is
that it only works with forward-chaining.
4.4 Finite State Machines
A finite-state machine is a model used to represent and control execution
flow. It is perfect for implementing AI in games, producing great results
96
97
98
FSM representing the brain of an Ant. Notice the lack of transition between run away
and go home
4.4.2 Implementing a FSM
In FSM can be implemented and encapsulated in a single class, named FSM for
instance. The idea is to implement every state as a function or method, using a
property called active state in the class to determine which state is active:
public class FSM {
private var activeState :Function; // points to the currently active state
function
public function FSM() {
}
public function setState(state :Function) :void {
activeState = state;
}
public function update() :void {
if (activeState != null) {
activeState();
}
}
}
99
Since every state is a function, while an specific state is active the function
representing that state will be invoked every game update. The active state property is
a pointer to a function, so it will point to the active state's function.
The update() method of the FSM class must be invoked every game frame, so that
it can call the function pointed by the active State property. That call will update the
actions of the currently active state.
The setState() method will transition the FSM to a new state by pointing the
active State property to a new state function. The state function doesn't have to be a
member of FSM; it can belong to another class, which makes the FSM class more
generic and reusable.
4.4.3 Using a FSM
Using the FSM class already described, it's time to implement the "brain" of a
character. The previously explained ant will be used and controlled by an FSM. The
following is a representation of states and transitions, focusing on the code:
The ant is represented by the Ant class, which has a property named brain and a
method for each state. The brain property is an instance of the FSM class:
public class Ant
100
{
public var position :Vector3D;
public var velocity :Vector3D;
public var brain
:FSM;
public function Ant(posX :Number, posY :Number) {
position = new Vector3D(posX, posY);
velocity = new Vector3D( -1, -1);
brain
= new FSM();
// Tell the brain to start looking for the leaf.
brain.setState(findLeaf);
}
/**
* The "findLeaf" state.
* It makes the ant move towards the leaf.
*/
public function findLeaf() :void {
}
/**
* The "goHome" state.
* It makes the ant move towards its home.
*/
public function goHome() :void {
}
/**
* The "runAway" state.
* It makes the ant run away from the mouse cursor.
*/
public function runAway() :void {
}
public function update():void {
// Update the FSM controlling the "brain". It will invoke the currently
// active state function: findLeaf(), goHome() or runAway().
brain.update();
// Apply the velocity vector to the position, making the ant move.
moveBasedOnVelocity();
}
101
(...)
}
The Ant class also has a velocity and a position property, both used to calculate
the movement using Euler integration. The update() method is called every game
frame, so it will update the FSM.
To keep things simple, the code used to move the ant, such as
moveBasedOnVelocity(), will be omitted. More info on that can be found in the
Understanding Steering Behaviors series.
Below is the implementation of each state, starting with findLeaf(), the state
responsible for guiding the ant to the leaf position:
public function findLeaf() :void {
// Move the ant towards the leaf.
velocity
=
new
Vector3D(Game.instance.leaf.x
Game.instance.leaf.y - position.y);
position.x,
102
position.x,
position.y
Stack-based FSM
104
Transitions in a stack-based FSM: pop itself + push new; pop itself; push new.
It can pop itself from the stack and push another state, which means a full
transition (just like the simple FSM was doing). It can pop itself from the stack, which
means the current state is complete and the next state in the stack should become
active. Finally, it can just push a new state, which means the currently active state will
change for a while, but when it pops itself from the stack, the previously active state
will take over again.
4.4.5 Implementing a Stack-Based FSM
A stack-based FSM can be implemented using the same approach as before,
but this time using an array of function pointers to control the stack.
The active State property is no longer needed, since the top of the stack
already points to the currently active state:
public class StackFSM {
private var stack :Array;
public function StackFSM() {
this.stack = new Array();
}
public function update() :void {
var currentStateFunction :Function = getCurrentState();
if (currentStateFunction != null) {
currentStateFunction();
}
}
public function popState() :Function {
return stack.pop();
}
public function pushState(state :Function) :void {
if (getCurrentState() != state) {
stack.push(state);
}
}
public function getCurrentState() :Function {
105
The setState() method was replaced with two new methods: pushState() and
popState(); pushState() adds a new state to the top of the stack, while popState()
moves the state at the top of the stack. Both methods automatically transition the
machine to a new state, since they change the top of the stack.
4.4.6 Using a Stack-Based FSM
When using a stack-based FSM, it's important to note that each state is
responsible for popping itself from the stack. Usually a state removes itself
from the stack when it is no longer needed, like if attack() is active but the
target just died. Using the ant example, just a few changes are required to
adapt the code to use a stack-based FSM. The problem of not knowing the
state to transition to is now seamlessly solved thanks to the very nature of
stack-based FSM:
public class Ant {
(...)
public var brain :StackFSM;
public function Ant(posX :Number, posY :Number) {
(...)
brain = new StackFSM();
// Tell the brain to start looking for the leaf.
brain.pushState(findLeaf);
(...)
}
/**
* The "findLeaf" state.
* It makes the ant move towards the leaf.
*/
public function findLeaf() :void {
// Move the ant towards the leaf.
velocity
=
new
Vector3D(Game.instance.leaf.x
Game.instance.leaf.y - position.y);
if (distance(Game.instance.leaf, this) <= 10) {
106
position.x,
position.x,
107
Game.mouse.x,
position.y
The result is an ant able to run away from the mouse cursor, transitioning back to the
previously active state before the threat:
Ant controlled by a stack-based FSM. Move the mouse cursor to threaten the
ant.
4.4.7 Conclusion
Finite-state machines are useful to implement AI logic in games. They can be
easily represented using a graph, which allows a developer to see the big picture,
tweaking and optimizing the final result. The implementation of a FSM using
functions or methods to represent states is simple, but powerful. Even more complex
results can be achieved using a stack-based FSM, which ensures a manageable and
concise execution flow without negatively impacting the code.
4.5 Patterning and waypoints
Artificial Intelligence can be a significant addition to many different types of
video games. Techniques of artificial intelligence make a more compelling experience
for the player by simulating human-like behaviors in their computerized opponents.
Our goal is to create computer-controlled characters that will:
* act in a way that is neither completely predictable nor purely random
* be responsive/adaptive to the player and to the environment (such as an
items/obstacles in the layout)
* present a level of challenge that is neither too easy nor too hard
For example, Let us discuss about of enemy movement in an airplane shoot-emup game, with emphasis on the idea of "waypoints": reference points in space used for
navigation.
108
The main idea is to create a Sprite object (small and invisible) that serves as a
Waypoint; each will contain two instance variables: ID and NextID. Each Enemy
sprite contains an instance variable called TargetID, which stores the ID of a
Waypoint, and each Enemy's angle of motion is constantly updated so that it is
moving towards the corresponding Waypoint. Once an Enemy reaches the desired
Waypoint, the Enemy updates its TargetID to the value stored in the Waypoint's
NextID variable, and the Enemy's journey continues. In the sections that follow, we
discuss the implementation details, as well as introduce additional techniques (each of
which is optional) to make the enemy movement seem more "realistic".
4.5.1 Initial Setup
Movement
First, we create a new project with window size and layout size of 800 by 600
pixels. Then, create:
* a Sprite object named "Player" with 8-Direction and Bound to Layout behaviors
* a Sprite object named "Enemy" with Bullet and Timer behaviors, and an instance
variable called TargetID with initial value 1.
* a Sprite object named "EnemyMissile" with the Bullet and Destroy Outside Layout
behaviors.
* a Sprite object named "Waypoint" with two instance variables: ID and NextID
Then create multiple instances of the Waypoint sprite in your layout and arrange
them as desired. Change their instance variable ID values to the numbers 1, 2, 3,... in
the order they should be visited by the enemies. For each Waypoint, change the value
of NextID to one more than ID, except for the last Waypoint, whose NextID value
should be set to 1 (assuming they will be travelling in a loop).
There are two events to keep move the enemies along the waypoints.
First, for each Enemy you need to select the Waypoint whose ID is equal to the
Enemy's TargetID value, and set the angle of motion towards that Waypoint
(the angle can be calculated using the function angle(Enemy.X, Enemy.Y,
Waypoint.X, Waypoint.Y)). Also, make sure that the "Set Angle" property of the
Enemy's Bullet behavior is set to "No", and rotate the Enemy to face the
Player (this will be important when the enemies spawn objects to shoot at the
player). Second, if an enemy collides with a Waypoint and that Waypoint's ID
is equal to the Enemy's TargetID, then the Enemy determines its next target
by setting its TargetID value to equal the NextID value of the Waypoint.
109
Firing
We've set up the code so that enemies are facing the player; next, we would like
them to fire at regular intervals. There are a number of way to achieve this result:
* We could set up the event: Every X Seconds -- Enemy Spawns EnemyMissile. This
causes the unrealistic (and hence undesirable) result that every Enemy on the screen
will fire at the Player at the exact same time.
* When new enemies are spawned, we start a Timer action on each to activate
Regularly, say, 1.5 seconds, and use the On Timer condition for an Enemy to spawn
an EnemyMissile. This is slightly better, since Enemies could fire at different times,
but an attentive player will still spot a mechanical regularity in the firing patterns.
* A better option is to modify the previous approach, and set a Timer with a randomly
calculated duration (say, random(1.0, 2.0)) to activate Once, and then after the On
Timer condition activates, set another Timer in the same way (random duration, type
Once). There are no patterns in the fire timing here, and thus it may feel more
realistic.
In addition, it may not be the case that all enemies have perfect aim, so to
incorporate this feature you can calculate and set the missile's angle of motion to be
the angle towards the player plus a small random value between -X and X. (For this to
work correctly, EnemyMissile objects need to have the Bullet property "Set Angle" set
to "No".)
110
value to 1 (or in general, 1/4 the value of the period), this will cause the Waypoints to
move in a circle.
((Technical mathy note: by changing the period offset of a Sine function to 1/4
the value of the period, we're actually creating a Cosine function, and in general, the
equation of a circle can be parameterized by using one of Sine or Cosine for the X
coordinate, and using the other for the Y coordinate.))
4.5.4 Enemy Speed
Another realistic touch we could add to Enemy movement is to vary the speed.
Always moving at the same speed falls into the category of unrealistic patterns that
we wish to avoid. Instead, we will set up our Enemy objects to alternate between slow
and fast movement.
To accomplish this, we'll add a Sine behavior to the Enemy objects, and set the
Movement property to "Value Only". Then, in the event sheet, we will have each
Enemy set its Bullet speed to 150 + Enemy.Sine.Value, and with the Sine Magnitude
set to 50, this means that the speed will fluctuate between 150 - 50 = 100 and 150 +
50 = 200.
Fuzzy Logic
Fuzzy logic takes a complex sentence such as TallPerson(Nate) V
Smart(Nate) and determines its truth value as a function of the truth values of
its components. The rules for evaluating the fuzzy truth, T, of a complex
sentence are
Fuzzy logic is therefore a truth-functional system, and is thus subject to all the
usual problems.
It has the additional
problem that it is inconsistent
with normal propositional or first-order logic. We would like any logic to ensure
that standard equivalences such as True hold, but in fuzzy logic,
Despite these serious semantic difficulties, fuzzy logic has been very
successful in commercial applications, particularly in control systems for
products such as automatic transmissions,trains, video cameras, and electric
shavers. Elkan (1993) argues that these applications are successful because
they have small rule bases, have no chaining of inferences, and have tunable
parameters that can be adjusted to improve the system's performance (often
by learning techniques). The fact that they are implemented with fuzzy
operators is incidental to their success.
Elkan predicts that when more complex applications are tackled with fuzzy
logic, they will run into the same kinds of problems that plagued knowledgebased systems using certainty factors and other approaches.
4.7 Genetic Algorithm
Nature has a robust way of evolving successful organisms. The organisms
that are ill-suited for an environment die off, whereas the ones that are fit live
to reproduce. Offspring are similar to their parents, so each new generation
has organisms that are similar to the fit members of the previous generation.
113
If the environment changes slowly, the species can gradually evolve along
with it,but a sudden change in the environment is likely to wipe out a species.
Occasionally, random mutations occur, and although most of these mean a
quick death for the mutated individual, some mutations lead to new
successful species. The publication of Darwin's The Origin of Species on the
Basis of Natural Selection was a major turning point in the history of science.
It turns out that what's good for nature is also good for artificial systems.
Figure given below shows the GENETIC-ALGORITHM, which starts with a set of
one or more individuals and applies selection and reproduction operators to
"evolve" an individual that is successful, as measured by a fitness function.
There are several choices for what the individuals are. They can be entire
agent functions, in which case the fitness function is a performance measure
or reward function, and the analogy to natural selection is greatest. They can
be component functions of an agent, in which case the fitness function is the
critic. Or they can be anything at all that can be framed as an optimization
problem.
Since the evolutionary process learns an agent function based on
occasional rewards (offspring) as supplied by the selection function, it can be
seen as a form of reinforcement learning.
Unlike the algorithms described in the previous sections, however, no
attempt is made to learn the relationship between the rewards and the
actions taken by the agent or the states of the environment. GENETICALGORITHM simply searches directly in the space of individuals, with the goal
of finding one that maximizes the fitness function. The search is parallel
because each individual in the population can be seen as a separate search. It
is hill climbing because we are making small genetic changes to the
individuals and using the best resulting offspring. The key question is how to
allocate the searching resources: clearly, we should spend most of our time on
the most promising individuals, but if we ignore the low-scoring ones, we risk
getting stuck on a local maximum. It can be shown that, under certain
114
The fitness function depends on the problem, but in any case, it is a function
that takes an individual as input and returns a real number as output. In the
"classic" genetic algorithm approach, an individual is represented as a string
over a finite alphabet. Each element of the string is called a gene. In real DNA,
the alphabet is AGTC (adenine, guanine, thymine, cytosine), but in genetic
algorithms, we usually use the binary alphabet (0,1). Some authors reserve
the term "genetic algorithm" for cases where the representation is a bit string,
and use the term evolutionary programming when the representation is more
complicated. Other authors make no distinction, or make a slightly different
one.
The selection strategy is usually randomized, with the probability of
selection proportional to fitness. That is, if individual X scores twice as high as
Y on the fitness function, then X is twice as likely to be selected for
reproduction than is Y. Usually, selection is done with replacement, so that a
very fit individual will get to reproduce several times.
Reproduction is accomplished by cross-over and mutation. First, all the
individuals that have been selected for reproduction are randomly paired.
Then for each pair, a cross-over point is randomly chosen. Think of the genes
of each parent as being numbered from 1 to N. The cross-over point is a
number in that range; let us say it is 10. That means that one offspring will
get genes 1 through 10 from the first parent, and the rest from the second
parent. The second offspring will get genes 1 through 10 from the second
parent, and the rest from the first. However, each gene can be altered by
random mutation to a different value, with small independent probability. The
diagram given below shows the process.
115
We also need one bit for each test to say if the outcome is Yes or No. Thus, if
we want to represent a k-DL with a length of up to t tests, we need a
representation with t(5k +1) bits. We can use the standard selection and
reproduction approaches. Mutation can flip an outcome or change an
attribute. Cross-over combines the head of one decision list with the tail of
another.
116
117
The individual neurons are complicated. They have a myriad of parts, subsystems, and control mechanisms. They convey information via a host of
electrochemical pathways. There are over one hundred different classes of
neurons, depending on the classification method used. Together these
neurons and their connections form a process which is not binary, not stable,
and not synchronous. In short, it is nothing like the currently available
electronic computers, or even artificial neural networks.
These artificial neural networks try to replicate only the most basic
elements of this complicated, versatile, and powerful organism. They do it in a
primitive way. But for the software engineer who is trying to solve problems,
neural computing was never about replicating human brains. It is about
machines and a new way to solve problems.
4.8.2 Artificial Neurons and How They Work
The fundamental processing element of a neural network is a neuron. Th is
A Simple Neuron
Within humans there are many variations on this basic type of neuron, further
complicating man's attempts at electrically replicating the process of thinking. Yet, all
natural neurons have the same four basic components. These components are known
by their biological names - dendrites, soma, axon, and synapses. Dendrites are hairlike extensions of the soma which act like input channels. These input channels
receive their input through the synapses of other neurons. The soma then processes
118
these incoming signals over time. The soma then turns that processed value into an
output which is sent out to other neurons through the axon and the synapses.
Recent experimental data has provided further evidence that biological neurons
are structurally more complex than the simplistic explanation above. They are
significantly more complex than the existing artificial neurons that are built into
today's artificial neural networks. As biology provides a better understanding of
neurons, and as technology advances, network designers can continue to improve
their systems by building upon man's understanding of the biological brain.
But currently, the goal of artificial neural networks is not the grandiose recreation
of the brain. On the contrary, neural network researchers are seeking an understanding
of nature's capabilities for which people can engineer solutions to problems that have
not been solved by traditional computing.
To do this, the basic unit of neural networks, the artificial neurons, simulate the
four basic functions of natural neurons. Figure given below shows a fundamental
representation of an artificial neuron.
UNIT V
The Future for AI in games
Artificial intelligence in games has matured significantly in the past decade.
Creating effective AI systems has now become as important for game developers as
creating solid gameplay and striking visuals. Studios have begun to assign dedicated
programming teams to AI development from the onset of a game's design cycle,
spending more time and resources on trying to build varied, capable, and consistent
non-player characters (NPCs). More developers are also using advances in AI to help
their games stand out in what has already become a very crowded marketplace,
spawning a slowly growing discussion in the industry about redefining game genres.
Think tanks and roundtables on advances in game AI have become prominent at the
annual Game Developers Conference (GDC), while smaller AI-dedicated conferences
such as the annual Paris Game AI Conference and developer-run online hubs such as
AiGameDev.com are garnering a big industry and community following. While
industry awareness about the significance of AI in games continues to grow,
GameSpot prompted Matthew Titelbaum from Monolith Games, Remco Straatman
from Guerrilla Games, and AiGameDev.com founder Alex J. Champandard to share
their thoughts on the future and growth of game AI.
awards was to spotlight the games that showed promise in the field of AI,
either by trying something different or exhibiting technical proficiency. In
2009, the Best Combat AI and the overall Best Game AI awards were won by
the same studio--Guerrilla Games for Killzone 2. Remco Straatman, lead AI
programmer at Guerrilla, says a lot has changed in game AI in the last five to
10 years, with more developers trading low-level scripting for more advanced
NPC decision systems.
"In general, I think game AI has gone from the stage where it was an
achievement if it did not stand out negatively to the point where AI in most
big games is solid, and some titles are using innovative new ideas,"
Straatman says. "More development teams have also moved from simple
state machines to behaviour trees and using planners in NPC AI systems
describing knowledge of the world around the NPCs have improved with
better knowledge for navigation over changing terrain, and more knowledge
about strategic properties of the world such as cover. I also think advances in
animation systems with better ways to combine various animations and
physics have become available, which now allows for more realistic
movement and responses to being hit [in combat AI]. Most of these systems
were not around 10 years ago or simply could not run on the hardware
available."
Creating a solid game AI system involves successfully networking smaller
systems together. For example, a system that deals with the problem-solving
capabilities of individual NPCs goes hand in hand with a system that makes
sense of the gameworld and its parameters and helps NPCs make relevant
decisions. Thankfully, developers don't have to build these systems from
scratch: they use specific planners that generate increasingly complex
networks.
"At the moment [Guerrilla Games] is using a specific type of planner for
our NPCs called Hierarchical Task Network (HTN)," Straatman says. "This is
capable of generating more complex plans than what we had before Killzone
2. We also keep on improving things like the CPU performance, which means
we can support more NPCs in Killzone 3 than we could in Killzone 2. The
terrain-reasoning systems we generate have also evolved over our various
titles. We are now able to deal with much more dynamic terrain (like obstacles
moving around or changing shape) than ever before. Our data on where there
is cover has also become more detailed, something that allows NPCs to deal
with more complex environments such as multistory buildings, etc."
121
Killzone 2's lead AI programmer Remco Straatman believes the industry is still
struggling to make NPCs as human as possible.
Back when Straatman and Guerrilla began work on Killzone and
Shellshock, the teams goal was to make the AI system as capable of making
its own decisions as possible, realising this would make things all the more fun
for players. However, doing this in a consistent way proved to be a lot more
work than the team anticipated, particularly when dealing with combat AI.
While the goal of normal AI is to emulate the real-life behaviour of a particular
nature (for example, doctor, civilian, or shopkeeper), combat AI works very
differently. Firstly, its main objective is to be as entertaining as possible. In
some cases this means being efficient at killing players; in other cases, it's
more about making intentional mistakes and "overacting" by way of signalling
to players what is about to happen.
"Where normal AI tries to emulate an expert medical specialist or world
champion chess player, game combat AI is more like emulating an actor,"
Straatman says. "At the end of Killzone 2 we found ourselves looking at the
NPCs doing things that we did not expect, and this surprised us positively.
Reviews and forum feedback confirmed we had at least partly achieved the
vision we had so many years back, and people playing the game recognised
and appreciated it."
One of Killzone 2's most commended features in the field of AI was the
game's skirmish mode. Because this mode is more team-based and tactical
than the single-player campaign, the AI bots in this part of the game need to
do more than simply run around and kill one another. Guerrilla based the
skirmish AI in Killzone 2 on the real-time strategy model, building two levels of
AI on each individual bot. The first is a commander AI, which controls overall
strategic decisions; the second is a squad AI, which translates the commander
AI's orders into orders for the individual bots. The team then taught the bots
how to use the in-game badges as part of the order given to them by the
squad. For example, if an engineer bot is ordered to defend an area, he will
first build a turret at a tactical position before starting to patrol. While some
122
The AI director in the Left 4 Dead games is an example of how developers can
use AI to reach beyond traditional individual NPC behaviour.
Straatman believes the struggle to make NPCs as human as possible is
still very much at the top of the list for many AI programmers, with the future
set to change the way we think about in-game interaction.
"The ideal is always to immerse the player in the game: the NPCs should
123
feel like they are living and breathing creatures, and this illusion should not be
spoiled anywhere. Within the relatively limited interaction you have in a
game, it may be achievable to make the distinction very small. I think human
behaviour is so interesting, and yet subtle interactions such as conversations
are still out of reach of autonomous AI; games rely on clever scripting or
cutscenes to get that across. If we as a field will master these types of
interactions, more parts of the game can be interactive, and possibly whole
new game genres may become feasible."
"I think this will make games more approachable and immersive. If we are
able to maintain the immersion by having realistic behaviour in the interactive
parts of the game, you will get a seamless experience from cutscenes to
combat. I also think we are ready to use AI for more than just individual
NPCs--the director system in Left 4 Dead is one interesting first step in that
direction. We probably will see more combinations of AI systems that before
were limited to one type of game: RTS games will have unit AI that will come
closer to what you now see in first-person shooter games. MMOs could also
start using more elaborate AI, potentially even to command hordes of NPCs. I
hope we will see some brave studios try to create these new systems that are
now becoming possible."
Getting the most out of multiplayer
Alex J. Champandard, the brains behind AiGameDev.com, has his finger in
every game AI pie in town. Following his work as senior AI programmer for
Rockstar Games developing RAGE (Rockstar Advances Game Engine),
Champandard moved on to contract for Guerrilla Games Killzone 2, where he
developed the strategic AI for the multiplayer bots before starting up
AiGameDev.com, the online hub of the game AI community. In-between
running the site, Champandard continues his AI consulting work with studios
like 2K Czech and Crytek, as well as co-organising the aforementioned Paris
Game AI Conference.
Champandard says the last decade has brought a deeper understanding
on the part of game developers about how to best fix age-old AI problems.
"We've realised that just borrowing techniques from traditional artificial
intelligence doesn't work, and it requires a significant know-how to get
something fun and believable out of those algorithms," Champandard says. "A
large part of figuring this out has been to think about the impact on the player
and the in-game results. Thinking about creating NPCs as 'computational
behaviour' instead of 'game AI' sums it up perfectly: it's not about the
intelligence under the hood, it's about what the behaviour turns out like:
adaptive, credible, entertaining."
124
125
F.E.A.R. 2: Project Origin made use of Monolith's goal-based action planner AI,
which helped produce context-sensitive behaviours in the game.
Like Guerrilla, Monolith employs several subsystems for both normal and
combat AI. The common link between the two is the goal-based action
planner, which shipped in F.E.A.R. and F.E.A.R. 2: Project Origin, which helped
produce the context-sensitive behaviours in the games. The first step came
from the teams level designers, who annotated each level with information
that the AI could understand. For example, marking a table as a good spot to
take cover and noting that the table must be flipped over before being used.
After this marking is completed, it is up to the AI to properly interpret the
126
annotations and integrate its own context: when the AI decides to go for cover
and it chooses that table, the annotation tells it to flip it over. These systems
work together to give the AI more knowledge about the world, and give
players the impression that NPCs see their movements and correctly judge
their intentions.
So if the goal of NPCs is to fool players into believing they think and act
just like other players, why does Titelbaum think that striving to make NPCs
correctly copy human behaviour in future AI systems is not a good idea?
Titelbaums answer is to expand the domain to which AI is applied in
games. For example, if AI can stand in for humans playing the game, this
means developers should be able to find ways to allow AI to stand in for
humans making the game.
"A good portion of level designers' time on F.E.A.R. was spent annotating
all the places AI could hide; it's possible, using terrain analysis techniques,
that much of that nitty-gritty work can be automated. Using automation
removes the need to redo hand-done work when there are major changes to
the level layout. The more parts of level creation we can automate, the more
time level designers have to create and polish rich experiences."
127