Correctly parsing "light light light"

I stumbled across this very old thread the other day:
https://groups.google.com/g/rec.arts.int-fiction/c/ZmSqzhIpSqw/m/y2II_smsIx8J

The original poster in that thread says:

I want to make two lamps, called “the light light” and “the heavy
light”, but I can’t make the parser deal with them correctly. I7 has
no problems being able to handle words which can be both verbs and
nouns, but doesn’t seem to like the same word being used as both a noun
and an adjective.
[…]

I get the this behavior:
>take light light
Which do you mean, the light light or the heavy light?

Even though I explicitly said which one, it is interpreting both
"light"s as (redundant) nouns.

The solution in that thread was to use a parse_name routine on the heavy light, such that it wouldn’t match the heavy light if there were two consecutive instances of the word “light”. However, this doesn’t work in later versions of Inform.

Does anyone know how to get the parser to understand that “take light light” always means the light light, or to correctly parse “light the light light”?

Here’s the code I’m using, slightly modified from the original (I’m still using 6M62):


The Boring Room is a room. The Boring Room is dark.
A light is a kind of device. A light can be lit.
A light light is a light in the Boring Room.
A heavy light is a light in the Boring Room.
The heavy light is switched on and lit.

Before burning a light: instead try switching on the noun.
Carry out switching on a light: now the noun is lit.
Carry out switching off a light: now the noun is unlit.

Test me with "light light / light / light light light".

Include (- Replace LanguageVerbMayBeName; -) before “Language.i6t”

Include (-

[ LanguageVerbMayBeName w;
	if (w == 'long' or 'short' or 'normal' or 'brief' or 'full' or 'verbose' or 'light')
		rtrue;
	rfalse;
];

-) after “Commands” in “Language.i6t”.
1 Like

Im sure many i7 fans will offer solutions, but i’ve always maintained issues like this are down to i7 failure to properly handle adjectives.

For example, you cannot have a “killer whale” and a “whale killer” as different game objects. That is, unless you also put in a whole bunch of workaround hackery. Even then, it’s borderline.

People will say you shouldn’t have a “light light”, but these sort of things come up all the time in games based on comedy wordplay.

3 Likes

Yeah I have to agree, handling such cases does need some extra work:

Especially those understand statements can get quite cumbersome. I would much prefer to only use nouns when sufficient to disambiguate and only look for adjectives otherwise.

1 Like

How about this?

The Boring Room is a room. The Boring Room is dark.
A light is a kind of device. A light can be lit. Understand "light" as a light when the snippet-so-far does not include "light".
A light light is a privately-named light in the Boring Room. Understand "light" as the light light.
A heavy light is a privately-named light in the Boring Room. Understand "heavy" as the heavy light.
The heavy light is switched on and lit.

Before burning a light: instead try switching on the noun.
Carry out switching on a light: now the noun is lit.
Carry out switching off a light: now the noun is unlit.

Test me with "light light / light / light light light".

To decide which snippet is snippet-so-far:
	(- (SnippetSoFar()) -).

Include (-

[ SnippetSoFar ;
	if (wn == match_from)
		return 100;
	else
		return (match_from*100)+(wn-match_from);
];

-).
4 Likes

The I6 solution above does not work by distinguishing nouns from adjectives. It works by distinguishing word order. That’s the feature which I7 dropped in favor of a simpler (but lacking in that one aspect) Understand model.

If you really want I6’s capabilities back, hardwiring an adjective/noun distinction puts you farther from that.

(Otis’s solution looks good although I haven’t tested it.)

2 Likes

That’s a really neat way of creating a parse_name routine from I7 that does what’s required!

For those wondering what I’m rabbitting on about, Understand "light" as a light when the snippet-so-far does not include "light". translates to an I6 parse_name routine that allows the parser to match the word ‘light’ as all or part of a light’s name so long as the word ‘light’ doesn’t appear in the command words already parsed as part of that name.

Therefore ‘light light’ can’t be parsed as the heavy light, because the second ‘light’ won’t be matched, whereas ‘heavy light’ can be parsed as the heavy light because the solitary ‘light’ will be matched.

Conversely, ‘light light’ can be parsed as the light light, because although the second ‘light’ can’t be matched through this ‘Understand…’ phrase, it can still be matched by the separate Understand "light" as the light light. phrase, which matches any occurrence of ‘light’ as all or part of the light light’s name, regardless of position, order or repeats.

