Help with Differentiating Between Identical Objects in Different Locations

Hi! Relatively new to Inform 7, and I’ve been having an issue with the way Inform treats identical objects. Any solutions or workarounds would be much appreciated!

I have a scale set that I want the player to be able to move blocks around on, with three kinds of blocks - small, medium, and large - which weigh different amounts. I have it so that the scale set will lean left or right, depending on which side has more weight. The scale set is a thing, and the left side and the right side are supporters which are part of the scale set. Part of the puzzle is that the player can’t take blocks, they can only “vanish” and “unvanish” them, which are actions I wrote myself.

The problem is with being unable to distinguish between the blocks. Typing “vanish large block” vanishes the block from the left side without asking the player for clarification, presumably because the left block was created first and Inform doesn’t see any use in differentiating between two identical objects. However, as long as they’re in different places, which object does matter. I’ve been able to get it to accept “vanish left large block” and “vanish right large block”, but what I’d really like is for it to respond to “vanish large block” with something as complex as “Which do you mean, a large block from the left side, the large block from the right side, or the large block from your inventory?” or at least not assume the player means any one of them. Similarly, I’d like it to differentiate between locations with blocks of the same size when the player types “vanish block”, where it currently only differentiates between size and not the locations. I tried giving them unique object names and the same printed names, but it still grouped them. I haven’t found a way to get it to ask “which do you mean” when it wasn’t already, and I’m not even sure how that would work.

Here is my code:

The scale set is a fixed in place thing on the plain wooden table. Understand "scales", "set of scales" as the scale set.
A side is a kind of supporter. The left side, the right side are sides. The left side, the right side are part of the scale set. The left side, the right side have a number called the sum.
Understand "tilt [scale set]", "tilt [side]", "push on/-- [scale set]", "push on/-- [side]", "pull on/-- [scale set]", "pull on/-- [side]" as a mistake ("You try, but the scales seem magically locked in place.").
A block is a kind of thing. A block has a number called weight. A block has some text called size. A large block is a kind of block. The weight of a large block is always 3. The size of a large block is always "large". A medium block is a kind of block. Weight is always 2. Size is always "medium". A small block is a kind of block. Weight is always 1. Size is always "small".
Instead of taking a block which is on a side: say "You try, but it can't seem to budge from the scale."
There is a small block and two medium blocks on the left side. There are three large blocks on the right side.

This part will print “large block from the left side” when asking which do you mean between multiple sizes of blocks, but then will neglect to mention any large blocks that might be on the right side:

After printing the name of a block (called the block) while asking which do you mean:
	if the block is carried by the player:
		say " from your inventory";
	else if the block is on a supporter (called the supporter):
		say " from the [supporter]";
	else if the block is in a container (called the container):
		say " from the [container]";
	else:
		say " from the ground".
Understand "left" as a block when the item described is on the left side. Understand "right" as a block when the item described is on the right side. Understand "inventory" as a block when the item described is carried by the player. Understand "floor/dropped large/medium/small/big/-- block" as a block when the item described is not enclosed by anything.

Thanks for any insight!

3 Likes

