Recording and restoring initial object location

You need to deal with two cases here.

First: The decoy’s home is not a room. For this we want to define a home-room predicate (Think of it like a method, in this case) which always points to a room.

Second: The decoy is already in the right room, just not in the right container. So:

Definition: a decoy is secured:
	if it is enclosed by the player, decide yes;
	if it is enclosed by a closed container, decide yes;
	if it is in the home of it, decide yes;
	decide no.
	
Definition: A decoy is unsecured if it is not secured.

To decide which room is the home-room of (item - a decoy):
	let H be the home of item;
	if H is a room, decide on H;
	if H is a thing, decide on the location of H.

Definition: a decoy (called item) is free to go:
	if best route from the location of item to the home-room of item is a direction, decide yes;
	if the location of item is the home-room of item, decide yes;
	decide no.

Every turn: [You could do this with an every turn rule, or an after rule.]
	repeat with item running through unsecured decoys:
		if the item is free to go:
			say "[The item] spreads its wings and flies back to [the home of item].";
			move the item to the home of item;
		otherwise:
			say "[The item] flaps about uselessly, unable to find its way."

As you can see, we also put the logic that figures out if the decoy is in a closed container into the ‘is a decoy secured’ rule. Then we set up a rule to figure out routing; my personal practice is that if an ‘if’ line would have more than one or statement in it, I make it into a separate definition (Essentially a function); other people’s ideas on this vary, of course.

At one point, the logic may get complicated enough that this is best done as a rulebook or an activity. Rulebooks are much more modular, making it easy to add new steps to checking or carrying out some function of the game. In particular, a rulebook would be useful if you wanted to consolidate the various decoy messages into one.

As for finding real examples of Inform 7 code, several I7 projects, large and small, have their source code available; I7 has a function to publish the source of a story in a readable format. The source code to Emily Short’s games is usually very well-written and informative.

I have to say that I am unable to see why this, which uses three separate relations and creates three separate objects called “home” for each decoy, is superior to the implementation where “home” was set as a property of the decoy (and where we could set the home at startup with a simple reference to “the holder”). It also seems very likely to produce bugs to me. Suppose a decoy has the room-belonging, supporter-belonging, and container-belonging relations all set. What’s “the home of” the decoy supposed to return? The room, the supporter, or the container?

In fact, using the “relations” debugging command yields this:

It seems as though the “home” test is working as intended which is good – but we’re winding up with type mismatches in the relations. Innnteresting. I don’t know how the internals are working here, so I don’t know what we want, but it seems to me that this is likely to not work well.

Sequitur, you said this approach was more Informish than the other one; what makes it so? I’m not the most Informish programmer, so there could well be something I’m missing, but I don’t see what we’re gaining here.

Personally, I would use a property, then define my assertion verbs from that property if I needed to. It’s cleaner.

Gents; I really appreciate your interest in the topic at hand. I really hope you’ll continue to provide your input and suggestions.

Sequitur: Thanks for taking the time to write up the code to go along with your suggestions. I’m going to try it and see how it goes.

Matt W: I’m not that familiar with relations in this context, so I’d like to ask why one would expect that the code should necessarily relate like types. Not having that constraint could be rather useful. Also; from a BNF grammar design viewpoint, I don’t see that as being something that a language could not do and still work reliably. Now, exactly what the interpreter author intended is quite another story. Maybe I’m missing your point. Could you explain further?

Draconis: New ideas always interest me. Could you elaborate with a bit of code? I’d like to see what you mean by cleaner.

A decoy has an object called the home. Belonging relates a decoy (called the item) to an object (called the place) when the home of the item is the place. The verb to belong to implies the belonging relation.

Well it’s simply that room-belonging is supposed to relate one room to one decoy. If room-belonging is actually relating a container to a decoy, or a supporter to a decoy, then I’d think it might lead to trouble elsewhere in the code. I don’t know nearly enough about the internals to know whether it is leading to trouble.

Anyway, looking at it again I don’t think that’s the problem. Contrary to the suggestion in 6.14 that best route goes from object to object, I don’t think it works if both things aren’t rooms (I suppose that “object” allows you to put “nothing” in as an argument, in which case it’ll return “nothing”). So you’d have to define home-room the way Sequitur suggests.

But, more importantly, best routes don’t use even open doors unless you add “, using doors” to your best route call. So if you just look for the route to the homeroom the drake will fail to get home because the route goes through a door, and the duck will fail to get home because it’s already in the room (but not in its box). Add “, using doors” to your best route call and use Sequitur’s solution for the case when the decoy is in the right room but not in/on the right thing.

Thanks, Fellows. All of you have been a big help. My curiosity has been thoroughly tweaked.
I’m going to play with both approaches, for a few days (I have my Spanish class on Monday, so that night is gone).
I’ll try what Sequitur has suggested and then see if I can do it the way Draconix has suggested.
Once I have things working, I’ll post what I have and any observations/questions that are relevant.

