SourceFiles.org - Use the Source, Luke
Home | Register | News | Forums | Guide | MyLinks | Bookmark

Sponsored Links

Latest News
  General News
  Reviews
  Press Releases
  Software
  Hardware
  Security
  Tutorials
  Off Topic


Back to files

The nazbot agent is an extension to the open-source nazghul game engine. The extension provides an API for writing an agent to control the "player".

***

Getting and starting the agent:

0. First, you need to install the SDL and SDL_image libraries available from

libsdl.org (I believe they're already installed on onyx) 1. Get the source from http://myweb.cableone.net/gmcnutt/nazbot-0.1.3.tar.gz 2. Once downloaded, then under linux or cygwin:

$ tar -xzf nazbot-0.3.0.tar.gz
$ cd nazbot-0.3.0
$ ./configure --prefix=$HOME
$ make
$ make install

!!! Note: the --prefix option to configure should refer to your home

       directory. If you don't use this option then the make install step will
       require you to be root.

3. To run the agent:

$ cd worlds/haxima-1.001
$ nazghul --bot map-1.scm

Besides map-1.scm, there is also map-2.scm and map-3.scm. Each map illustrates a different quest and a different situation to challenge an agent.

Some other tips:

  1. You can download the windows binary at http://myweb.cableone.net/gmcnutt/nazbot-win32.tar.gz. Untar it the same, but you don't need to build it. Just open a command window, cd to the directory, and run the game as:

    DOS> nazghul --bot map-1.scm

  2. You can invoke the game without the --bot option to play it as a human. To toggle between agent mode and human mode use the semicolon (;) key.
  3. There is a User's Guide at http://myweb.cableone.net/gmcnutt/USERS_GUIDE.TXT which has more instructions on how to play the game, which will be important to understand the agent API. The ORIENTATION section of the manual assumes you use the haxima.scm file instead of atf.scm as the startup world.
  4. For agent development you will only have one place (or map, or level) to work in, so you don't have to worry about portals or map edges leading to other places.
  5. Also, you will only have one character in your "party", so your agent will only control one actor.

***

Writing an agent

The interface used between the agent and the kernel is specified in src/agent.h. I've tried to comment it extensively. When you write an agent, you should not need to include any other nazghul header file. In fact, I encourage you not to.

agent.h specifies both the interface which your agent presents to the nazghul kernel as well as the interface which your agent uses to access the kernel.

In a file called src/beowulf.c you will find a sample implementation of an agent. It isn't meant to be a good agent, instead it's meant to provide examples of how to use the functions outlined in agent.h. Hopefully its pitiful performance will inspire you to prove that you can write one better than a professional programmer. That's my excuse anyway.

In particular, I do not want you to use a function called actor_get_path(). It's there, like the Tree in the Garden to tempt you, but do not use it. This function promises to do your pathfinding for you. And it will. But it cheats, and furthermore will punish you in hidden ways. Feel free to look at the underlying implementation in astar.c, and you may even use astar.c if you like, but avoid actor_get_path().

To write your own agent the simplest thing to do is gut beowulf.c down to some stubs which implement the agent interface and start filling them in. If you just want to start with beowulf.c and change it knock yourself out, but get rid of the calls to actor_get_path().

beowulf.c is not that well documented. Tough. You need to get used to reading code. Being able to read other people's grotty code is an important part of being a pro.

BTW, I will encourage Dr Andersen to award an unspecified amount of extra credit to anyone who can guess why the file is named beowulf.c. I personally will buy a coke for the first person who can tell me what the literal meaning of "beowulf" is. This is a really easy question, and Google probably makes it easier, so I should be losing 60 cents here pretty quick.

The smart ones will be able to see pretty quickly that the present architecture only permits one agent at a time, and it must control the player. However, if you are confident of your scheme programming skills you may try to write an NPC agent. See examples in worlds/haxima-1.001/spider.scm, troll.scm and ai.scm. The API provided to these agents is in kern.c and it allows them to cheat like clairvoyants at a casino. Eternal fame awaits anyone who can present me with a new monster AI written along these lines. Surely someone can do better than what I have done.

The session will end when your agent dies or calls agent_quit(). Upon exit the program returns the agent's score. So, for example, in UNIX you can retrieve this via:

     $ nazghul --bot map-1.scm
     $ echo $?

***

Agent-writing FAQ

Q: If the goal of a map is to escape the dungeon, how do I find the exit? A: As a human player the exit is marked with a ladder. As an agent use the

loc_is_exit() call to test locations.

Q: How can my agent tell if a terrain is a door? A: Technically, doors aren't terrain. They're mechanisms. And, in the agent

maps, it just so happens that doors are called "doors". So, this generally works to tell you if a door is at a location:

OBJ mech = loc_mechanism(loc);
if (mech && ! strcmp(obj_name(mech), "door"))

/* yep, it's a door */;
else

/* probably not a door */;

I say "probably not" because if somebody ever adds a new type of door and decides to name it "steel orifice" then the above check will incorrectly decide that a steel orifice is not a door.

A more robust but more challenging way is for the agent to "learn" what constitutes a door. An agent can discover this by experimenting. I mean, what really is a door? A door is a mechanism that, when handled, makes its location passable to the agent.

Q: How can my agent tell if a terrain is a wall? A: Unlike a door, a wall really is terrain. You can try the name hack:

TERRAIN t = loc_terrain(loc);
if (t && ! strcmp(terrain_name(t), "wall"))

/* yep, it's a wall */;

But again, what if the wall is named "rock wall" or "log palisade"? And again, it doesn't really matter what it's name is - a wall is impassable, opaque terrain. Your agent can learn the names of wall terrains by experimenting.

Q: When I look at the map that is dumped after the agent can no longer find a

path. Some of the places that are out of line of sight are showing up as unaccessible rather than unexplored. A: First of all, you're using agent_find_path() instead of writing your own

pathfinding. I know it's tempting but IT CHEATS. What you are seeing here is an example of that. The locations are out of line-of-sight, but the CHEATING PATHFINDING CODE looks at them anyway.

Q: I noticed in the source a function called is_valid_location()... can I use

this?
A: Knock yourself out but it's pretty useless on the agent maps. The function

is used on the big, wrapping world-level maps used in the main game. Agent maps never wrap, so you can tell if a location is off-map by checking its (x, y) coords as compared to the current map's width and height.

Q: Why aren't the hit points of the agent shown on the main screen? A: They are. In the upper right hand window near the top line you see your

agent's name, Hiro Protagonist (credit Neal Stephenson with the pun, viz. Snow Crash)? Right next to it you see a number and a "G" as in 30G? That number "30" is your agent's hit points. The "G" doesn't mean "gold" (that's the next window down), it means "good", as in not poisoned (P), not dead (D), not sleeping (S) and nor paralyzed (Z). Sorry for the obscure UI but remember this is based on a twenty year-old game and I kind of like the honest crankiness of the interface.

