Weird logic when setting values

So for the ‘Footprints’ challenge over in the ‘Getting Started and General Game Design’ section, I wrote a thing where your muddy dog is tracking muddy pawprints everywhere. The only problem is that the footprints get out of sync with what is actually going on.

I store a From text variable and a To text variable for each room, and every time the dog moves, it updates the From and To for the rooms it moves through. The only problem is sometimes the wrong room names are stored, and rooms that haven’t been moved through recently get their From and To texts changed when they shouldn’t be.

I snagged the base movement code from Example 77 in the Inform Recipe Book, and then bolted on some extra movement and value setting. The dog moves between the rooms fine, it’s just the value storing that’s wonky.

I pulled my problem code into a new project, and after poking at it, I’ve concluded I have no idea what it thinks it’s doing. It should not be doing the things it is doing, so something is clearly broken here (possibly me). My coding style is mostly ‘hit it until it works’, so I am completely out of my depth here. :frowning:

Can someone tell me why my code is behaving the way it is?

[code]Fido is a male animal.

NextSpace is a room that varies. CurrentSpace is a room that varies. FurtherSpace is a room that varies.

A room has text called FromWay. A room has text called ToWay. FromWay is usually “‘Default’”. ToWay is usually “Default’”.

TestingCenter is a room. TestingNorth is north of TestingCenter. TestingEast is east of TestingCenter. TestingSouth is south of TestingCenter. TestingWest is west of TestingCenter. TestingNorth is northwest of TestingEast. TestingEast is northeast of TestingSouth. TestingSouth is southeast of TestingWest. TestingWest is southwest of TestingNorth.

Fido is in TestingCenter.

Every turn (this is the rampaging dog does damn near everything rule):
Now CurrentSpace is location of fido; [dog starts here]
Now NextSpace is a random room which is adjacent to CurrentSpace; [dog will go here]
Now FurtherSpace is a random room which is adjacent to NextSpace; [if player is in NextSpace, dog will continue to here]
say “debug - From [CurrentSpace] (CurrentSpace) to [NextSpace] (NextSpace), or to [FurtherSpace] (FurtherSpace).”;
If fido is visible: [that is, if you and the dog are in ‘CurrentSpace’/the starting room]
say “debug - player and dog began in the same room.”;
say “The dog barks happily and charges off into another part of the house!”;
now the ToWay of CurrentSpace is “[NextSpace]”;
say “debug - ToWay of CurrentSpace ([CurrentSpace]) is [ToWay of CurrentSpace].”;
move fido to NextSpace; [dog runs off to an adjacent room]
now the FromWay of NextSpace is “[CurrentSpace]”;
say “debug - FromWay of NextSpace ([NextSpace]) is [FromWay of NextSpace].”;
If fido is visible: [that is, if you happen to be in the same room that the dog just went to]
say “debug - dog moved to player’s room.”;
say “The dog gallops in from the [CurrentSpace], knocking you over, and continues out the room without even slowing down.”;
now the ToWay of NextSpace is “[FurtherSpace]”;
say “debug - ToWay of NextSpace ([NextSpace]) is [ToWay of NextSpace].”;
move the fido to FurtherSpace; [dog runs off to another room instead of hanging out with you]
now the FromWay of FurtherSpace is “[NextSpace]”;
say “debug - FromWay of FurtherSpace ([FurtherSpace]) is [FromWay of FurtherSpace].”;
say “debug - FromWay of TestingCenter is [FromWay of TestingCenter]/ToWay of TestingCenter is [ToWay of TestingCenter].”;
say “debug - FromWay of TestingNorth is [FromWay of TestingNorth]/ToWay of TestingNorth is [ToWay of TestingNorth].”;
say “debug - FromWay of TestingEast is [FromWay of TestingEast]/ToWay of TestingEast is [ToWay of TestingEast].”;
say “debug - FromWay of TestingSouth is [FromWay of TestingSouth]/ToWay of TestingSouth is [ToWay of TestingSouth].”;
say “debug - FromWay of TestingWest is [FromWay of TestingWest]/ToWay of TestingWest is [ToWay of TestingWest].”.[/code]

When I look at code like this, I usually choose to refactor it rather than debug it. But I think I see the problem:

now the ToWay of CurrentSpace is "[NextSpace]";

Two things:

First, if you want to store the dog’s path through the rooms, you can either store it as rooms or directions. Using text doesn’t really make any sense. (although you would define the property as being an object, so it can hold the “nothing” value by default).

Second, a text is not a fixed string. It is a function for producing a value. “[NextSpace]” is a function that will always print out the current value of NextSpace. If you fix the first problem, you won’t have this problem.

