The actual AI is not finished. Only, about ninety percent or more of the support infrastructure. I have just started to work on the actual code for the AI.
One of the more interesting abilities which makes it different from other AI is that it executes on separate thread from game engine. When I first started I had no reason to use a separate thread since the normal processing done, as with other AIs, is hardly worth moving it into a separate thread. What happened was that as I was working with some path finding algorithms and some normal enumeration of data from the game I noticed that my load time was getting rather long. This created a noticeable pause before the game started. To keep from using threads I implemented a cache for this data, but this did not solve the first time loading. Also, my goal is to write as much as possible in Lua to make it easy for people to experiment and fix problems. Since Lua can be edited with any text editor and requires no compilation this makes it perfect. The down side is that it is magnitudes slower in some areas. So my only option left was to move the code in C which I did not and still will not due, unless I always have a equivalent function in Lua that someone can switch too.
So, I decided to try using co-routines in Lua. These worked very nicely except now I had the headache of having to maintain all these yield commands in just the right places and then end up with later on scaling problems where a slow machine might notice the points between the yields more. In Lua a co-routine is cooperative multi-tasking. Each thread yields it's execution. This caused me to put some time and effort in creating a separate AI thread that could run Lua and use co-routines for multiple AI, but not block the main game engine thread. Oh, and I disliked the co-routine approach too because the more yields you inserted to smooth out the heavy loading computations the more overhead and the less efficient everything became.
My results so far as very good. I use ring buffers for communication between the AI thread and the game engine thread. A implementation of asynchronous callbacks is implemented, and also (which I use in my code at some points) the equivalent synchronous calls. I do not plan at the moment to support a individual thread for each instance of my AI -- although in the future this would be nice to simply match the number of cores (maybe minus one) on someone's machine -- if the processing need even existed but it requires some additional work for data shared between Lua instances. Plenty of tricks to do it with out lots of overhead.
The code is written for win32 systems. I will have to take some time to add in the ability for it to compile on unix machines, but this is only a minor annoyance at the moment. The problem is the thread creation and synchronization calls being win32 specific. I tried to keep everything so that it would compile in plain C, although I might have accidentally slipped in a C++ keyword somewhere which needs removal.
At the moment it just loads. Drives the AI commander to the 0,0 position on the map and handles most of the events including tracking units on the fields and their properties for their definition and current real time properties like health and such.
I thought it was to a point that other people might find it useful or helpful in the event that they were planning to do something similar and wanted some insight into how someone else did it. You know since my AI is not actually playable.
Oh, and just in case someone missed it. The only reason I made a separate thread was not because the AI needed the extra computation power on a multi-core system -- but it was to keep the game running smooth no matter how deep the AI got into thinking about it's next move or generating any type of data structure to make the game more challenging. <-- This makes it a lot easy on me which is important in the sum of things.
If you are wondering about my actual AI. This is a overview and you can find a bare minimum of the code for it implemented.
Code: Select all
Overlord
1- handling contracts to build certain units
2- manages the contracts for building structures and units that collect resources
3- manages the accept/deny of contracts to build units and structures from
the scout, defense, and offense masters
4- manages goals which entail contracts with defense, offense, and scout master
ScoutMaster
1- manages groups(singe/multi) of units
2- determines need to build radar towers
3- determines need to build radar jammers
4- keeps track of targets (by scouting or radar)
5- determines enemy movement destinations, ect.
6- requests building of units and structures to the overlord
BuildMaster
1- manages groups(single/multi) of construction units
2- builds structures and units
3- manages the building queue and balances with resource needs
4- tells overlord about resource needs
5- tracks unmanaged units
DefenseMaster
1- requests structures to the overlord (not units -- OffensiveMaster does this)
2- requests guard or patrol contracts from the offensive master
OffenseMaster
1- manages groups(single/multi) of offensive units
2- manages contracts for attacking and guarding
3- requests units (not structures) from the overlord
4- manages need for bigger, specialized, ect units by talking to the scout master
You will not find any of that code implemented, but it will not take much code to do it. It is all mostly abstract thinking.