As some of you may already know, last weekend and in my off time this week, I've been working on the beginnings of Mythruna's AI system. This is tapping into knowledge that I haven't used heavily since the 1990s when I did some expert system work.
The general idea is that you define a bunch of operations/actions that an AI can perform. Each of these has a set of conditions that must be met before it can be run and a set of effects that happen when it is performed. So, for example, an "eat" action might require that the NPC be holding food first and the effect is that the NPC's hunger level changes.
From these simple actions and their pre-conditions and effects, the real meat of the AI can work: the planner. The planner is responsible for chaining effects and preconditions together to achieve some goal. The hows and whats of this are probably too low level to get into here but suffice it to say that it tries to find the shortest plan of actions to meet some goal.
An example shows how this might work. Let's say you have the "eat" action is described above. To this we will add an "equip" action that removes an item from inventory and holds it. For brevity's sake, we will also add a "buy" action that buys an item from a NPC merchant (way oversimplified) and a "move to" action that walks to some target.
A goal for the NPC might be "reduce my hunger level". The planner scans through the available actions and finds the "eat" action that will satisfy that goal. But in order for the "eat" action to run, the NPC needs to be holding food. Both "equip" and "buy" can make the NPC hold food. "equip" requires food in inventory and maybe the NPC has none. "buy" requires that the the NPC be next to a merchant. Since neither "buy" nor "equip" resolved on their own the planner will try another step and sees that the "move to" action can move the player to a merchant. The planner has found the best plan and then it's just a matter of executing those steps.
The nice thing about a system like this is that actions are relatively easy to create. In many of the above examples they are just shifting resources around... pretty straight forward stuff. You can also give actions a "cost" which might lead the NPC to pick one over another, all things being equal. So in the above example, maybe there is food laying on the table already and the "buy" action has a higher cost than the "pick up" action. But I digress...
The real clever works is done in the planner and a particular NPC may have a different set of available actions and costs than another and that's what will make it really interesting.
Anyway, in order to test the planner, I've been using a really simply artificial scenario. There are some stacks of lettered blocks (A, B, C, etc.) in a certain starting configuration. The actions are "stack" and "unstack"... basically, put a block down or pick a block up. I enter a goal of the way I'd like the blocks stacked and the planner tries to find a way to do that.
So if I had something like:
And wanted to get to:
Then the planner will figure out:
-unstack C
-stack C on B
-unstack A
-stack A on C
...and a variety of other starting and ending conditions will find the appropriate sequence of events.
The interesting part is that I'm watching the different things that the AI tried to do and failed... and it's already hacking this simple setup.
Since this is not a real game or even real code, I've left the "world state" simple. We see a nice picture above but the computer sees that starting state as "C on A", "A on ground", "B on ground" basically.
What the AI planner figured out is that there is nothing preventing it from stacking "C on C" to move it out of the way. Those paths never resolve because it can never pick up C again... at least they never resolve because I always included "C" in my goal.
Still, I find it interesting how close an eye I will have to keep on how the world is represented and managed... not just because players will exploit it but because my AI certainly will.