Here’s a slightly refactored version, which eliminates the global variables and puts all the movement tracking into one phrase:

[code]Fido is a male animal.

A room has an object called FromWay. A room has an object called ToWay.

TestingCenter is a room. TestingNorth is north of TestingCenter. TestingEast is east of TestingCenter. TestingSouth is south of TestingCenter. TestingWest is west of TestingCenter. TestingNorth is northwest of TestingEast. TestingEast is northeast of TestingSouth. TestingSouth is southeast of TestingWest. TestingWest is southwest of TestingNorth.

Fido is in TestingCenter.

Every turn (this is the rampaging dog does damn near everything rule):
Let origin be the location of Fido;
Let NextSpace be a random room which is adjacent to origin; [dog will go here]
If Fido is visible:
[player and dog began in the same room]
say “The dog barks happily and charges off into another part of the house!”;
make tracks for NextSpace;
if Fido is visible:
say “The dog gallops in from the [FromWay of the location], knocking you over, and continues out the room without even slowing down.”;
make tracks for a random room that is adjacent to the location.

To make tracks for (destination - an object):
Now FromWay of destination is the location of Fido;
Now ToWay of the location of Fido is destination;
say “DEBUG: Fido going from [location of fido] to [destination].”;
showme FromWay of the location of Fido;
showme ToWay of the location of Fido;
showme FromWay of destination;
showme ToWay of destination;
move fido to destination;

[/code]

Thanks capmikee, that works beautifully.

This is mostly thinking out loud:

I wasn’t aware that you could assign objects to rooms like that. Looking at the kinds index, I just noticed that the room’s region is an object, so I guess it makes sense that for other abstract things, you’d set them to be objects too.

I’ve spent a bit of time trying to wrap my head around your code, and I guess I don’t really get why objects are so different from text. They’re both storing a value…

How was that a bad thing? When I was setting the ToWay of the dog’s location, I wanted the current value of NextSpace.

Or, when I set ToWay to be NextSpace, it will always be the current value of NextSpace, and not remain as what NextSpace happened to be when I set it? That would explain the weirdness that was going on. >.<

If so, that neatly clarifies the difference between objects and text.

One last question - how would I go about setting default values for FromWay and ToWay now? My first room has a tub, I wanted the footprints to show as originating from there. When the ToWay isn’t set yet, checking the footprints reveals that the dog is still in the same room with you.

Would I just have to catch this in the routine that displays the footprints, and display my custom text there?

Technically, yes. But the value of the text is actually a pointer to a function that prints some text. It’s not the text itself. And you only ever set the value to one text: “[NextSpace]”. The value of NextSpace may change, but the value of the text never does, and it’s set to the same thing for every room that the dog has exited.

You got it.

You could set default values, but if you don’t do it explicitly, the default value is “nothing.” You can use that in your code:

if the FromWay of Bathroom is nothing, say "The footprints lead from the bathtub."

If you don’t like the way that looks, write a phrase:

Definition: an object is unset if it is nothing.

Are you sure? What if the dog has been through the room twice?

If the dog has been through a room more than once, then the FromWay and ToWay of that room will be at their most recent dog entrances and exits.
The only reason FromWay would be ‘nothing’ is if the dog never entered that room - either because he hasn’t made it there yet, or because it’s his starting room.
There are two reasons why ToWay could be ‘nothing’ - either the dog hasn’t made it to that room yet, or the dog is there but hasn’t left yet.

I’m not really sure what the ‘object’ ToWay is storing. The name of the room? The room itself? (if it’s the room itself, wouldn’t that get recursive?) So I’m not sure how to change what its default text would be. Would I have to make a room with the text I want as the room name?

This is my first attempt at catching the default values and turning them into the text I want. Unfortunately it’s broken - possibly because I am once again trying to mix two different types of values (text and whatever objects are). I’m not sure, the error messages are making it sound like Inform has no idea what I mean when I set up the temporary variables.
When I have time for a next attempt, I’ll try removing the temporary variables, putting the ‘if FromWay/ToWay is nothing’ checks in the say text itself, and seeing if that works, but it seems convoluted.

Fido is a male animal.

A room has an object called FromWay. A room has an object called ToWay.

TestingCenter is a room. TestingNorth is north of TestingCenter. TestingEast is east of TestingCenter. TestingSouth is south of TestingCenter. TestingWest is west of TestingCenter. TestingNorth is northwest of TestingEast. TestingEast is northeast of TestingSouth. TestingSouth is southeast of TestingWest. TestingWest is southwest of TestingNorth.

