Making the A.I. fortify bottlenecks - part 2
Tuesday, July 29th, 2008The A.I. work on placing towers at natural bottlenecks in the terrain is coming along pretty well. I implemented a quick, “dumb” algorithm to try it out. Its effect on gameplay is pretty favorable - that is, when the “dumb” algorithm works. Which is not very often.
I’ve been thinking about this problem some more. Finding ideal defensive bottlenecks, at which to build fortifications, is pretty hard to do.
I shouldn’t be surprised; now that I think about it, not a single RTS game I’ve ever played has had A.I. that did this very well. Maybe there are some out there, but I haven’t played them. Usually, the A.I. would just build a huge rectangular wall around each base. In those cases, the A.I. obviously wasn’t analyzing the terrain for optimal defense locations at all. Case in point: remember Age of Empires 2? Yes…then you know what I’m talking about :)
I want Orcs vs. Martians to do better than that.
Technicals
Ok, so here’s an update to my algorithmic approach.
To simplify the implementation, I’ve thrown away that first step I mentioned about finding terrain bottlenecks for the entire world. I think I can still find very-nearly-optimal bottlenecks around a particular base without it (and the resulting alg will likely be faster, too).
Next, the frontier-walk, the one that starts from the base to be defended, needs to be made smarter.
My current thinking is that the frontier-walk needs to keep track of individual sub-frontiers, within the main frontier. I see this as being absolutely key to solving this problem. Each sub-frontier represents a “passage”, or an “entrance”, to the base. Initially, as you walk away from the base, there’s just the single frontier. But as the frontier collides with cliff walls, water, or other un-walkable tiles, it splits into these sub-frontiers, which then “walk” down the passages independently.
The sub-frontiers are necessary, because you need to analyze separately each passage that leaves the base. Why? Because many of those so-called “passages” will dead-end! Those passage don’t need to be defended, and shouldn’t count towards the “cost” of the frontier. Defending them would waste resources (and look dumb in the game), and counting their cost could make the algorithm pick a sub-ideal frontier.
After walking the passages, and finding each passage’s narrowest point, then roughly speaking, you’ve got the solution. The ideal defensive frontier is: the collection of narrowest gaps, on each passage that leaves the initial base.
…of course, it’s actually a little more complicated than that. Passages will often re-combine with each other, as they lead away from the base. So, as the passages branch out from the base, they don’t form a simple tree structure. They really form a directed acyclic graph (DAG).
The output of walking the passages will be this DAG. Each node in the DAG represents a sub-passage, and each sub-passage has its own narrowest gap.
And to really find the ideal defensive frontier, the DAG needs to be depth-traversed and analyzed, rather than just examining the immediate passages that leave the base. That’s because the ideal frontier may be further down the passages, after the passages branch and merge several times.
And, the “ideal” frontier is not only about narrowest gaps. If the A.I. is playing to win, it also wants to control as much territory as possible. So you’re also trying to maximize the amount of land area, that lies behind the defensive frontier.
So roughly speaking, in Orcs vs. Martians’s case, the merit of any particular defensive frontier is:
- decreased by size of the frontier (i.e. its length)
- increased by the land area behind the frontier
- decreased by the average distance to the frontier (because workers have to travel to/from the frontier, to build/repair towers)
The exact formula for which, I’m still working out.
- - - - -
If I implement all of the above, Orcs vs. Martians will have some fantastic tower-building, defensive A.I.!
Implementation challenges:
- what exactly constitutes a “passage”? If there’s a single unwalkable tile in the middle of a passage, does that briefly split the passage into two passages?
- how to detect when a frontiers splits, fast?
- how to detect when sub-frontiers merge back together, fast?
All of this has to run in near-real-time.