1 Like

Thanks, I never would’ve thought of doing it that way!

1 Like

I agree with you that it would be nice if Inform provided a way to distinguish nouns from adjectives. Right now, I can’t write a game with a cup of coffee, a coffee table, and a coffee table book. Or at least, not without a whole bunch of workarounds, as you mentioned.


The Living Room is a room. "Your typical living room. The exit is south."

The coffee-table is a privately-named supporter in the Living Room. The printed name is "coffee table". Understand "coffee","table" as the coffee-table.

The cup is a container on the coffee-table.

 Rule for printing the name of the cup while not inserting or removing:
	if the cup contains coffee, say "cup of coffee";
	otherwise say "empty cup";
	omit contents in listing.

The coffee is in the cup. The indefinite article is "some". 
Check taking the coffee: instead say "You can't hold that."

The block drinking rule does nothing when the noun is the coffee.

Carry out drinking the coffee:
	now the noun is nowhere;
	
Report drinking the coffee:
	say "You gulp down the coffee.";

Understand "cup of [something related by containment]" as the cup.
Check inserting something into the cup: instead say "That won't fit in the cup."
Before drinking the cup: instead try drinking the coffee.

Check drinking the coffee: 
	if the cup is not carried:
		carry out the implicitly taking activity with the cup;
		if the cup is not carried, stop the action.

The coffee table book is on the coffee-table. The description is "You leaf through the book but find nothing interesting." 

The Hallway is south of the Living Room. "A dull room. The living room is north."

Test coffee with "x coffee / get book / x coffee / drop book / x coffee / coffee / cup".
Test table with "x table / get book / x table / drop book / x table".

The parser assumes “table” is the book if I’m holding it and that it means the table if the book is on it. The parser also thinks “coffee” is the book if I’m holding it. There’s no way for a player to use “coffee” on its own and have the parser understand that it’s the cup of coffee that’s being referred to without using workarounds.

Ideally, I’d like “coffee” to refer to the cup of coffee unless the coffee isn’t in scope, in which case it could mean either the book or the table. Similarly, “table” should always mean the coffee table, unless the coffee table isn’t in scope, in which case it would refer to the book.

One way is to write a conditional understand line that tests whether the book or table are visible, but that doesn’t seem to be a great solution to me. I suppose another way is to use DTPM rules, but I’ve never gotten them to do exactly what I want.

2 Likes

Some pointers about name conflicts:

  1. When parsing nouns, the way the parser works is essentially to ask objects whether they match to words, then to decide that the object that matched the most words is the one that the player intended. (EDIT: As zarf points out below, this sentence is misleading. I should have said “the most words in a row” instead. There is a lot of detail being skipped here.)

  2. In cases where more than one object matches the same maximum number of words, it attempts to automatically disambiguate between them based on various rules. Among those rules are checks to see whether objects are carried or in the location, which creates preference over other objects, though which location is better depends on the current action. Invoked by the rules for automatic disambiguation are the does the player mean rules (which have more weight than the automatic scoring rules), but these are used only if there is a tie in word matches. If automatic disambiguation succeeds, the clarifying the parser's choice activity runs to show which object was chosen.

  3. If automatic disambiguation fails, then it uses the asking which do you mean activity to prompt the player for more words and returns to step 1. When asking which do you mean, all previous information about scoring is disregarded.

If you have coffee, a coffee table, and a coffee table book available at the same time, then all three score one point on the word “coffee”. Trying to guess which is the right object is a really difficult situation for the parser, because it lacks context about which objects are suitable for which actions. You can try to give it that context with does the player mean rules, but for certain actions (such as examining) it’s not really possible to craft rules that make sense universally.

There is a use option:

Use unabbreviated object names.

which is described in WWI 3.2 Rooms and the map. It will make the I7 compiler assume that only complete names of objects can be used. This can help when writing your code, but it doesn’t affect the parsing of player commands.

Given the code:

Use unabbreviated object names.

Chapter - Coffee Clash

The Living Room is a room. "Your typical living room. The exit is south."

Section - Coffee Table

The coffee table is a supporter in the Living Room.

Section - Cup

The cup is a container on the coffee table.

 Rule for printing the name of the cup while not inserting or removing:
	if the cup contains coffee, say "cup of coffee";
	otherwise say "empty cup";
	omit contents in listing.

