problem: "a random door" eliminates options until list empty

EDIT: Reading my third post, below, will probably save you some time. I discovered some new data that simplifies things.

Hi everyone,

New to IF, new to Inform 7. Some experience with programming languages.

Problem: I want a character to move each turn through any random available door to the adjacent space. However, using “a random door” in my Source causes Inform to eliminate already-chosen doors each turn until there are no doors in current space’s “list of doors.” I wonder if “purely at random” can be used (see “Writing with Inform” §5.7 on random text), or if I should just solve it all differently.

My basis is “Mistress of Animals,” Recipe Book §6.14 and §7.13. However, in my Map, each room is separated by a door. As the example says,

“The implementation would become more complicated if there were doors which might block transit between these locations.”

My Map has 3 rooms (Red, Blue, Yellow), separated by 3 doors (purple, orange, green). The “showmes” are how I debug. Pay attention to the “list of doors” produced each turn.

Source:

[code]“traveling custodian”

The Red Room is a room. The purple door is a door. The purple door is east of the red room and west of the blue room. The green door is a door. The green door is southwest of the blue room and northeast of the yellow room. The orange door is a door. The orange door is northwest of the yellow room and southeast of the red room.

The custodian is in the Red Room.

Every turn:
if the custodian is in a room (called the old space):
showme the location of the old space;
showme the location of the custodian;
showme list of doors in the old space;
let xanadu be a random door in the old space;
showme xanadu;
let the new space be the back side of xanadu;
showme the location of the new space;
if the custodian is visible, say “The Custodian heads to [the new space].”;
move the custodian to the new space;
if the custodian is visible, say “The custodian arrives from [the old space].”;
showme the location of the custodian.
[/code]

Story:

traveling custodian
An Interactive Fiction
Release 1 / Serial number 160905 / Inform 7 build 6L38 (I6/v6.33 lib 6/12N) SD

Red Room
You can see an orange door, a purple door and a custodian here.

z
Time passes.

“location of the old space” = room: Red Room
“location of the custodian” = room: Red Room
“list of doors in the old space” = list of doors: {orange door, purple door}
“xanadu” = object: purple door
“location of the new space” = room: blue room
The Custodian heads to the blue room.
“location of the custodian” = room: blue room

z
Time passes.

“location of the old space” = room: blue room
“location of the custodian” = room: blue room
“list of doors in the old space” = list of doors: {green door}
“xanadu” = object: green door
“location of the new space” = room: yellow room
“location of the custodian” = room: yellow room

z
Time passes.

“location of the old space” = room: yellow room
“location of the custodian” = room: yellow room
“list of doors in the old space” = list of doors: {}
“xanadu” = object: nothing
“location of the new space” = room: nothing

[** Programming error: tried to “move” custodian to nothing **]
“location of the custodian” = room: yellow room


Can anyone see a way to either implement “purely at random” to stop Inform from eliminating options each turn, OR just solve the whole thing differently?

Thank you!
Brooke

Addendum:

I have correctly (I think) changed the definition of “the new space” FROM “the back side of xanadu” to “the other side of xanadu from the location of the custodian”.

The Story runs the same as before, with the same problem. BUT I see that the list of doors always becomes empty in the Yellow room, and the error message is now:

*** Run-time problem P47 (at paragraph 14 in the source text): Phrase applied to an incompatible kind of value.

Paragraph 14 in the source text is that same line: “let the new space be the other side of xanadu from the location of the custodian;”.

ALSO: The list of available doors goes immediate from 2 to zero if the custodian happens to be moved first to the Yellow room instead of the Blue room. For example:

traveling custodian
An Interactive Fiction
Release 1 / Serial number 160905 / Inform 7 build 6L38 (I6/v6.33 lib 6/12N) SD

Red Room
You can see an orange door, a purple door and a custodian here.

z
Time passes.

“location of the old space” = room: Red Room
“location of the custodian” = room: Red Room
“list of doors in the old space” = list of doors: {orange door, purple door}
“xanadu” = object: orange door
“location of the new space” = room: yellow room
The Custodian heads to the yellow room.
“location of the custodian” = room: yellow room

z
Time passes.

“location of the old space” = room: yellow room
“location of the custodian” = room: yellow room
“list of doors in the old space” = list of doors: {}
“xanadu” = object: nothing

*** Run-time problem P47 (at paragraph 14 in the source text): Phrase applied to an incompatible kind of value.

“location of the new space” = room: yellow room
“location of the custodian” = room: yellow room

Thanks,
Brooke

Sorry to be a pain, but it looks as if the problem is much simpler than I thought, and not related to randomness. Rather: the first room created “lists” both its doors; the second room created only “lists” one of its doors; the third room created “lists” none of its doors. Nonetheless, the Index seems to show that each room has two doors.