Having three relations is a wart resulting from the fact that rooms aren’t things. I actually don’t know why rooms aren’t things; it seems more intuitive that they should be things - especially considering that players can enter non-Room objects - and yet, they are not; if someone knows better than me about the internal design on Inform they could shed some light on it, actually, because it bugs me.

The property and relation solutions are two different ways of accomplishing the same thing, and I don’t think one is inherently superior to the other, just that the relation solution is more idiomatic.

Relations are ‘Informish’ because they’re a feature of Inform, basically; they’re Inform’s solution to the problem of relating objects to one another. Because they’re a well-supported idiomatic feature, they have some advantages. First, relations can be reversible, whereas there’s no elegant way of figuring out whether an object is a property of another object. Relations can be debugged easily. They abstract complexity well in the code, and so on.

Now, were this my project, what I actually would have done is stop and consider whether I need decoys that can home to either a room or a thing; because if not, I can just happily use relations to do this in a transparent, elegant way. Otherwise, I actually like Draconis’ solution better; I hadn’t thought of it before, but it’s true, it’s cleaner. Objects in Inform are ‘dirty’; you can’t do much with an object unless you know whether it’s a thing or a room or something else, so it’s annoying to implement behaviour that does things to objects.

(I posted the relations example for educational purposes; choosing between one way or another of doing things depends on knowing what the project as a whole is supposed to accomplish).

To the best of my knowledge rooms are not things because that’s how it’s always been in Inform, and it would break lots of stuff to change it now.

I’ve seen some other explanations for it too. If rooms are things, can you put a room inside a room? Can you pick a room up? Can you push a room, touch it, etc.? Some of these would break the world model less than others, but in general rooms seem different enough from other things that it makes sense to me that they’re separate.

In Inform 6 rooms aren’t (or at least weren’t) their own special kind; a room was an enterable object without a parent. I believe that Inform 7 changed this because it wasn’t doing anyone any good. There’s been some discussion of this somewhere, but I’m not sure where to find it.

Correct. (Not an object with an “enterable” property, but simply an object that the player might enter by any means.)

Pretty much. In I6 you could change an object from a non-room to a room simply by moving it off-stage. But the library didn’t have good support for this kind of trick, and in fact you had to fight it in some ways to make it happen. (Some properties were interpreted differently, and not in a convenient way.) So I7 dropped that idea and made rooms explicit.

The explicit room kind makes a bunch of features easier. For example, it permits the compiler to understand “A lamp is in every room”.

All that said – I’d think it would be easier to say

Belonging relates one object (called the home) to one decoy.

Then you could do a runtime test to see if the home is a room, container, or supporter.

Sounds like this is not something for which there is much of a precedent.

I think I should clarify that I’m trying to write this “decoy” code to create an extension for use in a number of adventures.
The user would typically wish to create a “world” in which the decoy would return to the place it occupied at instantiation.
As such, I can’t really make the assumption that home will always be a room or always be a thing.

The relationship approach seems to work with the various combinations of objects, odd as it sounds.
However, I am still having troubles with the the drake finding its way home to the hallway desk, when doors are involved.
Hope this isn’t a manifestation of a type mismatch.

I suppose that I could instantiate an “invisible” generic supporter in every room and define “dropping” the decoy, etc., as putting it on that supporter in the current room. I’d need to have a home-room and also a home-object within the room to make this useful. The drop logic would basically drop the decoy on the invisible supporter in the current room, then it would determine whether a path home exists using best route between the current room and the home-room, then potentially move the dropped decoy from the current rooms invisible generic supporter to the home-room object (floor, table, box etc.). In the case of a floor being the home-object, I think I’d have to explicitly define a “floor” supporter. Dropping it on the invisible generic supporter of the home room may not work.

I know my explanation is very rough and far from being either elegant or simple.
However; it would appear to address the mixing of types.

Thoughts?

So this worked for me (some debugging text is left in):

Every turn: repeat with item running through unsecure decoys: if best route from the location of the item to the location of the home of item, using doors is a direction (called indicated direction): say "[The item] spreads its wings and flies [indicated direction] back to [the home of item]."; move the item to the home of item; otherwise: say "[The item] can't find the way home to [the home of item], since the indicated direction is '[indicated direction]'."; if the home of item is not a room: say "We should be seeing if [the item] can get back to [the location of the home of item] by going [best route from the location of item to the location of the home of item]."; showme the best route from the living room to the hallway, using doors.

Note “using doors”; that’s what allows the route to go through the door. Have you tried something like this?

Full compilable code below the spoiler tag. Note that the duck still can’t get home because of that trick we were discussing before, where it’s in the same room as its home so the best route is “nothing.”

[spoiler][code]“Mallard v4” by Gary

A decoy is a kind of thing.

Room-belonging relates one room (called the home) to one decoy.
Supporter-belonging relates one supporter (called the home) to one decoy.
Container-belonging relates one container (called the home) to one decoy.