Q: How can I tell how much damage weapons do? A: As a player, you have to experiment. But your agent can use the

armament_average_damage() function to get a hint.

Q: Can my agent cast spells?
A: Alas no, not generally. You can mix spells that produce potions and use

them, but most spells require interactive targeting with the user and there's no solution to that yet in the agent extension.

Q: I make changes to the source and rebuild, but they don't seem to take

affect!
A: Be sure and do a "make install" so that the new binary is posted to your

$HOME/bin directory.

***

Making maps.

Making maps is so much fun I really should charge you money for it. The simplest way to explain it is with a question-and-answer session. I'll take your questions now. Let's start with you there, in the glasses.

Q: Uh, how do I make a map?
A: See the examples files: map-1.scm, map-2.scm, etc.

Q: Ok. But what do they do?
A: They each call four scheme functions. First, they call (load "atf.scm") to

load a bunch of definitions. Then they call (mk-map ...) to make a map and populate it with terrain and stuff (this is most of the file). Then they call one of the three set-goal functions to give the agent a goal. Then they call start-at to tell the game where to start the agent.

Q: Do I have to call (load "atf.scm")?
A: Yes, and you must call it first thing.

Q: What's all that funny "rr rr rr ..." stuff in mk-map? A: That's the terrain map. Note that the first argument to mk-map is the result

