Navigating and Searching the MUD

In order for a bot to search the MUD, it must have a way to navigate. In other words, it must have a method for moving from room to room.

Important Data Structures for Navigating the MUD

The most important data structure in the MUD is called the room. Besides the fact that the room metaphor is the abstraction that helps keep the environment coherent and understandable, rooms form the 'context' of computation. For the purposes of search and navigation, rooms have the following properties:

  • every room has an object number
  • every room has a room 'type' and inherits verbs and properties accordingly
  • every room has a .exits property, which contains a list (possibly empty)

Object Numbers

Every object in the MUD has a unique object number assigned by the system. In navigation and search it is often useful to maintain a list of rooms that have been visited, to help avoid navigating and searching the same areas over and over again.

Maintaining Lists of Objects

There are two methods for maintaining lists of objects. In the case of navigating and search rooms, the first method is to keep every object in the order it was visited. Suppose a bot had a property defined that was named .room_list - the method for keeping a complete list of every room visted could be done like this: this.room_list = {@this.room_list, this.location}; This will simply add the new location onto the end of the list, so there could be duplicate entries if a room were visited more than once (note: '@' is called the 'splice' operator).

The second method is to record rooms using the idea of mathematical sets, where only one instance of an object can appear in a set - the method for maintaining such a list would be this:

this.room_list = setadd(this.room_list, this.location); This would be appropriate when recording the visit was important, but the order of the visit was not.

Equally important is the ability to determine whether an object is on a list or not. This is most easily achieved using the 'in' operator. For example, suppose a bot had a local variable named 'roompos' for temporarily storing the position of a room object in a list of rooms. That could be done like this:

roompos = this.location in this.room_list The resulting value stored in 'roompos' will either be a 0 (zero) indicating the current location is not on the list, or an integer greater than zero, indicating both the room is on the list, and in what indexed position.

Room Types

Every room inherits functions/verbs and properties from its ancestors. All rooms inherit from 'generic room(#3)'. In Blackwood, all the rooms also inherit from 'GameRoom(#1805)'. The following are all children of $g.gameroom: Street(#1280) Store(#1281) Generic Infrastructure Room(#1448) Back Room(#3670) Basement(#3671) Backyard(#3672) Outhouse(#3673) Living Quarters(#3674) Sleeping Quarters(#3675) Current Stores(#1669) Map Room(#4772) Dwelling(#5606) Garden(#5728) Generic Programmer Room(#1442)

Exits

Every room has a '.exits' property, listing the exits leaving the room. Exits have the following properties:
  • .source - a room object the exit leaves from
  • .dest - a room object the exit leads to
  • .obvious - a flag (0 or 1) denoting whether the exit is visible to the players

The .exits property is usually private (only visible to the room's owner), so there is a 'wizardly' function defined on $g used to access this property. Suppose a bot had a local variable named 'current_exits', then the exits of the current room could be stored there as follows:

current_exits = $g:get_exits(this.location);

Important Functions for Navigating the MUD

The 'proper' way for bots to navigate the MUD is by going from room to room using connecting exits. This is accomplished using the 'move' function defined on $exit (the generic exit). Suppose, for example, a bot wished to move from its current room to the first room on the list of exits connected to the current room. This could be accomplished like this:

current_exits = $g:get_exits(this.location);
current_exits[1]:move(this);

For next time, suppose the bot only wanted to visit a new room if it was of type $g.street and had never been vistied before.

Searching the MUD

The basis for searching the MUD is called a 'best-first' search algorithm, because it is possible in this problem-space to evaluate the relative values of competing paths. In the case of the Blackwood Mine search assignment, there is a value defined on each $g.street named '.to_mine' that contains an integer representing the distance from that room to the mine. Therefore, in this particular case, lower numbers are better.

For our purposes, the basic algorithm given on pages 73-79 of the Rich and Knight textbook as simplified below, is enough to form the basis of the assignment.

  1. Start with OPEN containing just the initial state
  2. Until a goal is found or there are no nodes left on OPEN do
    1. Pick the best node in OPEN
    2. Generate its successors
    3. For each successor do
      1. If it has not been generated before, evaluate it, add it to OPEN, and record its parent
      2. If it has been generated before, change the parent if this new path is better than the previous one. In that case, update the cost of getting to this node and to any successors that this node my already have.

In LambdaMOO terms

The 'skeleton' of your search algorithm will look like this:


"";
for startpoint in ($g.mine_start)
" start with OPEN containing just the initial state (and an empty CLOSED list)";
move(brian_slator7, startpoint);
while (brian_slator7.location != $g.blackwood_mine && length(OPEN) > 0)
" Pick the best node in OPEN (you could define a global OPEN property on the bot, ";
" or use a 'scattering assignment' like this "; " if a closed street was found on the last iteration, "; " clear the flag and calculate new successors to the bestnode "; " else proceed normally "; {bestnode, OPEN} = brian_slator7:dequeue(OPEN);
" generate its successors (a list of exits)";
for successor in (successors)
" if it has not been generated before, evaluate, add to OPEN, and record 'parent' (i.e. the path) ";
endfor
" now we are ready to move to the next room - Here is where would check for a closed road ";
next_room = brian_slator7:front(OPEN);
next_exit = "code to find the right exit ";
if (next_room in $g.mine_flooded) " CLOSE the next_room, dequeue from the OPEN queue, and set a flag "; else " the same code as before "; next_exit:move(this); endif endwhile
endfor


Contact: slator@cs.ndsu.edu; Modified: 14nov06