Understand "cup of [something related by containment]" as the cup.
Check inserting something into the cup: instead say "That won't fit in the cup."
Before drinking the cup: instead try drinking the coffee.

Section - Coffee

The coffee is in the cup. The indefinite article is "some". 
Check taking the coffee: instead say "You can't hold that."

The block drinking rule does nothing when the noun is the coffee.

Carry out drinking the coffee:
	now the noun is nowhere;
	
Report drinking the coffee:
	say "You gulp down the coffee.";

Check drinking the coffee: 
	if the cup is not carried:
		carry out the implicitly taking activity with the cup;
		if the cup is not carried, stop the action.

Section - Coffee Table Book

The coffee table book is on the coffee table. The description is "You leaf through the book but find nothing interesting." 

Test coffee with "x coffee / get book / x coffee / drop book / x coffee / coffee / cup" in Living Room.
Test table with "x table / get book / x table / drop book / x table" in Living Room.

Here’s the room description:

Living Room
Your typical living room. The exit is south.

You can see a coffee table (on which are a cup of coffee and a coffee table book) here.

and here’s what you get for >TEST COFFEE:

(Testing.)

>[1] x coffee [coffee table gets preference because it is in the "second best location" (the room) per automatic disambiguation]
(the coffee table)
On the coffee table are a cup of coffee and a coffee table book.

>[2] get book [only one object matching the word "book"]
Taken.

