Author Topic: working with AI library of sorts  (Read 9697 times)

tuturto

  • Rogueliker
  • ***
  • Posts: 259
  • Karma: +0/-0
    • View Profile
    • pyherc
working with AI library of sorts
« on: March 22, 2016, 08:37:06 AM »
I have been tinkering with a rewrite of my messy AI routines and got the first one done. It's super simple, just a rat that selects a room, travels there and then patrols along the walls. If enemy comes close, it switches to combat mode and starts fighting. After enemy either dies or runs away, the rat returns patrolling the room. It's a rough draft still, for example any creature with different name is considered as an enemy (so player can see rats and beetles fighting with each other). Current code is at: https://github.com/tuturto/pyherc/blob/master/src/herculeum/ai/rat.hy and https://github.com/tuturto/pyherc/blob/master/src/herculeum/ai/firebeetle.hy

Most likely it doesn't make sense to publish this as a real standalone library, but I'm still trying to have it be mostly nicely contained within the codebase of the game. There are actual finite state machines for AIs that are generally per monster and then underlying set of functions that implement specific behaviour. Combining the functions and a bit of logic in state machines is how I envision the library working in the end.

A bit further down the road I would like to add more complex things, like scavenging level for gear and selecting what items to use or deciding when it makes sense to take a short cut over a trap instead of going around. Maybe even throw in a bit of fuzzy logic, so I can raise level of abstraction from solid numbers to ranges of things.

But this is where I'm drawing a blank. What else should there be that would create interesting creatures and situations? I like having monsters that player can lure to fight with each other for example. And maybe a group of creatures that move together as a loose band. But what else would be interesting? What are memorable creatures from other creatures, mainly because how they functioned?
Everyone you will ever meet knows something you don't.
 - Bill Nye

akeley

  • Rogueliker
  • ***
  • Posts: 348
  • Karma: +0/-0
    • View Profile
Re: working with AI library of sorts
« Reply #1 on: March 22, 2016, 09:14:39 PM »
AI and - connected to it - emergent gameplay are two of my Holy Grails that I always look forward to in games, sadly quite often ignored. I guess these being complex issues is one of the reasons, though it`d be nice to see more people trying at least.

My favourite RLs - Linley`s Crawl, Brogue, Sil, Qud all have rather interesting monsters/behaviors. Some examples & ideas:

- different movement patterns: ye ole bat is the most obvious with it`s erratic, infuriating schemes, then frogs can jump and advance rapidly, bulls could charge blindly, centaurs and such are fast, nagas slow.

- depending on intelligence and type: different responses to the environs; avoiding traps as you said already, but also natural obstacles like water, pits etc. That charging bull would plunge into one, I suppose.

- depending on intelligence and type (2): different equipment and use of collectables: you mention it already. Crawl`s strong suit...it really makes the world more believable instead of countless monsters which differ only in name and HP count.

- trying to lure player into ambushes and traps - Sil excels here with its group tactics, retreats and suchlike

- tracking the player: there really should be more to this, in so many RLs having a stronger foe next to you means curtains no matter how far you run. But monster could run out of stamina or trip over. And so could the @. Also, scent and tracking in general: some monsters should be better and some worse at this, doors and environments again should aid or hinder the escapee (old trick with jumping into a stream? or throwing out loot for the greedy kobolds or meat at trolls/hounds).

