Make NPC walk to adjacent rooms through doors, one step per turn

I want to make my NPC move from their current location to a random adjacent room, even through open or closed doors. But two rooms are not adjacent if a door is between them.

How to accomplish this?

I tried this, but it doesn’t work:

Nextness relates a room (called A) to another (called B) when A is adjacent to B or A is not B and a door which is adjacent to A is adjacent to B. The verb to be next to implies the nextness relation.

Every turn:
if Dave is in a room (called currentspace)
begin;
if a random chance of 1 in 2 succeeds
begin;
let nextspace be a random room which is next to currentspace;
if Dave is visible, say “Dave heads to [nextspace].”;
move Dave to nextspace;
if Dave is visible, say “Dave arrives from [currentspace].”;
end if;
end if;

This results in programming error: Dave moved to nothing or some such error. I am 99% sure this worked in earlier inform versions.

Nothing seems to work. This shouldn’t be hard. Why does adjacency not include doors by default? It seems to me the way doors are handled in Inform is a bit braindead, because all my coding headaches always came from doors.

You can let Inform figure out the details (and the messages):

Dave has a room called destination.  

When play begins: now the destination of Dave is the location of Dave.

Every turn:
	while the destination of Dave is the location of Dave:
		now the destination of Dave is a random room;
	let way be the best route from the location of Dave to the destination of Dave, using doors;
	if way is not nothing, try Dave going way.

Dave will automatically open closed doors as needed in order to travel, and this will automatically print travel messages if Dave is visible to the player at the time.

If you want Dave to be able to travel through locked doors as well (to which he has the key), that’s a bit trickier. The Locksmith extension can help with letting players and NPCs automatically unlock locked doors, but there isn’t currently any good way to restrict the route-finding to use only the doors that Dave has a key for, so he can get stuck if you’re not careful.

Usually best to avoid getting into those kinds of situations, unless the point of a puzzle will be to find a way to unlock the door for Dave.

This is sort of thing mentioned in Writing with Inform: 6.14. Adjacent rooms and routes through the map

Actually, locked doors plus Locksmith and giving Dave a master key to all the doors could be amusing – you could make it so that Dave automatically locks any lockable door behind him (even if it wasn’t locked to start with), and then the player has to contend with doors they’ve already used “randomly” locking, so they always have to keep those keys at hand…

Thank you, this almost works!

I would have never been able to come up with this myself, because it is not in the documentation I think.

The only problem now is that Dave leaves all doors open that he passes. Is there an easy way to make him close doors behind him?

I think the reason why my original approach didn’t work had to do with the definition of the nextness relation. I like your solution much more, so I will use it.

But, out of curiosity, is there a way to tell Inform the priority of Boolean operations? In my original wording

A is adjacent to B or A is not B and a door which is adjacent to A is adjacent to B.

I would like it to have a certain hierarchy to the Booleans, e.g.

(A is adjacent to B) or (A is not B and a door which is adjacent to A is adjacent to B).

Mathematically, one would use parentheses, but Inform doesn’t understand this. So how can I group Boolean operations to make the priorities clear?

There are several examples in the documentation, actually. The page that Jonathan linked above describes the specific phrase (although the first example there more closely resembles your original code). Even more examples can be found in RB7.13.

I haven’t tested this, but in theory something like this should do the trick:

After Dave going through an openable door (called portal):
	try Dave closing portal;
	continue the action.

Parentheses do work for that, in general. The problem here is not with the priorities, it’s with the generality of asking for a door which is adjacent to A. That never actually finds anything, despite the fact that if you ask if a specific door is adjacent to a room then it will agree. Technically speaking, if you look at the Index, you’ll find that the adjacency relation is only specified for rooms to rooms, so it’s not really correct to be asking if doors are adjacent to anything, even if it sometimes does appear to work.

Doors are peculiar things that – like backdrops – theoretically exist in multiple locations but actually only exist in one particular location at a time, depending on the location of the player. Hence they can be quite tricky to reason about from anywhere other than the player’s location.

The following is a working way to define your nextness relation, though I’d still recommend using the route-finding method above instead:

Door-targeting relates a door (called D) to a room (called A) when the front side of D is A or the back side of D is A.  The verb to be door-targeted towards implies the door-targeting relation.

To decide if (A - room) is calculated-door-linked to (B - room):
	repeat with D running through doors that are door-targeted towards B:
		if the other side of D from B is A, decide yes;
	decide no.

[Strictly speaking, defining this relation is unnecessary; nextness could just use
 calculated-door-linked directly.  But this allows you to check it both positively and negatively elsewhere.]
Door-linking relates a room (called A) to another (called B) when A is calculated-door-linked to B.  The verb to be door-linked to implies the door-linking relation.

Nextness relates a room (called A) to another (called B) when A is adjacent to B or A is door-linked to B. The verb to be next to implies the nextness relation.

Note that this will probably not work as expected for one-way doors.