>[3] x coffee [coffee table book gets preference because it is in the "best location" (PC's hands) per automatic disambiguation]
(the coffee table book)
You leaf through the book but find nothing interesting.

>[4] drop book [only one object matching the word "book"]
Dropped.

>[5] x coffee [three objects match the word, and two have the same automatic disambiguation score (table and book, both in the "second best location"), so player is asked which one they mean]
Which do you mean, the coffee table book, the coffee table or the coffee?

>[6] coffee [since all three objects match this word, it does not help to disambiguate]
Which do you mean, the coffee table book, the coffee table or the coffee?

>[7] cup [a little trickier to understand, see below]
I only understood you as far as wanting to examine the cup of coffee.

When the asking which do you mean activity runs, it produces a non-standard prompt state. Any new words entered will be preferentially added to the previous command and another parsing attempt of it will be made, unless the new input looks like a new command by virtue of starting with a recognized verb word. Importantly, the new words are added before the others in the previous command, so given the interaction:

>X SANTA

Which do you mean, the santa hat or Santa Claus?

>HAT

then the parsing will be attempted as though the player had entered >X HAT SANTA.

In your example, the comparable revised command is >X CUP COFFEE COFFEE, which the parser can’t understand as the cup. Although it can understand “cup” as meaning the cup, it needs the word “of” in order to recognize the word “coffee” as being relevant to it.

Similarly for the test table output:

(Testing.)

>[1] x table [both coffee table and coffee table book match the word "table", but only table is in "second best location"]
(the coffee table)
On the coffee table are a cup of coffee and a coffee table book.

>[2] get book [only one object matching the word "book"]
Taken.

>[3] x table [both coffee table and coffee table book match the word "table", but only book is in "best location"]
(the coffee table book)
You leaf through the book but find nothing interesting.

>[4] drop book [only one object matching the word "book"]
Dropped.

>[5] x table [same situation as test coffee command 5]
Which do you mean, the coffee table book or the coffee table?

EDIT: Another helpful feature is the use of Understand... lines with optional words in them:

The coffee table is a privately-named supporter in Living Room. Understand "coffee/-- table" as the coffee table.

This makes it so >X TABLE or >X COFFEE TABLE will match the table, but >X COFFEE will not.

Even more helpful can be making your own tokens (see WWI 17.13 New tokens):

Use unabbreviated object names.

...

The coffee table is a privately-named supporter in Living Room. Understand "coffee/-- table" as "[table designation]". Understand "[table designation]" as the coffee table.

...

The coffee table book is a privately-named thing on the coffee table. The description is "You leaf through the book but find nothing interesting." Understand "book" or "[table designation] book" as the coffee table book.

With that in place your test coffee and test table scenarios might be working the way that you want.

3 Likes

@peach Thanks for this. A most entertaining example of the limitations of the Inform parser. If the parser properly handled adjectives, this would all work as normal.

@maddog

Thanks for the detailed explanation of the parser operation here. And i understand that there are workarounds and fixups that can get around these problems in any given case. However the idea that;

When parsing nouns, … decide that the object that matched the most words is the one that the player intended.

Is basically the wrong way to do it. If you do that, then words that are actually adjectives get as much weight as the nouns. So you’re starting the parse on the wrong foot which will lead to various troubles (as we’ve seen).

It should simply not work this way.

Out of interest, what do all the other IF systems do here? eg TADS?

1 Like

Hang on, that’s not right. An object has to match every player word, or it’s not considered at all!

Nor is there a bias towards objects that get named with the largest number of object words. (This would be a terrible policy, because it would penalize defining objects with a big list of obscure synonyms – words the player might type. Authors love doing that and it should be encouraged.)

DTPM rules are invoked after words have been resolved to objects, so they’re not very good for this sort of thing. (They can’t naturally look at which words the player typed, just at which objects might be involved. You can sort of hack in that capability by messing with snippets and regexes, but eww.)

If you have coffee , a coffee table , and a coffee table book available at the same time…

The way I’d prefer to deal with this… well, the honest answer is “I wouldn’t put those three objects in the same game.” But that aside, I’d want a scoring mechanism at the word-parsing level. This does not exist at all in I6 or I7. (The I6 parse_name routine makes accept/reject decisions; there’s no numeric scoring at that stage.)

Since this would be new territory, it would be rather knotty to come up with a scoring model that didn’t break today’s assumptions! At a minimum, you’d need to be assured that the “naive” model (object has a bag of synonyms, matches every word in the player’s input) always scored the baseline. Author tweaks should build on that.

For this example, I’d say that the coffee-table should score low (not zero!) if the input contains the word “coffee” but not “table”. The coffee-table-book should score low if the input contains “table” but not “book”, and lower if it contains “coffee” or “table” but neither of the others.

I would not look at word order for this case – I don’t think it would solve any real problem. But there are other examples (the famous “pot plant” and “plant pot”) where word order would be worth using.

The problem with this model is that it’s almost impossible to explain – I’ve done a terrible job already. And I haven’t even completely solved the problem. (What’s the score for coffee-table-book if the input is “coffee table”? It’s too early in the morning for me to finish working it all through.) It’s not surprising that Graham didn’t even try to include this sort of thing.

BTW, I entirely agree with this:

One way is to write a conditional understand line that tests whether the book or table are visible, but that doesn’t seem to be a great solution to me.

Scope checks in a parsing routine are a very classic way to bring the Inform parser to its knees. I first saw this way back when Mike Gentry asked why Anchorhead was running so slowly with a certain object in scope.

2 Likes

This is how I’d do it, personally:

A coffee-table is a supporter. Understand "coffee/-- table" as the coffee-table.
On the coffee-table is a cup of coffee.
On the coffee-table is a table-book. Understand "coffee/-- table/-- book" as the table-book.

I believe this gets you the same results as the Infocom parser, which would reject TAKE COFFEE to take the coffee table book, since you didn’t use any nouns. (In “coffee table book”, it’s an adjective.) COFFEE on its own now means only the cup, and you need to use the nouns TABLE or BOOK to refer to the others.

2 Likes

Thank you for pointing out that I was accidentally being misleading there. I’ve edited above.

1 Like

Strongly seconded. Let’s be honest, it doesn’t detract anything from the game to name these three things unambiguously. And then you can just get on with writing and polishing your game rather than inventing and testing tortuous workarounds to bend the parser to your will. This thread is an interesting academic ‘proof of concept’ exploration of how one might approach such a scenario, but it’s something of a rabbit hole when it comes to practical authorship.

As is nearly always the case, the best advice for authors is ‘if you want to finish your game rather than while away the days in intellectual jousting, find a simple way of working with rather than against the grain of whichever authorship system you’re using’.

EDIT: Of course, some do prefer intellectual jousting to writing games, and there’s nothing wrong with that. :wink:

3 Likes

The parser can be changed to work more like Infocom’s through addition of an adjective property – this was done in the Platypus library for I6. I think at this point the bigger challenge would be getting the I7 compiler to make sense of authorial intent. How would you expect to be able to naturally specify which were the adjective words for an object?

I always like the opportunity to point out Draconis’s Subcommands extension, and it offers some easy possibilities for a situation like this:

Include Subcommands by Daniel Stelzer.

Definition: A thing is exactly-matched if its subcommand matches the text its printed name.

Does the player mean doing something to something exactly-matched: it is likely.

Does the player mean doing something to something when the second noun is exactly-matched: it is likely.

Use unabbreviated object names.

A coffee table is here.

On the coffee table is a thing called a coffee table book.

On the coffee table is a cup. In the cup is coffee. The coffee is improper-named. The indefinite article of the coffee is "some".

There will be frequent parser clarification messages, but input using full names will be interpreted correctly so long as the player uses the full object name:

>X COFFEE
(the coffee)
You see nothing special about the coffee.

>X COFFEE TABLE
(the coffee table)
On the coffee table is a cup (in which is some coffee).

>X COFFEE TABLE BOOK
You see nothing special about the coffee table book.

>PUT COFFEE TABLE BOOK ON COFFEE TABLE
(the coffee table)
(first taking the coffee table book)
You put the coffee table book on the coffee table.

EDIT: And if you prefer to suppress the excessive parser clarification messages:

Rule for clarifying the parser's choice of something (called item) when item is exactly-matched:
	do nothing.

Another approach would be to force the author to manually specify which words are adjectives for a given object:

Include Subcommands by Daniel Stelzer.

A thing has a list of text called adjective words.

To decide whether only adjectives were used for (T - thing):
	let comparison text be the substituted form of "[subcommand of T]";
	let N be the number of words in comparison text;
	repeat with wn running from 1 to N:
		if word number wn in comparison text is not listed in adjective words of T:
			decide no;
	decide yes.

Definition: A thing is weakly-named rather than strongly-named if only adjectives were used for it.

Does the player mean doing something to something strongly-named: it is likely.

Does the player mean doing something to something when the second noun is strongly-named: it is likely.

The adjective words of the coffee table are {"coffee"}.

The adjective words of the coffee table book are {"coffee", "table"}.

[same object setup as above]
1 Like

In this case, I get the impression that the OP is going for a wordplay-esque style, so renaming items may cost something from that perspective.

… I’ll just be over there, checking the saddle on my hobby horse.

(That is not to say I don’t agree.)

1 Like

I think most of the attempts at implementing an adjective-noun distinction wind up here: reject some objects entirely for not having enough words. I dislike this. “READ COFFEE” should not respond “You see no such thing” when the coffee table book is in scope.

That said, I did use a similar technique quite a bit in the I6 days – adjusting a parse_name routine to only accept “coffee” or “table” if “book” also appears. It was a practical solution given the I6 parser structure. One of my long-standing gripes about I7 is that it’s now very difficulty to do without hauling word order into it.

(Your solution would reject “TABLE COFFEE BOOK”, or “COFFEE TABLE BIG BOOK” if “big” were also in the synonym list. These are not natural phrasings in English but it seems harsh to reject them when the parser is by default generous about word ordering.) (There’s also issues with the way Inform stitches in disambig responses.)

1 Like

This requires some nuance, mind you. I don’t actually want “GET OF” to match the “cup of coffee”.

(This can be managed in I7: Understand "cup", "cup of", "coffee" as the coffee-cup. Or you could write Understand "cup of/--", "coffee" as the coffee-cup. I use that construction all the time. Relies on word order but in a narrow way which isn’t likely to trip anyone up.)

Now you’re getting into another whole set of pitfalls: unnecessarily restricting synonyms. The “book” part of “coffee table book” could be “volume” or “tome”, right? That’s a completely separate group of synonyms which doesn’t involve any confusion with the coffee or the table. But you’re penalizing the command for using them.

1 Like

Somewhat tangential complaint: one aspect of Inform object disambiguation that has frustrated me for a long time is that the game will tell the player,

Which do you mean, the X or the Y?

in situations where typing X or Y verbatim does not work (brings up a disambiguation prompt yet again). This behavior seems to me unarguably perverse.

1 Like

No, you’re barking up the wrong tree here. “of” should never be part of a name. “of” is part of the grammar and should be parsed as such.

For example, “cup of coffee” is a grammatical phrase. The parser needs to resolve “of” by looking at the world, and what is in cups.

If I drink the coffee and put cherries in the cup, then i have a “cup of cherries” and it should be parsed as such.

1 Like