glob2-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[glob2-devel] Full Nicowar behaviour assessment


From: Bradley Arsenault
Subject: [glob2-devel] Full Nicowar behaviour assessment
Date: Sun, 5 Feb 2006 23:58:49 -0800

I know I talk about Nicowar allot, but it has been the root of all
evil for me. Its allot of work, and being an AI, its difficult to
debug. So I need some help. In this email, i'm going to try to state
everything I know about nicowar, and hoepfully recieve some
constructive criticism about it, so I can finish Nicowar and move onto
other things. This description is long and will eventually be merged
with the wiki. If you have the time, please read it over and provide
as much feedback as possible. Don't trust the information in the
headers either, unfortenetly, I haven't been changing them to keep up
with the latest behaviour changes. And when I make reference to things
in AINicowar.h, I'm talking about variables, feel free to examine them
and change them, even if you know no programming, its just a number.

  **Main**
Nicowar is devided up into modules. But there is, of coarse, and
overhead controller, one that serves as a middle man between the ai
interface and my internal modules itnerface. Nicowar runs in
iterations. In each iteration, in runs several turns. Right now a turn
happens every 4 ticks. The "4" is provided at line 1260 AINicowar.h.
You can see Nicowar executing its various iterations on the console,
as in this long game, where it got up to " AINicowar: getOrder:
******Entering iteration 2400 at tick #249544. ****** " without
winning or losing. Each turn, it does two things. Firstly, it updates
one of the gradients. This is done in a systematic fashion, one
gradient at a time. Secondly, it calls upon one of the modules to do
something. This is also  systematically, one module after another, one
action at a time. This interface is provided at line 443 AINicowar.h.
Thus, an iteration is composed of calling every module to do all of
its actions at least once. When the overhead controller is
initialized, it precreates all of the modules that are going to be
run, however, in the future, it will be runtime dependant, as the
module system was originally designed to be flexible in this manner.

  **Defense**
Defense was a tricky thing and most say Nicowar still doesn't defend
overly well. The defense module records all of the hit points of all
the various buidlings within a teams control. If any of these
hitpoints goes down from one turn to the next, it means that the
building is under attack, in which point it creates a defense flag.
The defense flags size is reletive to the size of the building its
trying to defend plus an amount of padding at the top and bottom,
given at line 1304 AINicowar.h. It assigns an equal number of warriors
to the flag as the number that are within the area around the building
(bassically the enemes within the flag) up to a maximum of 20. It
orders a fixed number of warriors to be made just for defense, given
at line 1305 AINicowar.h. It records all of this information
internally. The next turn comes around, it looks for the flag it
created. This is because the building isn't created the exact
millisecond the order was created, the building is instead created
when the order is proccessed, which is generally 1-2 ticks later. It
tries to find defense flags that "match the criteria" for what it
requested to be built, which is essentiall just the x and y position.
If it finds what its looking for, it assocciates that flag with its
record, and moves on. On the defense engines third turn, it looks at
existing flags that have been recorded properly (ie onesthat where
correctly found by step 2), and simply updates the number of units
assigned to them in accordance to how many units are in the flags
zone, which often changes during an attack.

  **Attack**
Attack was tricky for me, although I spent lots of time on it, so it
works quite well. Nicowar targets only one person at a time, and
attacks them untill they die. It chooses who to attack at random. Then
the attacking turn comes around. This turn is most interesting, and
there has been allot of bugs contained within its function. Firstly,
it computes the highest barracks level it has available, then it
computes the average unit strength level of its warriors. It will use
one of the numbers to decide what level of warriors to attack with.
Which one is given at line 1348 AINicowar.h. Then it decides how many
warriors it wants to have constructed, and sends that information to
the unit module. It does so in an interesting fashion, because I
wanted to keep the attack module from taking up all the production
time of workers. First of all, its always ordering the construction of
atleast 30 new workers (line 1341), but it also does so in "chunks".
Meaning it will order the production of 35 units, and let that dwindle
to 30 units, and jump right back up to 35. (line 1343). The low chunk
number doesn't have a major effect, but with a higher number, it
causes the ai to build its armies in one big mass. Meaning build up to
30 units, then up to 60, then up to 90, etc, instead of having a
continous flow of production.