of calling (list ...) with a bunch of strings. Each string represents a row of terrain. Each two-character word in the string represents a single tile of terrain. You can edit maps in a text editor. There is another way to do it in-game, but it involves some extra steps to retrieve the results. Let me know if you want to learn how to do it. Sometimes I just use Gimp to pixel-edit a map then save it as an xpm and use search-and-replace to convert it. Sorry, the tools suck, noted for future refinement.

Q: Does my map have to be 32x32?
A: Yes. Unless you are feeling adventerous and care to peek under the covers at what mk-map actually does. You can find it in atf.scm.

Q: How do I know what the terrain codes like "rr" mean? A: You can find them in terrain_palette.scm, which maps these codes to terrain

types. "rr" maps to rock wall.

Q: I've noticed that terrain has different properties. Like walls block

line-of-sight and movement. Trees just block movement. And some terrain hurts my agent if he steps on them. How can I find out what properties a terrain has?
A: All the terrain types are defined in terrain.scm. It's pretty

well-documented so I think a smart person like you can figure it out.

Q: Can I add my own terrain type?
A: Feel free.

Q: Cool! Can I give it its own picture? A: Yes. See sprites.scm and sprite-sets.scm. If you can't figure them out let

me know and I'll give you a rundown.

Q: How do I put stuff on the map?
A: Do it in mk-map. After the terrain list you can provide any number of

(add-object <obj> x y) calls to put stuff on the map. That second argument must ultimately be the result of a call to (kern-mk-obj <type> <quant>). For example, to make a 4x4 map of grass and put a short sword at tile (0, 0):

     (mk-map (list ".. .."
                   ".. ..")
              (add-obj (kern-mk-obj short-sword 1) 0 0))

Except you can't make a 4x4 map with mk-map -- it always has to be 32x32.

Q: What stuff can I put on the map?
A: Check out arms.scm, items.scm and anyplace else that calls (kern-mk-obj-type

...) or it's wrapper, (mk-obj-type ...). All of those calls make object types. To make an object from a type use (kern-mk-obj <type> <quant>) and this will create an instance of the type. Use the (add-obj <obj> x y) call discussed above within mk-map to put the object on the map.

Q: How do I set a goal for the map?
A: The third function in your file should be one of the (set-goal-*) procedures

to give the agent a goal. There are three:

(set-goal-escape-dungeion <x> <y>)

The agent must reach the tile at (x, y) to complete the goal.

(set-goal-kill-all-monsters)

      The agent must kill all hostile monsters to complete the goal. Not all
      non-player character's are hostile!

(set-goal-steal-item <x> <y>)

The agent must find and get the "quest item" to complete the goal.

Q: How do I tell the game where to start the agent: A: The final thing you call is (start-at <x> <y>), Which sets the agent's

starting point.

Q: The game crashes/errors/calls me names when I try to load my map. What's

wrong?
A: I don't know. Send me your map file and I'll have a look.

As always with a new language or API, start with the minimum necessary (or a working example) and build it up one small step at a time until you're confident. Unfortunately, the warnings (and asserts!) you get from a map with an error in it can be maddening to figure out. These errors pretty much always appear when starting up, so if you can get that far you're probably home free.

And of course give me your questions and comments at

gmcnutt@sourceforge.net.


Sponsored Links

Discussion Groups
  Beginners
  Distributions
  Networking / Security
  Software
  PDAs

About | FAQ | Privacy | Awards | Contact
Comments to the webmaster are welcome.
Copyright 2006 Sourcefiles.org All rights reserved.