-different reactions to @s presence depending on varying circumstances - maybe monsters don`t always feel like attacking?  Could be alignment, player`s strength or rat`s allergy to leather. Expanding: intelligent monsters could ally with the player or let him off for a "fee"

-there could be other adventurers in the dungeon with agendas of their own, again these could aid or hinder - or just ignore - the player.

In case you missed it, great post regarding AI in general from Dr URR: http://www.ultimaratioregum.co.uk/game/2016/03/13/alphago-lee-sedol-and-grand-ai-challenges/


tuturto

  • Rogueliker
  • ***
  • Posts: 259
  • Karma: +0/-0
    • View Profile
    • pyherc
Re: working with AI library of sorts
« Reply #2 on: March 23, 2016, 11:35:47 AM »
I'm huge fan of having different monsters that differ in other ways than just stats. It doesn't even have to be that different before interesting things start popping up. Like the aforementioned rats and beetles. They have almost identical AI, except rat likes to live by the walls and beetles away from walls. When there are couple of both in a big room, rats will patrol around the walls, while beetles take care of rest of the room. Player can still try and sneak past them, but it's a lot harder. Movement patterns are probably one of the easiest ways to differentiate monsters. It's readily available for player observation and is easy to follow over time.

Natural obstacles could be fun, as ones obstacle is others' home. Bats could live inside deep pits and emerge when somebody disturbs them and eels could lurk under water. Currently none of my creatures really understand what pits mean for them, so they just try to walk over them and die in process. I have been playing with an idea that AI could reason about things like that to a degree: it would understand that walking over pit means it doesn't have support from below and thus would fall down and hurt itself. But if it can fly (by natural or unnatural means), pits aren't problem at all. But that probably is too resource intensive to be run for each and every character, at least for each and every step. Maybe a two level approach would work, where more resource intensive part of the routine is ran less often and less intensive more often. Less often run routine could be in charge of selecting high level goals and making broad decisions (like deciding to cross trap by going through it) and lower level system would be in charge of more simpler tasks (finding path and such).

Tracking by scent doesn't sound too complicated to write. I'm not sure how granular the simulation should be, ie. would all horses smell same or could bloodhound track a specific one? From realistic point of view, one could tell the scent apart, but what would make most sense from the gameplay point of view? Would be funny if characters could use oils to mask their scent or even impersonate other creatures. Tracking by memory sounds a bit more complicated, as creatures would have to remember where they last saw the foe, walk there and start looking until eventually giving up.

Lots of good and interesting ideas. Probably just have to slowly chip away the easiest ones first and then what kinds of tools that will give to me and then build more complex cases on top of the more simpler ones.
Everyone you will ever meet knows something you don't.
 - Bill Nye

wire_hall_medic

  • Rogueliker
  • ***
  • Posts: 160
  • Karma: +0/-0
    • View Profile
Re: working with AI library of sorts
« Reply #3 on: March 24, 2016, 05:07:31 PM »
I've been playing around with different AIs in my current project, Professional Adventurers' League.
To start with, actors are classified as either smart or dumb.  Smart actors use A* pathfinding and avoid dangerous terrain, while dumb ones check to see if the most direct step toward the nearest enemy is possible, then the two adjacent steps; if none of those, they stand still.  Dumb actors blindly charge through dangerous terrain.  Some enemies can use doors, some can't.

I keep too different 2D boolean arrays for pathfinding; one for walkers and one for flyers.  That way I don't have to recalculate anything and the actor just grabs the appropriate map.  The only exception to this is for enemies who burrow; they grab a copy of the appropriate map, then mark all nearby diggable cells as passable.  This stays reasonably efficient, as there there are never many burrowing enemies.

Some of my ranged actors will prioritize staying at range over attacking an enemy; one particularly family of actors uses Dijkstra maps to flee around the player when cornered, while the others just back directly away and switch to attacking if cornered.

Ghouls will move near, but not adjacent to, an enemy.  They will attack the enemy if it moves adjacent to them (they don't run), they are hasted (they can self-buff by eating a corpse), or there is an ally adjacent to the enemy.

Revenants will prioritize moving to a corpse so they can possess it, and if one is not available and they don't have a host will flee from the enemy.

tuturto

  • Rogueliker
  • ***
  • Posts: 259
  • Karma: +0/-0
    • View Profile
    • pyherc
Re: working with AI library of sorts
« Reply #4 on: March 29, 2016, 04:28:27 AM »
I've been playing around with different AIs in my current project, Professional Adventurers' League.
To start with, actors are classified as either smart or dumb.  Smart actors use A* pathfinding and avoid dangerous terrain, while dumb ones check to see if the most direct step toward the nearest enemy is possible, then the two adjacent steps; if none of those, they stand still.  Dumb actors blindly charge through dangerous terrain.  Some enemies can use doors, some can't.

I keep too different 2D boolean arrays for pathfinding; one for walkers and one for flyers.  That way I don't have to recalculate anything and the actor just grabs the appropriate map.  The only exception to this is for enemies who burrow; they grab a copy of the appropriate map, then mark all nearby diggable cells as passable.  This stays reasonably efficient, as there there are never many burrowing enemies.

Some of my ranged actors will prioritize staying at range over attacking an enemy; one particularly family of actors uses Dijkstra maps to flee around the player when cornered, while the others just back directly away and switch to attacking if cornered.

Ghouls will move near, but not adjacent to, an enemy.  They will attack the enemy if it moves adjacent to them (they don't run), they are hasted (they can self-buff by eating a corpse), or there is an ally adjacent to the enemy.

Revenants will prioritize moving to a corpse so they can possess it, and if one is not available and they don't have a host will flee from the enemy.

This sounds neat, especially how ghouls kite the player into attackking them. What will they do if player has ranged weapon and never come next to them?

I really like the sound of the game as enemies seem to be varied and have different behaviours. Fleeing is something that I have been considering, but haven't gotten around implementing. How did you implement dijkstra maps for fleeing? Fill with player at tile 0 and have monster move to downhill on the map?
Everyone you will ever meet knows something you don't.
 - Bill Nye

tuturto

  • Rogueliker
  • ***
  • Posts: 259
  • Karma: +0/-0
    • View Profile
    • pyherc
Re: working with AI library of sorts
« Reply #5 on: April 06, 2016, 06:41:39 AM »
I tinkered with some miniKanren code and wrote a blog post about it too (https://engineersjourney.wordpress.com/2016/04/06/wishful-coding-adderall-traps-and-items/). What's not shown is a small function that when given characters inventory and trap they want to cross, will find out all the items that could be helpful:

Code: [Select]
(defn helpful-items [inventory trap]
  (run* [q]
        (fresh [item trigger mode]
               (memberᵒ item inventory)
               (triggerᵒ trap trigger)
               (safe-modeᵒ trigger mode)
               (effectᵒ item mode)
               (nameᵒ item q))))

Essentially, the code is saying that there are three logic variables: item, trigger (what triggers the trap) and mode (what movement mode should be safe). Then it goes about to declare relations between them and passed parameters inventory and trap: item is member of inventory, trigger is triggering effect of trap, trigger and mode has safe-mode relation (mode will be what doesn't cause specific trigger to work), mode also will be an effect in item (flying, teleporting, etc.) and finally q (the return value of logic program) will be name of item.

The progress has been slow (got sidetracked with other things), but I have a hunch that this might be an interesting approach. Drop memberᵒ goal and unify item with q and suddenly program will start producing item descriptions that help you to crossing the trap. I can see feeding this description to item generator when level is being generated, so the level is guaranteed to have item(s) for getting past some specific trap.

And to make sure that AI is up to date with rules and vice versa. I would be checking if moving through a trap using certain movement mode triggers is, by using same goals:

Code: [Select]
(defn triggers? [trap mode]
  (not (in #U0
          (run 1 [q]
                 (fresh [trigger]
                        (triggerᵒ trap trigger)
                        (safe-modeᵒ trigger mode))))))

Here I'm stating that trigger is what-ever causes the trap to sprung and there is safe-mode relation between that trigger and current movement mode. If program finds any answers, the trap doesn't trigger, so as a final flourish, I'm taking a negation of the result.

So slow progress and dumb ai still, but I'm having fun tinkering with these ideas and seeing what I can cobble together.
Everyone you will ever meet knows something you don't.
 - Bill Nye