Recording and restoring initial object location

I tend to learn programming languages by trying to write code that is a bit of a stretch for my knowledge level.
So; I have tried to write some code to define a kind of object called a “_decoy”.

I would like to record the initial room in which each decoy is placed.
The object is to then be able to have the decoy return to the home location when dropped by a player.
I haven’t addressed the code to restore the location, because I still can’t record the initial location.

Any help would be appreciated.

Section 1 - _decoy (kind)

[This is the start of the code intended to later be set up as an extension.]

A _decoy is a kind of thing.
A _decoy has a text called type.  The type of a _decoy is usually "mallard".
A _decoy has a text called home.  The home of a _decoy is usually "undefined".

The description of a _decoy is usually "It is a beautifully carved and painted [type] decoy.".

When play begins:
	repeat with item running through _decoy:
		say "Programmed location of [item]: [location of item].";
		[Now home of item is "mantlepiece";] [This assignment works in recording the word 'mantlepiece']
		Now home of item is location of item; [This assignment does not work.]
		say "Stored location of [item]: [home of item].".

[This is the end of the code intended to later be set up as an extension.]

Section 2 - Test Adventure Code

The landing is a room.
The library is a room. It is south of the landing. 
The Mantlepiece is a supporter in the Library. "The mantlepiece is one solid piece of oak.".
The Mallard Decoy is a _decoy on the Mantlepiece.

What’s the error message?

The home of the item is defined as a text, and the location of the item is a room, so “Now home of item is location of item;” is a type mismatch.

If you actually want to have the item returned to its home when dropped, you don’t want the home to be a text. If you just wanted it to wind up on the floor, then you could have the home of the object be a room. (And you could still put it in a say phrase; room names can be printed just by referring to the room.)

But it looks like you want it to be a room sometimes, a supporter sometimes, and a container sometimes. In that case I would define the home as an object that varies. On dropping the decoy, you could test if the home was a supporter (and move it to on the supporter), a container (and move it to on the container), a room (and move it into the room), and then if it’s none of those perhaps you leave it on the floor.

Echoing Matt, except I wouldn’t make the object global. This should be all you need.

A decoy is a kind of thing. A decoy has an object called origin.

Then you could access the decoy as “the origin of (the decoy)”.

Yes, this is what I meant. “That varies” was a brainfart.

Thanks Gents;

Now I have it working nearly as I intended.
All of your input helped me a great deal.
Matt seemed to have guessed what I originally intended by suggesting that I may want to put the decoy back on the mantlepiece, or I might just want it to “land” on the floor of the original location.
How would I determine and store the “mantlepiece” instead of the “library”?

Here is what I have at the moment:

"Mallard" by Gary

Section 1 - _decoy (kind)

[This is the start of the code intended to later be set up as an extension.]

A _decoy is a kind of thing.
A _decoy has a text called type.  The type of a _decoy is usually "mallard".
A _decoy has an object called origin.

The description of a _decoy is usually "It is a beautifully carved and painted [type] decoy.".

When play begins:
	repeat with item running through _decoy:
		say "Programmed location of [item]: [location of item].";
		Now origin of item is location of item;
		say "Stored location of [item]: [origin of item].".
		
After dropping a _decoy (called the chosen decoy):
	Say "the [chosen decoy] spreads its wings and flies back to the [origin of the chosen decoy].";
	move the chosen decoy to the origin of the chosen decoy.

[This is the end of the code intended to later be set up as an extension.]

Section 2 - Test Adventure Code

The landing is a room.
The library is a room. It is south of the landing. 
The Mantlepiece is a supporter in the Library. "The mantlepiece is one solid piece of oak.".
The Mallard Decoy is a _decoy on the Mantlepiece.

Here is the output of the above:

Mallard
An Interactive Fiction by Gary
Release 1 / Serial number 140201 / Inform 7 build 6G60 (I6/v6.32 lib 6/12N) SD

landing

>s

library
The mantlepiece is one solid piece of oak.

On the Mantlepiece is a Mallard Decoy.

>take decoy
Taken.

>n

landing

>drop decoy
the Mallard Decoy spreads its wings and flies back to the library.

>look
landing

>s

library
The mantlepiece is one solid piece of oak.

You can also see a Mallard Decoy here.

>

“Location of…” is always the room that something in. “Holder of…” will give you the container it’s in, supporter it’s in, or room it’s in, or whoever’s carrying it or wearing it if applicable; see section 8.17 of Writing with Inform (which describes using “holder of” as a last resort, but phooey on that unless there’s a really good reason to be cautious).

EDIT: By the way, you might want to check that the origin of the chosen decoy isn’t the room the player just dropped it in. And if the player gets rid of the decoy some other way, for instance by putting it on something, then it won’t fly back. You might be able to take care of that with a kind of action:

[code]Dropping is letting go. Putting something on is letting go. Inserting something into is letting go. [and so on as you think of more cases]

After letting go when the noun is a _decoy: [your code here][/code].

And you might want to think about whether there’s a path to the origin, so the decoy can’t fly out of any closed containers… by the way there’s no special reason to put the underscore in the name, though I guess in extensions it might help avoid namespace clashes.

Thanks, Matt. I’ll give what you suggest a try.

By the way; you’re right on all counts.

I realized that I have to put some checks in to avoid situations in which the decoy shouldn’t or can’t fly back.
However; I thought I’d keep things minimalistic until I’d addressed the basics of how to save and restore to the “origin”.

As for the underscores. Right again. I have written a lot of reusable modules in other languages.
Using an underscore has avoided namespace clashes on many occasions.
It’s not fool-proof, but it’s a good start.
End-users of modules are less likely to use leading underscores in their object names and the like.

While your code works, it’s very un-idiomatic. The Informish way of accomplishing this isn’t to have things as properties of other things, but rather to use relations and rules to set up this kind of logic:

"Back Home"

A decoy is a kind of thing.

Room-belonging relates one room (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 in (he belongs in, they belong in, he belonged in) implies the reversed container-belonging relation.

[This is necessary because you can't set up a relation pointing from a thing to an object. We could also make a "belong on" relation for supporters, if we wanted to.]

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

Every turn: [You could do this with an every turn rule, or an after rule.]
	repeat with item running through unsecure decoys:
		say "[The item] spreads its wings and flies back to [the home of item].";
		move the item to the home of item.
		
Living room is a room.

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

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 mallard / w / put mallard in box / take duck / drop duck / look / e"

Of course, if it works, it works, but I thought you might want to know the ‘native’ way of doing it.

Thanks, Sequitur. I really appreciate your jumping in. I’ll try this.

Coding style is not something that is well covered, if at all, in the inform7 documentation. I come from an object-oriented background (mostly Ada), but some of the natural language variants still leave me scratching my head as to how to accomplish something the way the interpreter author intended. Wish there was a good forum for collecting articles and examples of proper coding style for inform7. I sure could use a “first place to look” spot.

Thanks, Sequitur. I implemented the “belongs on” rule as well. It all works nicely.
I still need to implement the code for ensuring there is a clear “flight-path”, but I think I have the info to do that.
By using the every turn, the decoy will move even if the path becomes clear after the player has left the room.
So, I’ll have to print the message only if the decoy is visible. That would take care of any closed box case as well.

To test for an open object to home path using “best route from…” resulting in a direction or “nothing”, one appears to need to have a way of obtaining a current location of the decoy specified that is of the same type as the home of the object. The home of the object could be a room, a supporter or a container. If the object is arbitrarily “dropped”, “placed in” or “placed on”, the test may not work, because of a type mismatch and there won’t be a reported error. I suppose one needs to use a containment relationship, but this sounds complicated. So, I’m likely wrong about it.

What is the stylistically correct inform7 way of addressing this?

Can you give an example of code that’s resulting in an error? According to Writing with Inform 6.14, you should be able to use “best route” from any object to any object.

I guess I must be doing something incorrectly, but it does seem as if the way one specifies the item location (current) has to be the same as the home of the item.

"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 home of item 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]'.".
		

[---------------------------------- 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"

Testing yields:

[code]
Mallard v4
An Interactive Fiction by Gary
Release 1 / Serial number 140202 / Inform 7 build 6G60 (I6/v6.32 lib 6/12N) SD

Hallway
You can see a Passage Door and a Hall table (on which is a drake) here.

test me
(Testing.)

[1] take drake
Taken.

[2] w
(first opening the Passage Door)

living room
You can see a Passage Door and a mallard here.

[3] close door
You close the Passage Door.

[4] drop drake
Dropped.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[5] look
living room
You can see a drake, a Passage Door and a mallard here.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[6] open door
You open the Passage Door.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[7] take mallard
Taken.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[8] w

Dining room
You can see a box (in which is a duck) here.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[9] put mallard in box
You put the mallard into the box.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.
The mallard spreads its wings and flies east back to the living room.

[10] look
Dining room
You can see a box (in which is a duck) here.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[11] take duck
Taken.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.

[12] drop duck
Dropped.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.
The duck can’t find the way home to the box, since the indicated direction is “nothing”.

[13] look
Dining room
You can see a duck and a box (empty) here.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.
The duck can’t find the way home to the box, since the indicated direction is “nothing”.

[14] e

living room
You can see a Passage Door, a mallard and a drake here.

The drake can’t find the way home to the Hall table, since the indicated direction is “nothing”.
The duck can’t find the way home to the box, since the indicated direction is “nothing”.

[/code]

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.