It then goes through its enemies buildings, sorting them based on
their type, and randomly shuffles them. It goes through the buildings
in a fixed order, it will destroy or attack all of one building type
before it goes onto the next (line 1308). Naturally, it will spend
most of its time attacking the first two types of buildings on the
list, but its important to provide order to the rest to help the ai
finish off the enemy. It doesn't create a new flag on a building thats
already being attacked, and will quit the algorithm if it doesn't have
enough units to attack with, regardless of what building its
attacking. If all condiditions are right, it creates a new flag in the
center of the enemies building, and assigns units proportional to the
number of units in the flags zone, with a fixed minimum (line 1330).
It examins an area much larger than the flag zone itself, however,
(lines 1328-1329). On the next turn, it will look to see if the falgs
that it has previoussly created have been created, and if so, add
their gids to the records. It will also go through found flags and
reassign them depending on the new number of units in the defending
zone, and will update the update the level of units assigned to the
flags if the numbers have changed.

  **Construction**
Construction is not complex, but it has taken me allot of effort to
master and is still a major area that controls how well Nicowar
performs overall. The first turn is the main. At the very start of the
turn, it updates the imap. The imap is what a set of integers, more or
less just 0's or 1's but has space to be advanced upon later. It
represents a grid, one that specifies where the ai can construct
buildings. Its fairly simple. Any point that can't normally
constructed on (such as one with water or ressources) is set as 1. If
the point happens to be a building, it puts 1's on every point the
building takes up, as well as an area of padding (line 1351), so the
ai won't construct buildings too close together. Its also important to
note that the ai always takes into account the space needed to upgrade
a building, so it doesn't just put 1's on every space the building
takes up + padding, it sets 1's for every space the building *could*
take up + padding.

Just a note, several of the following reference lists of numbers, each
applies to a particular building, but unfortenetly, the header doesn't
say "MAX_INN=5" and "MAX_HOSPITAL=3", its all shoved into one list.
The order of the list goes: swarm, inn, hospital, race track, swimming
pool, barracks, school, tower, exploration flag, war flag, clearing
flag, stone wall, and lastly, market (IntBuildingType.h). It wasn't my
decision.

Next, the algorithm builds up a variety of statistical information,
where it leads into deciding in what order it should construct
buildings. It does this by looking at how many buildings it currently
possesses, and comparing that to the number of buildings it "wants".
It applies both weak and strict ordering to help it order what
buildings it should do. Weak ordering (line 1386) simply multiplies
the percentage of buildings to desired with the given number. Strict
ordering (line 1389) garuntees that certain buildings will always be
constructed before others. It then goes into the loop constructing
buildings. It always constructs all of one building untill one of the
flags stops it, where it then goes onto the next. Theres 5 failures
that will stop the ai from constructing a building. The first one is
if there is too much overall construction (line 1374). The second one
is if it doesn't have enough units provided to it by the unit manager
module, this is the most common reason for not constructing a
building. Third thing is if there is too much construction of that
particular building type (line 1375). Fourth thing is if the ai
already has enough buildings of that type. It may surprise you that
this happens at most once in an entire game. It will almost always
have a desire for more buildings. Will disucss in a moment how it
decides how many buildings it wants. At this point, it looks for a
place to put the building. Again, we'll discuss this in a moment. But,
the last failure is if there is no place to put the building anywhere.
By the way, allot of this information comes out in live updates in the
file "NicowarStatus.txt".

How it decides to place a building is fairly simple, and farily
inefficient. It considers every point on the map. It looks up in
gradients (lines 1358 - 1370) about that point. What gradients it uses
depends on the building. The gradients provide basic "distance to
nearest" information. It looks for the point with the lowest average
score on all its gradients, applying some weights to particular
gradients, that the imap says is capable of being built in. For
example, for inns (line 1360) it looks at the distance to the nearest
pieces of wheat, and the distance to the nearest buildings, desiring
wheat twice as much as other buildings. So it naturally puts inns near
wheat, but it other buildings certainly plays a factor in its
construction, which can keep it from placing inns all over the map.
How it decides how many buildings to build is also fairly simple, it
takes the total number of units, and for every n units (line 1380), it
asks for another building. It may seem somewhat demanding to have one
barracks for every 20 units, but it seems to work for me.

The rest of the algorithm should be fairly predictable, but if not,
I'll explain it. After it constructs a building, the next turn it
"waits" for it to appear on the map, and once it finds it, it records
its gid, and assigns a particular number of units to it. It always
assigns a minimum of 4 units (line 1377), with the exception of
buildings that need less then that, such as inns, which need only 3
wood, so it assigns only 3 units. But it tries to assign as many units
as it has available, up to 8 (line 1378), and it removes buildings
that have finished construction from the records.

  **Upgrading and repairing**
This was my first module. My first behaviours. And frankly, the code
has changed very little since. When I first made it, I got it right,
for once. I had spent plenty of time working on the upgrading system
when i first started nicowar. Since then, some of its behaviours have
more or less become useless because the surrounding enviroment has
changed, although I do know that its original behaviours where best.

I don't have the time to explain everything else tonight, expect the
completion of htis email in around 10-12 hours when i've slept.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]