Truth or reason maintenance systems can be used to handle inferred information about facts and derived facts.
While working on Stilpo, I wrote a simple chat bot. This post takes a look at how it works and how it could be expanded. It’s based on ideas of Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp by Peter Norvig.
Recently I wrote about some simple AI stuff that involved different kinds of search routines. There was breadth first, depth first, best first and a* search. All of them share some common features that allowed me to write just a single routine and then tune it according to specifc search strategy I wanted to use. This blog post will show how that was done. While pretty basic concept, I found it interesting how different kinds of search strategies actually shared quite a bit between each other.
Building an AI (for a game or for some other purpose) which can look ahead, subdivide its goal to smaller goals and plan actions required for completing each of them doesn’t sound too hard. Just use some mechanism to break big goal into smaller steps, maybe starting from the very last on and then working backwards towards current situation and stuff those goals into a stack. AI can then take the topmost item from the stack and start working towards solving it. If it’s not achievable, just figure out what’s needed to be done first, return original item on top of the stack and start working on the new one. If situation changes drastically, say a huge fire breathing monster appears, return the current item on top of the stack and figure out what needs to be done in the short term in order to be able to return back to that task.
I have been pondering over some ideas about traps, items and how to represent what kind of effects they have in-world. I might be over thinking this a bit and going for too general and flexible solution, when simpler solution would work just fine. Currently this isn’t that urgent yet, as there are only few monsters and two types of traps (pits and caltrops). Monsters are too stupid to avoid either one. For caltrops it sort of makes sense, but they really should be able to spot huge pits and go around.
AI routines for enemies in Herculeum are nothing fancy, mostly just random movement until the player happens to wander too close. The plan is to have each monster to behave in a semi-predictable, distinct way (think monster in Super Mario Bros.). First guinea pig for AI experimentation will be rat. The plan is to make them search for closest wall and then walk alongside the wall, randomly turning back when they arrive a corner. If player happens to come too close, the rat will attack. I have not yet decided how will they react on ranged attacks, but probably they are going to flee.
To make things more interesting, I’m going to write AI routines using Hy.
As always, I started with little bit doodling and then writing couple of tests:
(import [pyherc.test.builders [LevelBuilder CharacterBuilder]] [pyherc.ai.rat [next-to-wall?]] [hamcrest [assert-that is- is-not :as is-not- none has-items]]) (defn test-empty-space-is-detected  "test that an empty space is not reported as wall" (let [[character (-> (CharacterBuilder) (.build))] [level (-> (LevelBuilder) (.with-floor-tile :floor) (.with-wall-tile :empty-wall) (.with-empty-wall-tile :empty-wall) (.with-solid-wall-tile :solid-wall) (.with-character character (, 5 9)) (.build))] [wall-info (next-to-wall? character)]] (assert-that wall-info (is- (none))))) (defn test-wall-is-detected  "test that a wall can be detected next to a given point" (let [[character (-> (CharacterBuilder) (.build))] [level (-> (LevelBuilder) (.with-floor-tile :floor) (.with-wall-tile :empty-wall) (.with-empty-wall-tile :empty-wall) (.with-solid-wall-tile :solid-wall) (.with-wall-at (, 4 10)) (.with-wall-at (, 5 10)) (.with-wall-at (, 6 10)) (.with-character character (, 5 9)) (.build))] [wall-info (next-to-wall? character)]] (assert-that wall-info (is-not- (none))) (let [[wall-direction (get wall-info :wall-direction)]] (assert-that wall-direction has-items [:east :west]))))
The threading macro (->) makes it breeze to use all those builders that I have coded in Python. Without it I would have to write very deeply nested function calls. I’m also very happy about how clean and readable Hamcrest verifications are. It’s really hard to get closer to natural language in a standard programming language.