Oh wow, this is a very tricky conundrum you’ve found yourself in – distinguishing identical objects is a pain point for Inform, triggering a disambiguation question isn’t something that’s at all easy to do, and even clarifying things for the player might not clarify things for the parser (like, your rule can lead to disambiguation prompts like “Which do you mean, the left side, the small block from the left side or a medium block from the left side?”, but the player types SMALL BLOCK FROM THE LEFT SIDE in reply, the parser won’t understand.

Rather than try to hack through this thicket, I think you’re probably better off trying to catch ambiguous commands with something like an understand as a mistake rule that flat-out tells the player “if there’s more than one large block on the pans, you need to type VANISH LEFT LARGE BLOCK” or what have you.

I don’t have more time to mess around with Inform now, but in a couple hours if no one smarter has come up with a better idea I might be able to hack an example for that approach together.

2 Likes

Welcome!

Thank your for this exercise :slight_smile:.

Well, I am a beginner too. I worked on your problem (and I must go to bed…). My little experiment, if it could help:

Lab is a room.

The plain wooden table is in Lab.
The scale set is fixed in place.
The scale set is on the plain wooden table. Understand "scales", "set of scales" as the scale set.

The scale set is a fixed in place thing on the plain wooden table. Understand "scales", "set of scales" as the scale set.

A side is a kind of supporter. The left side and the right side are sides. The left side and the right side are part of the scale set.

A block is a kind of thing. A block has a number called weight. A block has some text called size. 

The small block is a block. The weight of the small block is 1. The size of the small block is "small". The small block is on the left side.

The medium block 1 is a block. The weight of the medium block 1 is 2. The size of the medium block 1 is "medium". The medium block 1 is on the left side.

The medium block 2 is a block. The weight of the medium block 2 is 3. The size of the medium block 2 is "medium". The medium block 2 is on the left side.

The large block 1 is a block. The weight of the large block 1 is 4. The size of the large block 1 is "large". The large block 1 is on the right side.

The large block 2 is a block. The weight of the large block 2 is 6. The size of the large block 2 is "large". The large block 2 is on the right side.

The large block 3 is a block. The weight of the large block 3 is 9. The size of the large block 3 is "large". The large block 3 is on the right side.

To decide which text is the block description of (B - a block):
	if B is on the left side, decide on "left [size of B] block, weight [weight of B]";
	if B is on the right side, decide on "right [size of B] block, weight [weight of B]";
	if B is carried by the player, decide on "[size of B] block from your inventory (weight: [weight of B])";
	decide on "[size of B] block".

After printing the name of a block (called B) while asking which do you mean:
	say " ([block description of B]) ".

Understand "left [block]" as a block when the item described is on the left side.
Understand "right [block]" as a block when the item described is on the right side.

Understand "vanish [block]" as vanishing. Vanishing is an action applying to one visible thing.
Carry out vanishing:
	if the noun is on the left side or the noun is on the right side:
		say "[The noun] vanishes in a puff of smoke.";
		now the noun is off-stage;
	otherwise:
		say "[The noun] is not here to vanish."

Results:

Lab
You can see a plain wooden table (on which is a scale set) here.

>vanish block
Which do you mean, the small block (left small block, weight 1) , the medium block 1 (left medium block, weight 2) , the medium block 2 (left medium block, weight 3) , the large block 1 (right large block, weight 4) , the large block 2 (right large block, weight 6)  or the large block 3 (right large block, weight 9) ?

>large
Which do you mean, the large block 1 (right large block, weight 4) , the large block 2 (right large block, weight 6)  or the large block 3 (right large block, weight 9) ?

>large block 2
The large block 2 vanishes in a puff of smoke.

>vanish block
Which do you mean, the small block (left small block, weight 1) , the medium block 1 (left medium block, weight 2) , the medium block 2 (left medium block, weight 3) , the large block 1 (right large block, weight 4)  or the large block 3 (right large block, weight 9) ?

I hope this will help you, I am not sure, because I struggled to understand your target. But do not worry, @DeusIrae is very smart and very kind :wink: .

1 Like

Another version using duplicates:

Lab is a room.

The plain wooden table is in Lab.
The scale set is fixed in place.
The scale set is on the plain wooden table. Understand "scales", "set of scales" as the scale set.

The scale set is a fixed in place thing on the plain wooden table. Understand "scales", "set of scales" as the scale set.

A side is a kind of supporter. The left side and the right side are sides. The left side and the right side are part of the scale set.

A block is a kind of thing. A block has a number called weight. A block has some text called size.

A small block  is a kind of block.
The weight of a small block is  usually 1. 
The size of the small block is usually "small".

A medium block  is a kind of block.
The weight of a medium block is usually 2. 
The size of the medium block is usually "medium".

A large block  is a kind of block.
The weight of a large block is usually 3. 
The size of the large block is usually "large".

There is 1 small block on the left side.
There are 2 medium blocks on the left side.
There are 3 large blocks on the right side.

Understand "vanish [block]" as vanishing. Vanishing is an action applying to one visible thing.
Carry out vanishing:
	if the noun is on the left side or the noun is on the right side:
		say "[The noun] vanishes in a puff of smoke.";
		now the noun is off-stage;
	otherwise:
		say "[The noun] is not here to vanish."

Results:

Lab
You can see a plain wooden table (on which is a scale set) here.

>examine left side
On the left side are a small block and two medium blocks.

>examine right side
On the right side are three large blocks.

>vanish block
Which do you mean, the small block, a medium block or a large block?

>medium
The medium block vanishes in a puff of smoke.

>examine left side
On the left side are a small block and a medium block.

>vanish block
Which do you mean, the small block, the medium block or a large block?

>large
The large block vanishes in a puff of smoke.

>examine right side
On the right side are two large blocks.

>vanish block
Which do you mean, the small block, the medium block or a large block?

>

I can’t test this at the moment, but what about…

After printing the name of a block (called the item) when asking which do you mean:
    if the item is on a supporter (called the holder):
         say " on [the holder]";
    otherwise if the item is in a container (called the holder):
        say " in [the holder]".

Understand "on [something related by reversed support]" as a block.
Understand "in [something related by reversed containment]" as a block.

As DeusIrae indicates, you have pointed yourself at a fairly thorny problem. Congratulations! (Also, welcome.)

To get what you seem to want requires a lot of fakery and/or deep surgery, and is much easier to deal with when you’ve gotten farther than you seem to have based on your code snippet (though I do applaud the inventiveness shown so far).

Here’s something that I slapped together that might approach what you want in most cases, but is mostly fakery and workarounds.

Pain Points Aplenty
The scale set is a fixed in place thing on the plain wooden table. Understand "scales", "set of scales" as the scale set.

A side is a kind of supporter. The left side, the right side are sides. The left side, the right side are part of the scale set. The left side, the right side have a number called the sum.

Does the player mean putting a block on a side: it is likely. [You might need more of these or something sturdier.]

Size is a kind of value. The sizes are small, medium and large. [Nameless properties are another option instead of subkinds.]

A block is a kind of thing.  A block has a number called weight. The verb to weigh means the weight property. A block has a size. Understand the size property as describing a block.

Before printing the name of a block: say "[size] ".

A block has some text called current location. Understand the current location property as describing a block.

Every turn (this is the update block loc text rule):
	repeat with B running through visible blocks: [the main purpose here is to support distinguishing blocks; understanding a locational phrase is a side effect --understanding-by-relation isn't taken into account for distinguishing]
		now the current location of B is the substituted form of "[if B is in a container or B is carried by the player]in[otherwise ]on[end if] [if the B is in a room]the floor[otherwise if B is carried by the player]your inventory[otherwise][the holder of B][end if]".

When play begins:
	follow the update block loc text rule;
	now every large block weighs 3; [not elegant to assign weights this way, but works]
	now every medium block weighs 2;
	now every small block weighs 1.

[Instead of taking a block which is on a side:
	say "You try, but it can't seem to budge from the scale."] [disabled for my testing]

There is a small block and two medium blocks on the left side. There are three large blocks on the right side.

After printing the name of a block (called the block) while asking which do you mean:
	if the block is carried by the player:
		say " from your inventory";
	else if the block is on a supporter (called the supporter):
		say " from the [supporter]";
	else if the block is in a container (called the container):
		say " from the [container]";
	else:
		say " from the floor".

After printing the name of a block while the clarifying the parser's choice activity is going on:
	say " [current location]".

Understand "on/from/-- [something related by reversed support]" as a block when the item described is on a supporter. Understand "in/from/-- [something related by reversed containment]" as a block when the item described is in a container. Understand "from/in my/-- inventory" as a block when the item described is carried by the player. Understand "on/from/-- the/-- floor/ground" or "dropped" as a block when the item described is in a room. ["in a room" not the same as "enclosed by a room"]

If that doesn’t work for you, then maybe you can supply a sample transcript of ideal interaction.

1 Like

Properties are the best way to get the disambiguation distinction needed (except hacking “Identical”). Try this.

"Test"

Include (-

[ ScoreMatchL context its_owner its_score obj i j threshold met a_s l_s;
	if (indef_type & MY_BIT ~= 0)    threshold++;
	if (indef_type & THAT_BIT ~= 0)  threshold++;
	if (indef_type & LIT_BIT ~= 0)   threshold++;
	if (indef_type & UNLIT_BIT ~= 0) threshold++;
	if (indef_owner ~= nothing)      threshold++;

	#Ifdef DEBUG;
	if (parser_trace >= 4) print "   Scoring match list: indef mode ", indef_mode, " type ",
		indef_type, ", satisfying ", threshold, " requirements:^";
	#Endif; ! DEBUG

	for (i=0 : i<number_matched : i++) {
		obj = match_list-->i; its_owner = parent(obj); its_score=0; met=0;
		if (indef_type & MY_BIT ~= 0 && its_owner == actor) met++;
		if (indef_type & THAT_BIT ~= 0 && its_owner == actors_location) met++;
		if (indef_type & LIT_BIT ~= 0 && obj has light) met++;
		if (indef_type & UNLIT_BIT ~= 0 && obj hasnt light) met++;
		if (indef_owner ~= 0 && ((its_owner == indef_owner) || (CoreOf(obj) == indef_owner))) met++;
		if (met < threshold) {
			#Ifdef DEBUG;
			if (parser_trace >= 4)
				print "   ", (The) match_list-->i, " (", match_list-->i, ") in ",
					(the) its_owner, " is rejected (doesn't match descriptors)^";
			#Endif; ! DEBUG
			match_list-->i = -1;
		}
		else {
			its_score = 0;
			if (obj hasnt concealed) its_score = SCORE__UNCONCEALED;

			if (its_owner ~= Compass) its_score = its_score + SCORE__NOTCOMPASS;

			its_score = its_score + SCORE__CHOOSEOBJ * ChooseObjects(obj, 2);

			if (obj hasnt scenery) its_score = its_score + SCORE__NOTSCENERY;
			if (obj ~= actor) its_score = its_score + SCORE__NOTACTOR;

			! A small bonus for having the correct GNA,
			! for sorting out ambiguous articles and the like.

			if (indef_cases & (PowersOfTwo_TB-->(GetGNAOfObject(obj))))
				its_score = its_score + SCORE__GNA;

			match_scores-->i = match_scores-->i + its_score;
			#Ifdef DEBUG;
			if (parser_trace >= 4) print "     ", (The) match_list-->i,
				" in ", (the) its_owner, " : ", match_scores-->i, " points^";
			#Endif; ! DEBUG
		}
	}

	for (i=0 : i<number_matched : i++) {
		while (match_list-->i == -1) {
			if (i == number_matched-1) { number_matched--; break; }
			for (j=i : j<number_matched-1 : j++) {
				match_list-->j = match_list-->(j+1);
				match_scores-->j = match_scores-->(j+1);
			}
			number_matched--;
		}
	}
];

-) replacing "ScoreMatchL".

Vanishing is an action applying to one thing. Understand "Vanish [block]" as vanishing.

Carry out vanishing (this is the carry out vanishing rule):
move the noun to the player;
now the noun is inventory.

Report vanishing (this is the report vanishing rule): say "You vanish [the noun].".

Unvanishing is an action applying to one thing. Understand "Unvanish [block]" as unvanishing.

Carry out unvanishing (this is the carry out unvanishing rule):
move the noun to the scale set;
if a random chance of 1 in 2 succeeds begin;
now the noun is right;
otherwise;
now the noun is left;
end if.

Report unvanishing (this is the report unvanishing rule): say "You unvanish [the noun].".

To decide what number is the weight of (the chosen block - a block):
if the chosen block is large begin;
decide on 3;
otherwise if the chosen block is medium;
decide on 2;
otherwise if the chosen block is small;
decide on 1;
otherwise;
decide on 0;
end if.

To say wobbling:
let the left count be zero;
let the right count be zero;
repeat with the chosen block running through blocks on the scale set begin;
if the chosen block is right begin;
increase the right count by the weight of the chosen block;
otherwise if the chosen block is left;
increase the left count by the weight of the chosen block;
otherwise;
say "WOBBLY OUCH !!";
end if;
end repeat;
if the left count is greater than the right count begin;
say "tilting to the left";
otherwise if the right count is greater than the left count;
say "tilting to the right";
otherwise;
say "perfectly balanced";
end if.

A block is a kind of thing. A block is either inventory, left or right (this is its block place). A block is either small, medium or large (this is its block size).

Understand "on the" and "side" as a left block. Understand "on the" and "side" as a right block. Understand "from your" as an inventory block.

Understand the block place property as describing a block. Understand the block size property as describing a block.

Before printing the name of a block (called the chosen block) (this is the print block size rule): say "[block size of the chosen block] ".

Before printing the plural name of a block (called the chosen block) (this is the print plural block size rule): say "[block size of the chosen block] ".

After printing the name of a left block (called the chosen block) (this is the print left side rule): say " on the left side".

After printing the name of a right block (called the chosen block) (this is the print right side rule): say " on the right side".

After printing the name of an inventory block (called the chosen block) while asking which do you mean (this is the print inventory side rule): say " from your inventory".

After printing the plural name of a left block (called the chosen block) (this is the print plural left side rule): say " on the left side".

After printing the plural name of a right block (called the chosen block) (this is the print plural right side rule): say " on the right side".

After printing the plural name of an inventory block (called the chosen block) while asking which do you mean (this is the print plural inventory side rule): say " from your inventory".

Check taking a block (this is the can't take blocks rule): say "You try, but it can't seem to budge from the scale." instead.

The Testing Room is A Room. The plain wooden table is a scenery supporter in the testing room. The scale set is a fixed in place supporter on the plain wooden table. The description of the scale set is "The scales are [wobbling].". Understand "scales" and "set of scales" as the scale set.

There is 1 small left block on the scale set. There are 2 medium left blocks on the scale set. There are 3 large right blocks on the scale set.	

Test me with "x scales / vanish large block / vanish large block / right / vanish large block / right / x scales / i / x block / inventory / vanish medium block / vanish medium block / left / vanish small block / x scales / i / x block / small block from your inventory".

I’ve gone for a simpler approach where the block go in the scales and the side that they’re on is decided solely by the side property. That way you don’t’ve to worry as much about keeping the side and the property in sync. I’ve also included “inventory” for when the block is in your inventory. More options can easily be added. I’m not sure how you’re planning to move blocks in and out of the player’s inventory so I’ve used the vanishing and unvanishing actions to do that for the example. They can be changed accordingly.

Hope this helps!

Thank you all so much! I’ve been working with Mad Scientist’s suggestion and have been able to tweak it to work the way I want it to! Plus this taught me lots of syntax :slight_smile: Have a lovely day!