Select Random Room in Region

Hi,

I have four rooms that together, make up a region. If the PC tries to throw an object, and they are not in the correct room, the object should be thrown into one of the other three rooms, randomly, but not the one the PC is currently in. (The rooms don’t have walls, except for the right room).

I think I need a subset of the list of rooms, I just don’t know how to eliminate the current room from the list of rooms.

if(!gPlayerChar.isIn(belly2)){
            "You throw the dart as hard as you can. It sails out of your view but you hear it splash down in the muck some distance from you.  ";
            //belly2 is the right room
            local myRoom = gPlayerChar.getOutermostRoom();
            local otherRooms = [belly1,belly3,belly4];
            local randomRoom = otherRooms - myRoom //THIS IS WHERE I AM STUCK
            dart.moveInto(randomRoom);
        }

As always, thank you in advance.

1 Like

I think you have set up the room list correctly, including removing the unwanted room, but maybe you need to randomize it?

Something like

dart.moveInto(randomRoom[rand(randomRoom.length()) +1]);

Uh, adv3 syntax. Lite is… similar?

2 Likes

During action execution the current actor will be gActor. Their location is gActor.location. If the location may or may not be a Room (like if they might be lying in a bed, for example) you can use gActor.getOutermostRoom().

There are several ways to exclude a specific element from a list. I’ll talk about List.subset() as perhaps the easiest to understand. It takes an function as an argument, and will return go through the list calling the function with each element as its argument, and will return a list containing only the elements it returned true for. So:

local lst = [ 1, 2, 3 ].subset({ x: x > 1 })

…will set lst equal to [ 2, 3 ].

There are several ways to pick a random element; the most portable is probably something like:

lst[rand(lst.length) + 1]

Putting that all together, here’s a little function that takes a list and a function as an argument, and returns a random element of the subset that matches the function:

pickRandomWithExlusion(lst, fn) {
        lst = lst.subset({ x: (fn)(x) });
        return(lst[rand(lst.length) + 1]);
}

And here’s a little test “game” that illustrates it. It provides a >FOOZLE action that picks a random room that the player isn’t currently in:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

startRoom: Room 'Void'
        "This is a featureless void. "
        north = northRoom
        south = southRoom
;
+me: Person;

northRoom: Room 'North Room'
        "This is the north room. "
        south = startRoom
;

southRoom: Room 'South Room'
        "This is the south room. "
        north = startRoom
;

versionInfo: GameID;
gameMain: GameMainDef initialPlayerChar = me;

DefineSystemAction(Foozle)
        execSystemAction() {
                local rm;

                rm = pickRandomWithExlusion([ startRoom, northRoom, southRoom ],
                        { x: x != gActor.getOutermostRoom });
                defaultReport('Picked <<rm.roomName>>. ');
                local lst = [ 1, 2, 3 ].subset({ x: x > 1 });
                aioSay('\nlst = <<toString(lst)>>\n ');
        }
;
VerbRule(Foozle)
        'foozle' : FoozleAction
        verbPhrase = 'foozle/foozling'
;

pickRandomWithExlusion(lst, fn) {
        lst = lst.subset({ x: (fn)(x) });
        return(lst[rand(lst.length) + 1]);
}

I don’t know how you’re selecting the Rooms that are valid. If it’s a static list this will work fine. If you just wanted to pick adjacent rooms you could walk through Direction.allDirections to enumerate all the adjoining rooms and pick from it. I’ve got code that does that kind of thing as well, but I don’t know if that’s what you’re after.

1 Like

Does Lite not support this list subtraction operator?

            local otherRooms = [belly1,belly3,belly4];
            local randomRoom = otherRooms - myRoom

I’m pretty sure I am successfully using exactly this construct in adv3

2 Likes

I think operators on intrinsic types are part of the VM, not the library.

I generally prefer using subset() because it’s more flexible (works when you’re not just excluding a single element, for example).

2 Likes

Ringrazio JJ et. al. for giving me for once, an occasion of using the online edition of the adv3Lite documentation:

I haven’t got an actual usage for the specific documentation, notwhistanding a major and very complex WIP, but I think that removing the room from the list is feasible.

Best regards from Italy,
dott. Piergiorgio.

2 Likes

Tangential to @dsherwood’s initial question - on the randomization side of the equation, I did add a List method called randSublist if more than one item needed selected from a larger list. Works on a “card draw” paradigm. Defaults to a single element list returned.

/* ====================================================================
 *
 *   randSublist List method
 *
 *   returns list composed of a random sampling of elements, of size 'size'.
 *   if size bigger than existing list, just return copy of list 
 *   Parameters:
 *     size - size of list to return, default is 1 element
 *
 *   Returns:
 *     new list of length 'size', randomly selected from parent list
 *
 * ====================================================================
 */
modify List
    randSublist(size = 1) {
        local workingList = self;
        if (size < length()) {
            local newList = [];
            for (local i= size; i--; i>0) {
                local thisEl = rand(workingList.length())+1;
                newList += workingList[thisEl];
                workingList = workingList.removeElementAt(thisEl);
            }
            return newList;
        }
        return workingList;
    }
;

ie

destRoom = randomRoom.randSublist(); // returns single element list
destRoom = randomRoom.randSublist(2); // returns two-element list.  in this case same as start
2 Likes

I was so close.

Thank you, this was the missing bit!

1 Like

It’s also nice to have in your pocket the tidy TADS tidbit of

rand(lst);

to get a random element from lst. Assuming of course that lst has the necessary subtractions made.

1 Like