Simpler Source:

[code]“traveling custodian”

The Red Room is a room. The purple door is a door. The purple door is east of the red room and west of the blue room. The green door is a door. The green door is southwest of the blue room and northeast of the yellow room. The orange door is a door. The orange door is northwest of the yellow room and southeast of the red room.

The custodian is in the Red Room.

When play begins:
showme the list of doors in the red room;
showme the list of doors in the blue room;
showme the list of doors in the yellow room.[/code]

Resulting Story:

“list of doors in the red room” = list of doors: {orange door, purple door}
“list of doors in the blue room” = list of doors: {green door}
“list of doors in the yellow room” = list of doors: {}

traveling custodian
An Interactive Fiction
Release 1 / Serial number 160905 / Inform 7 build 6L38 (I6/v6.33 lib 6/12N) SD

Red Room
You can see an orange door, a purple door and a custodian here.


I attach a screen shot of Index > World, so you can see that the Map shows each room having two (2) doors.

Any ideas? Thanks!

This issue occurs because doors are floating objects (as are backdrops), and the behind-the-scenes movement of floating objects is keyed to the player’s location, not the custodian’s location.

Floating objects are logically present in multiple locations, but the objects representing them can only really be in one location at a time. When play begins, the purple and orange doors are in the Red Room, because the player is there. This means that the purple door is not presently in the Blue Room, and the orange door is not presently in the Yellow Room. However, the green door remains in the Blue Room (the first of the two rooms it connects that was defined in the source code), because it does not adjoin the player’s location. This leaves the Yellow Room containing no doors at all. When the player moves, floating objects are reevaluated, and the doors are moved as necessary so that the correct ones will be in the player’s new location.

A cheap solution would be to move the player to the custodian’s location without printing a room description at the beginning of your every turn rule (thus forcing floating objects to be moved so that they’re correct for that location), choose a random door, and then move the player back before moving the custodian (so that the tests for “custodian is visible” are correct):

Every turn when the custodian is in a room (called the old space):
	let the old location be the location of the player;
	let the old visited flag be false;
	if the old space is visited, now the old visited flag is true;
	move the player to the old space, without printing a room description;
	showme the old space;
	showme the location of the custodian;
	showme list of doors in the old space;
	let xanadu be a random door in the old space;
	showme xanadu;
	let the new space be the other side of xanadu from the old space;
	showme the new space;
	say "[run paragraph on]";
	move the player to the old location, without printing a room description;
	if the old visited flag is false, now the old space is not visited;
	if the custodian is visible, say "The Custodian heads to [the new space].";
	move the custodian to the new space;
	if the custodian is visible, say "The custodian arrives from [the old space].";
	showme the location of the custodian.

I’ve fixed a bug in the program where the custodian can go through a door into the same room that he’s already in, because of the use of “the back side of xanadu”. The front side and back side are determined based on how the door is defined in the source code, not on the current location of the custodian. Instead use “the other side of from ”. (Edit: I see that you mentioned this in your second post.)

I’ve also fixed up the visited flag for unvisited rooms to which we temporarily move the player.

Yes, the “floating” character of doors can be tricky, especially dealing with NPC.

Instead of moving the player around, you could also try defining a special construction that tests whether the door is “in” the room in the way we want–that is, whether the room is the front side or the back side of the door. Then we can use it in lists and collections of random objects. Like this:

[code]“traveling custodian”

Venting on relates a door (called X) to a room (called Y) when Y is the front side of X or Y is the back side of X. The verb to vent on means the venting on relation.

The Red Room is a room. The purple door is a door. The purple door is east of the red room and west of the blue room. The green door is a door. The green door is southwest of the blue room and northeast of the yellow room. The orange door is a door. The orange door is northwest of the yellow room and southeast of the red room.

The custodian is in the Red Room.

Every turn:
if the custodian is in a room (called the old space):
showme the location of the old space;
showme the location of the custodian;
showme list of doors that vent on the old space;
let xanadu be a random door that vents on the old space;
showme xanadu;
let the new space be the other side of xanadu from the old space;
showme the location of the new space;
if the custodian is visible, say “The Custodian heads to [the new space].”;
move the custodian to the new space;
if the custodian is visible, say “The custodian arrives from [the old space].”;
showme the location of the custodian.[/code]

The business with defining a relation that gets tested as a condition is in Writing with Inform §13.12.

At some point you might want to use something like this:

try the custodian entering xanadu;

instead of moving the custodian directly to the new space. That would force the custodian to respect requirements for entering doors, like opening it before going through, failing if the door is locked, etc.

Thanks, Vince! Thanks, Matt!

Now I’ve got two good, working solutions to choose from. And, more important, each solution gives me plenty to learn.

And thanks for your patience as I worked through my question.

Brooke