Fido is in TestingCenter. The tub is in TestingCenter.

Every turn (this is the rampaging dog rule):
	Let origin be the location of fido;
	increment the muddyness of origin;
	Let NextSpace be a random room which is adjacent to origin; [dog will go here]
	If fido is visible:
		[player and dog began in the same room]
		say "The dog barks happily and charges off into another part of the house!";
	make tracks for NextSpace;
	if fido is visible:
		[dog ends up in player's room]
		say "The dog gallops in from the [FromWay of the location], knocking you over, and continues out the room without even slowing down.";
		make tracks for a random room that is adjacent to the location.
   
To make tracks for (destination - an object):
	Now FromWay of destination is the location of Fido;
	Now ToWay of the location of Fido is destination;
	move fido to destination;
	increment the muddyness of destination.

A room has a number called muddyness. The muddyness of a room is usually 0.

Mud is a backdrop. It is not scenery. It is everywhere. The description of mud is "[MudTrack]".

The printed name of mud is "generic mud description #[muddyness of location]". [I've got a separate 'To say' for this that is not relevant here]

To say MudTrack:
	If FromWay of the location is nothing:
		If location is TestingCenter:
			let from way be "tub";
		Otherwise:
			let from way be "... well, from somewhere";
	Otherwise:
		let from way be "[FromWay of the location]";
	If ToWay of the location is nothing:
		If fido is visible:
			let to way be "... wait, he's right here!";
		Otherwise:
			let to way be "... hmm. He seems to have teleported.";
	Otherwise:
		let to way be "[ToWay of the location]";
	if from way is to way:
		if muddyness of location is greater than 16:
			Say "It's hard to pick out through all the mud, but the freshest tracks seem to come from the [from way] before doubling back the way they came.";
		otherwise if muddyness of location is greater than 8:
			Say "The multiple crossing tracks make it confusing, but you think the most recent tracks are coming from the [from way] before doubling back the way they came.";
		otherwise if muddyness of location is greater than 2:
			Say "The freshest tracks seem to come from the [from way] before doubling back the way they came.";
		otherwise if muddyness of location is greater than 0:
			Say "The muddy tracks come from the [from way] before doubling back the way they came.";
		otherwise:
			If fido is visible:
				Say "Muddy tracks lead from the [from way], heading towards [to way]";
			Otherwise:
				Say "Your dog doesn't seem to have made it to this part of the house yet.";
	otherwise:
		if muddyness of location is greater than 16:
			Say "It's hard to pick out through all the mud, but the freshest tracks seem to come from the [from way], heading towards the [to way].";
		otherwise if muddyness of location is greater than 8:
			Say "The multiple crossing tracks make it confusing, but you think the most recent tracks are coming from the [from way], heading towards the [to way].";
		otherwise if muddyness of location is greater than 2:
			Say "The freshest tracks seem to come from the [from way], heading towards the [to way].";
		otherwise if muddyness of location is greater than 0:
			Say "The muddy tracks seem to come from the [from way], heading towards the [to way].";
		otherwise:
			If fido is visible:
				Say "Muddy tracks lead from the [from way], heading towards [to way]";
			Otherwise:
				Say "Your dog doesn't seem to have made it to this part of the house yet.".

Whoa, that’s a long say phrase! Why not refactor some more?

I suggest you create two say-phrases, “from where” and “to where,” which do all the logic of testing the FromWay and ToWay of the location and then output the correct description directly, without trying to save them in a text variable. You’re just making extra work for yourself.

There’s also a lot of duplicated text there, which is usually a red flag for me that suggests refactoring is needed. Are you familiar with the DRY principle of programming? Don’t repeat yourself!

Here’s an example. I created three phrases for the muddiness of the tracks, the direction they come from, and the way they leave. Then I combine them in a single say-phrase that handles the exceptional case where there are no tracks.

You’ll notice that I never compare a text to a text. I don’t think there’s really a problem with that- I think the problem is that the compiler couldn’t figure out that “to way” was the name of a text variable, and not a phrase definition or some other construct that involves the word “to.” But it seems silly to me to compare variables that are derived from the relevant data, rather than comparing the data themselves.

[code]Fido is a male animal.

A room has an object called FromWay. A room has an object called ToWay.

TestingCenter is a room. TestingNorth is north of TestingCenter. TestingEast is east of TestingCenter. TestingSouth is south of TestingCenter. TestingWest is west of TestingCenter. TestingNorth is northwest of TestingEast. TestingEast is northeast of TestingSouth. TestingSouth is southeast of TestingWest. TestingWest is southwest of TestingNorth.

Fido is in TestingCenter. The tub is in TestingCenter.

Every turn (this is the rampaging dog rule):
Let origin be the location of fido;
increment the muddyness of origin;
Let NextSpace be a random room which is adjacent to origin; [dog will go here]
If fido is visible:
[player and dog began in the same room]
say “The dog barks happily and charges off into another part of the house!”;
make tracks for NextSpace;
if fido is visible:
[dog ends up in player’s room]
say “The dog gallops in from the [FromWay of the location], knocking you over, and continues out the room without even slowing down.”;
make tracks for a random room that is adjacent to the location.

To make tracks for (destination - an object):
Now FromWay of destination is the location of Fido;
Now ToWay of the location of Fido is destination;
move fido to destination;
increment the muddyness of destination.

A room has a number called muddyness. The muddyness of a room is usually 0.

Mud is a backdrop. It is not scenery. It is everywhere. The description of mud is “[MudTrack]”.

The printed name of mud is “generic mud description #[muddyness of location]”. [I’ve got a separate ‘To say’ for this that is not relevant here]

To say from where:
say "from the ";
If FromWay of the location is nothing:
If location is TestingCenter:
say “tub”;
Otherwise:
say “… well, from somewhere”;
otherwise:
say “[FromWay of the location]”

To say heading towards where:
If ToWay of the location is nothing:
If fido is visible:
say “, and here he is!”;
Otherwise:
say “, and don’t go anywhere! He seems to have teleported.”;
otherwise if ToWay of the location is FromWay of the location:
say " before doubling back the way he came.";
Otherwise:
say “, heading towards [ToWay of the location].”;

To say Muddy tracks come:
if muddyness of location is greater than 16:
Say “It’s hard to pick out through all the mud, but the freshest tracks seem to come”;
otherwise if muddyness of location is greater than 8:
Say “The multiple crossing tracks make it confusing, but you think the most recent tracks are coming”;
otherwise if muddyness of location is greater than 2:
Say “The freshest tracks seem to come”;
otherwise if Fido is visible:
Say “Muddy tracks lead”;
otherwise if muddyness of location is greater than 0:
Say “The muddy tracks come”;

To say MudTrack:
if the muddyness of the location is 0 and the location of fido is not the location:
say “Your dog doesn’t seem to have made it to this part of the house yet.”;
otherwise:
say “[Muddy tracks come] [from where][heading towards where]”;
say run paragraph on.
[/code]

By the way, I’ve learned a sneaky little thing about backdrops. You can set their location to a description of rooms, and they will move around based on which rooms fit that description:

[code]Definition: A room is muddy if the muddyness of it is at least 1 or it is the location of Fido.

When play begins: Move the mud backdrop to all muddy rooms.[/code]

You do have to manually update backdrop positions if the muddiness of a room changes, though:

To make tracks for (destination - an object): Now FromWay of destination is the location of Fido; Now ToWay of the location of Fido is destination; move fido to destination; increment the muddyness of destination; update backdrop positions.

This will ensure that you see “You can’t see any such thing” if you try to examine a room that has no tracks in it yet.

Of course you can also achieve the same effect with the “Conditional Backdrops” extension.

I actually had my backdrop doing that. :smiley:

[code]A room can be muddy or clean. A room is usually clean.

Definition: a room is muddy if the Muddyness of the location is greater than 0.[/code]
After every dog movement I would update the location of the backdrop. I wound up commenting that behavior out because I was okay with having the backdrop be everywhere, and I wanted the footprints to be visible in the starting room.
I might put it back in and just set the Bathroom to start at muddyness 1. (This is where the player and dog start in the actual game)

I’ve got an almost non-existent coding background - a tiny amount of visual basic when I was a kid, a little C+ in high school, writing areas for a Smaug MUD I was an immortal in (so many ifchecks!), and that’s it.
I ran across Inform when I saw an article about Playfic, and after I read the documentation I thought “I could totally put my area into this! I’ll just have to whip up a quick combat system first…” (My younger self of last month was so very naive. >.>)
This thing with the footprints is the second project I’ve tacked, and I was so very proud of managing to finish it without having to ask the forums for help. :stuck_out_tongue: Then I discovered my bug.

I hadn’t heard of refactoring before, but it (and the DRY principle of programming) are clearly good things. I’ve never been happy with the way everything get piled into one long function, but I’ve never been sure how to break out pieces. There’s a reason the ‘rampaging dog does damn near everything’ rule was named that.
(Someday I might post my code for my ‘MUD Area to Inform’ project that assigns the player a weapon/armor based on their stats. It’s a page long and horrific.)

Thanks again for looking at this! Your code is so much cleaner!