The verb to belong to (he belongs to, they belong to, he belonged to) implies the reversed room-belonging relation.
The verb to belong on (he belongs on, they belong on, he belonged on) implies the reversed supporter-belonging relation.
The verb to belong in (he belongs in, they belong in, he belonged in) implies the reversed container-belonging relation.

Definition: A decoy is secure if it is in its home or it is on its home or it is enclosed by the player.
Definition: A decoy is unsecure if it is not secure.

Every turn:
repeat with item running through unsecure decoys:
if best route from the location of the item to the location of the home of item, using doors is a direction (called indicated direction):
say “[The item] spreads its wings and flies [indicated direction] back to [the home of item].”;
move the item to the home of item;
otherwise:
say “[The item] can’t find the way home to [the home of item], since the indicated direction is ‘[indicated direction]’.”;
if the home of item is not a room:
say “We should be seeing if [the item] can get back to [the location of the home of item] by going [best route from the location of item to the location of the home of item].”;
showme the best route from the living room to the hallway, using doors.

[---------------------------------- Main -----------------------------------------]

Hallway is a room.
The Hall table is a supporter in the hallway.
The drake is a decoy on the hall table. The drake belongs on the hall table.

The Passage Door is a closed door. It is west of the hallway and east of the living room.

The Living room is a room.
The mallard is a decoy in living room. The mallard belongs to the living room.

The Dining room is west of living room.
The box is a container in dining room. The duck is a decoy inside the box. The duck belongs in the box.

Test me with “take drake / w /close door / drop drake / look / open door / take mallard / w / put mallard in box / look / take duck / drop duck / look / e”

[/code][/spoiler]

I can’t test this myself at the moment, but didn’t Sequitur say earlier that this didn’t work because you can’t have a relation of objects to things?

You’re right – I was thinking of properties rather than relations. My mistake.

This gets back to the “do it with a property” suggestion, and you’ve already posted sample code for that.

Matt;

Thanks. I had unwittingly used “using doors” and so I still had the drake flying through the apparently closed door. Seems the door needs to be locked, because best route assumes unlocked doors can be opened.

Will look at how fixing the in-same-room issue.

Yeah, I’m not sure if there’s any way to test the best route using open doors but not closed ones, at least not easily.

Sequitur posted a fix for the same room issue that I think should work; just test for that before you test for “best route.”

Thanks, Matt. Will give the “same room” fix a try and post an update on how things go.

I really appreciate the help of all of you.
Now I’ve just got to get more familiar with relations and definitions.
They seem to be a more “elegant” way of attacking this sort of issue.

The following seems to work pretty well.
If you have other suggestions, I’m always open to such things.


"Mallard v7" by Gary

A decoy is a kind of thing.

Room-belonging relates one room (called the home) to one decoy.
Supporter-belonging relates one supporter (called the home) to one decoy.
Container-belonging relates one container (called the home) to one decoy.

The verb to belong to (he belongs to, they belong to, he belonged to) implies the reversed room-belonging relation.
The verb to belong on (he belongs on, they belong on, he belonged on) implies the reversed supporter-belonging relation.
The verb to belong in (he belongs in, they belong in, he belonged in) implies the reversed container-belonging relation.

Definition: A decoy is secured if it is in its home or it is on its home or it is enclosed by the player.
	
Definition: A decoy is unsecured if it is not secured.

To decide which room is the home-room of (item - a decoy):
	let H be the home of item;
	if H is a room, decide on H;
	if H is a thing, decide on the location of H.

Definition: a decoy (called item) is free to go:
	let the best way be the best route from the location of item to the home-room of item, using doors;
	if the best way is a direction, decide yes;
	if the location of item is the home-room of item, decide yes;
	decide no.

Every turn: [You could do this with an every turn rule, or an after rule.]
	repeat with item running through unsecured decoys:
		if the item is free to go:
			say "[The item] spreads its wings and flies back to [the home of item].";
			move the item to the home of item;
		otherwise:
			say "[The item] flaps about uselessly, unable to find its way."		

[---------------------------------- Main -----------------------------------------]

Hallway is a room.
The Hall table is a supporter in the hallway.
A brass key is on the Hall table.
The drake is a decoy on the hall table. The drake belongs on the hall table.

The Passage Door is a an open lockable door. It is west of the hallway and east of the living room.
The brass key unlocks the Passage Door.

The Living room is a room.
The mallard is a decoy in living room. The mallard belongs to the living room.

The Dining room is west of living room.
The box is a container in dining room. The duck is a decoy inside the box. The duck belongs in the box.


Test all with "test drake / test mallard1 / test mallard2 / test duck".

Test drake with "take drake / take brass key / w / close door / lock passage door with brass key/ drop drake / look / unlock passage door with brass key / open door / e"

Test mallard1 with "w / take mallard / drop mallard / take mallard / w / drop mallard / e /e".

Test mallard2 with "w / take mallard / w / take duck / put mallard in box / look / e /e".

Test duck with "w / w / take duck / drop duck / look / e / e".