Disambiguation without unnecessary questions?

If this thread isn’t Inform-specific, then I’ll speak up on Hugo’s behalf as well and explain how it works. Hugo already makes the assumptions suggested.

First, every object has a “parse_rank” property that determines if it gets priority over other, similarly-named objects (you can also redirect actions to this or that object depending on what action is being taken). The default value of an object’s parse_rank is 0, giving them all equal footing. The FindObject routine checks parse_rank values among all possible objects, and the object last referred to gets a +1 so the red box would come out ahead in >PUT BALL IN BOX.

Of course, it also depends on what actions are being taken as some verbs rely on certain factors (are they held? are they unheld? and other stuff). Some of this is set in stone by the grammar definitions. Some of it is nudged along with higher priority parser ranking in FindObject (for example, if the action is OPEN/CLOSE, an unopenable object’s parse ranking is subtracted by one). “>EXAMINE RED BOX. GET BOX. GET BOX.” will result in the player getting both boxes without a disambiguation question.

Hugo’s >PUT OBJECT IN OBJECT grammar, by default, forces the first object to be held, so Hugo would just go with the held red ball in any case. Getting it to even consider unheld items involve using Hugo’s “Checkheld” system which is usually used for stuff like “>THROW BOOK (automatically picking up the book first…) You throw the book.” You then would put in a replacement to the following routine to make an exception for object that does not need to be held.

replace DoPutIn_CheckHeld ! See above re: ImplicitTakeForDrop { if object = water and xobject = goblet return Perform(&DoPutin, water, goblet) else return CallVerbCheckHeld(&DoPutIn, location) }

So, then a combination of the Inform and Hugo approach seems like something to go for? Give each object a likelihood score (parse rank) and use author definable rules per action (does the player mean) to increase or decrease the likelihood score.

Out of curiosity, how would Hugo handle a sentence like

[code]

hit the man with the hammer
You don’t have a hammer.

OR

hit the man with the hammer
What do you want to hit the man with the hammer with?

OR

…[/code]

Yes, Hugo would have this behavior. Trying to refer to characters by their possessions would be incredibly difficult.

Sorry, I realize now that my question was not clear.

The object would be defined as " the man with the hammer" (and probably also as “man”), he does not necessarily carry a hammer. Maybe “man with a mission” would be a better example.

In general, I want to allow object names with syntax , like “hall of fame”, “gallery of paintings”, “jack of all kinds”.

Would your parser try to map to an object, to another object and then link to the action by ? Or would it try to map to one object and perform the action on that object?

I want mine to try both and then go for the one that yields a usable result, if any (usable as in not an “you don’t see that here” message).

Hope this clarifies it.

Hugo really only has a concept of adjectives and nouns. In some of those cases, defining all of the words as adjectives might suffice (since Hugo expects the noun to be listed last). “hall of fame” would need the adjectives “hall” and “fame”, as “of” is defined as a “removal” by hugolib.h (which means it is ignored from parser input).

A good added precaution would be to have the PreParse routine look for applicable phrases and convert them to easier-to-interpret commands. “jack of all trades” could be turned to “jack-of-all-trades”. This is all done “behind the curtain” so the safe word or phrase doesn’t even have to make sense, and it’ll work from the player’s perspective.

Well, sticking purely to evaluating one object at a time has limitations. To go with the example I was trying to construct in Inform, consider this:

Shrine is a room. A blue pedestal is in Shrine. A bust of Venus is on the blue pedestal. A red pedestal is in Shrine. A bust of Cupid is on the red pedestal.

Remember the Understand line

Understand "take [things inside] from [something]" as removing it from.

Inform has a “removing it from” action which in theory can be understood when you type “remove from ,” and which lets you take noun1 so long as it’s in or on noun2. Now I’m going to start talking about how I want the Inform parser to work, as opposed to how it does work.

Let’s say you type:

What should the parser do? Well, it can figure out what “Cupid” is, and there are two possibilities for “pedestal”; but the only one that makes any sense is the red pedestal, because that’s the one that Cupid is on. So it would be good to be able to write a rule that tells the parser to look back, figure out that you’re taking the bust of Cupid, and figure that when you’re taking the bust of Cupid from noun2, it should prefer noun2 to be something that the bust of Cupid is on.

Inform is actually pretty good at figuring out one noun when it knows the other, though this example is currently bugged. But it can’t make a guess when it has to resolve both nouns at once; in this example:

[code]Kitchen is a room.

A fruit is a kind of thing. A lime, a coconut, and an orange are fruits in the Kitchen. Understand “fruit” as a fruit.

Does the player mean inserting the lime into the coconut: it is very likely.

Instead of inserting the lime into the coconut:
say “You put the lime in the coconut and drink them both up.”[/code]

it won’t realize that if you type “put fruit in fruit” then the only combination that makes sense is the lime and the coconut–it won’t be able to guess that you mean the coconut until the player tells it that they meant the lime. (This is terrible authoring, of course, and what Ade said is good advice, but there are times where I feel like you can’t help it–I made a game about making tea that involved a tea cup, tea leaves, a tea strainer, a tea pot, and tea, which each made sense with various actions only in various combinations–you would want to put the tea leaves in the tea strainer, the tea strainer in the tea pot, and the tea in the tea cup.)

The thing is that this might be really difficult to program–for every Understand line and for every Does the Player Mean rule you have to come up with a tentative parsing and then see whether the command can be parsed so as to match that rule. Inform does in a few special cases try to do a lookahead where one noun is parsed in terms of the other noun but from what I’ve been able to tell this involves a lot of extra programming just to deal with this case and is pretty fragile. So I would definitely understand if you just didn’t want to deal with these cases.

I’ll add that Inform does allow you to refer to people by their possessions (I think I put an example of this in the other thread); you can set it so “with ” refers to a person that carries x. This was probably pretty hard to implement.

The blue-sky, resource-unconstrained parser would work something like this:

(1) Create a list of all possible interpretations of the command. This includes all grammar lines and all objects in scope. If there are several colored balls, then TAKE BALL would give <take: red-ball>, <take: green-ball>, etc. If the player has an “inventory sheet”, then TAKE INVENTORY would result two possibilities: , <take: inv-sheet>.

We do not consider world state at this stage, except in deciding scope. (Do not rule out <take: inv-sheet> just because the player already carries the sheet.) If the player is visualizing the wrong world-state, we want our response to explain the mistake.

For conditional object names (“the ball in the box”, “the man wearing the hat”) we ignore the conditional phrase – parse as “the ball”, “the man” with annotations that we’ll consider later. (Same reasoning – we want to be able to explain the mistake.) To stretch a case, PUSH X IN Y could result in <insert-into: X, Y> and <push: X> both being considered.

(2) Sort. Go down the entire list and assign likelihoods. At this stage, we look at conditional phrase annotations and assign a big penalty for the ones that fail. (Any entry including “the man wearing the hat” will go to the bottom of the list if all men in scope are hatless.)

Nothing is eliminated from the list at this stage.

(3) If there’s a single best candidate interpretation, pick it. Done.

(4) If there is a group of equally good candidate interpretations above a threshold, print a disambig query. What threshold? The level where interpretatations are grammatical but don’t match the world state. Depending on the game, there may also be a threshold of commands which match the world state but the protagonist categorically refuses to do.

Printing a query can get messy! If all the entries in the group look like <take: …> then we can use a traditional “Which do you want to take…?” query. But if the group is heterogenous, we’ll have to do something clever. This is where numbered disambiguation starts to look really good.

(5) If the entire list is below your threshold, it’s time to complain. Again, this gets messy. Error messages could look like “Steve isn’t wearing a hat”; “No man here is wearing a hat”; “You’re already carrying the sword”; “That isn’t alive” (the Inform special case for ASK DOOR ABOUT HOMOIOUSIS).

Or maybe, as noted, there could be a threshold range that produces “You refuse to jump off the cliff,” or even “You refuse to jump off any of the cliffs here.”

The above is only a sketch. I haven’t accounted for incomplete commands (TAKE, or PUT SWORD IN). Those could be handled by allowing the parser to assume an implicit ALL at the end of the input.

Here’s an idea for including “You don’t see any such thing” in the model: include an invisible no-such-thing object in scope. It can match any string of words but is considered to have a world-state conditional phrase of (false). So TAKE SWORD will match it and add <take: no-such-thing> to the stage-1 list. But that entry will be sorted to the bottom at stage 2, no matter what. It will only become relevant if we reach stage 5, and then we can print “You don’t see any such thing.”

Further obvious possibilities: treat everything the player has ever seen as in-scope, with world-state conditions about unreachability. Then TAKE SWORD can result in “You left the Elvish sword in the living room.”

This is where it’s important that the model only prints disambig queries for entries above the threshold of could-possibly-work. You don’t want to print “Which do you mean, the Elvish sword that you left in the living room or the broadsword that got melted down in the furnace?”

Also note that TAKE SWORD still matches <take: no-such-thing>, but that’s even farther down the list than <take: elvish-sword>. This is why stage 2 involves only sorting, no elimination.

When you have multiple hits for noun1 and in order to resolve it you need noun2, which also happens to have multiple hits, then that’s an issue. Even worse when resolving noun2 also depends on noun1. In that case we need sort of a trial and error approach

I was thinking about simply trying all possible combinations of hits for noun1 and noun2: iterate through all possible hits for noun2 and in each iteration try all possible hits for noun1. Apply the parsing rules for each combination, assign the scores and hope that one combination wins.

So, for the fruits we would have 9 possibilities, each with initially, say, 10 points

put lime in orange, 10
put coconut in orange, 10
put orange in orange, 10
put lime in coconut, 10
put coconut in coconut, 10
put orange in coconut, 10
put lime in lime, 10
put coconut in lime, 10
put orange in lime, 10

Now we need some parsing rules that the author can enter in your framework :slight_smile:

We can never put something in itself, so

if equal(noun1, noun2) then score(-100)

This gives (sorted):
put lime in orange, 10
put coconut in orange, 10
put lime in coconut, 10
put orange in coconut, 10
put coconut in lime, 10
put orange in lime, 10
put orange in orange, -90
put coconut in coconut, -90
put lime in lime, -90

We can only put something in a container

if testflag(noun2.f_container) then score(+10) if testflag(noun2.f_open) then score(+5) # extra bonus when the container is also open endif endif
This gives:
put lime in coconut, 25
put orange in coconut, 25
put lime in orange, 10
put coconut in orange, 10
put coconut in lime, 10
put orange in lime, 10
put coconut in coconut, -80
put orange in orange, -90
put lime in lime, -90

Now there are 2 winners.
We could add another parsing rule which would rule out the orange

if testflag(noun1.f_in_harry_nilssen_lyrics) and testflag(noun2.f_in_harry_nilssen_lyrics) then score(+5)

If we forget about this last rule then we get:

[code]

put fruit in fruit
What do you want to put in the coconut, the lime or the orange?
lime[/code]

After this point, the scores don’t matter anymore because we have unique hits for noun1 and noun2. If the player would have typed ‘coconut’ instead of lime or orange then ‘put coconut in coconut’ would have been sent to the interpreter which would have thrown an error.

I know a little but about Inform 7 (I dissected the Bronze sources for my project). If you make the coconut a container, wouldn’t Inform be able to figure it out to the level of lime or orange?

For the pedestal and bust scenario I think “take bust from pedestal” is pretty hopeless. Unless we use the Hugo approach and set a flag for the last examined object and hope it’s either a bust or a pedestal.

Options are:
take venus from blue pedestal, 10
take cupid from blue pedestal, 10
take venus from red pedestal, 10
take cupid from red pedestal, 10

Rule1: if testflag(noun2.f_supporter) then score(+5) Rule2: if testflag(noun1.f_takeable) then score(+5) Rule3: if testflag(noun1.f_last_examined) or testflag(noun2.f_last_examined) then score(+1) Rule 4: if contains(noun2, noun1) then score(+5)

After rule 1:
take venus from blue pedestal, 15
take cupid from blue pedestal, 15
take venus from red pedestal, 15
take cupid from red pedestal, 15

After rule 2:
take venus from blue pedestal, 20
take cupid from blue pedestal, 20
take venus from red pedestal, 20
take cupid from red pedestal, 20

Suppose they examined the blue pedestal last, then after rule 3
After rule 3:
take venus from blue pedestal, 16
take cupid from blue pedestal, 16
take venus from red pedestal, 15
take cupid from red pedestal, 15

And after rule 4:
take venus from blue pedestal, 21
take cupid from red pedestal, 20
take cupid from blue pedestal, 16
take venus from red pedestal, 15

But honestly, if I were in the shrine and someone would instruct me to take the bust from the pedestal, I would kindly ask them to be a little more specific…

Well, what should happen for “take bust from pedestal” is that the parser asks “Which do you mean, the bust of Venus or the bust of Cupid?” or “Which do you mean, the red pedestal or the blue pedestal?” And then when you answer, it automatically selects the matching one. And this is what happens currently, although it’s happening for the wrong reasons. I’m pretty sure this has to do with the special parsing that Inform uses for “take… from…”, which is designed to ensure that the player can type “TAKE ALL FROM TABLE” and get all and only the things that are on the table.

I suppose in the new blue-sky parser the parser could ask for entire action names when the actions differ at more than one place. So you would get a tie between taking venus from the blue pedestal and taking cupid from the red pedestal, and the parser could ask “Which do you mean, taking the bust of Venus from the blue pedestal or the bust of Cupid from the red pedestal?”

In cases that don’t involve the removing from action and its weird grammar Inform is doing pretty well, it seems. For instance this:

[code]Stadium is a room. A Yankee fan is a person in Stadium. A Red Sox fan is a person in Stadium.

The player carries a Derek Jeter card and a David Ortiz card.

Instead of showing the Derek Jeter card to the Yankee fan, say “The Yankee fan is impressed.”

Instead of showing the David Ortiz card to the Red Sox fan, say “The Red Sox fan is impressed.”

Does the player mean showing the Derek Jeter card to the Yankee fan: it is very likely.

Does the player mean showing the David Ortiz card to the Red Sox fan: it is very likely.[/code]

yields

(apologies if you’re not a honkbal fan)

–long text warning –

Well, I gave it a try. For who’s interested, below I’ll share some detail on what I did, with an example.

I must give a little background info on my parser. It uses what I call action records. The player’s command line input is translated to an action record with information on the action , actor, objects involved, etc. Ambiguities occurs when the parsers tries to convert user input to an action record. There are 3 candidates for ambiguity: actor, subject and specifier (don’t remember why they are called like that, I made it up some 20 years ago and never changed it).
So in “man, put cube in bowl”: actor = man, subject = cube, specifier = bowl.

I made s ample story with ambiguity.
It’s one room with:

3 Actors:

  • red man with a mission
  • green man with a mission
  • blue man with a mission

5 subjects:

  • red cube
  • green cube
  • blue cube
  • orange cube
  • pink cube

4 specifiers:

  • red bowl
  • green bowl
  • blue bowl
  • orange bowl

From an ambiguity point of view, the worst command possible would be “man, put cube in bowl”. This would give 3x5x4=60 possible combinations. Let’s take this as an example.

Here’s how the parser handles it.

  1. It starts with creating all possible action records (60 in this case). Each action record has a score field that is set to 0.

2.Next, the parser examines the structure of the user command and checks with the appropriate verb if disambiguation rules exist for this structure. In this example it will query the ‘put’ verb for structure “someone, put in ”. If there are no rules, it will skip the next step and go to step 4.

  1. Disambiguation rules have syntax IF THEN score(). Each of the 60 action records is now ran by the rules and if it complies the score field is increased by number. In we can relate actor, subject and specifier, so resolving one can depend on the value of the others. For example, if - for same reason - it is less likely to put the blue cube in the blue bowl, a rule might be defined as :
    IF equal(o_subject, o_blue_cube) AND equal(o_spec, o_blue_bowl) THEN score(-10)
    The 3 action records with blue cube and blue bowl will each get subtracted 10 points.

  2. Now the parser will check if there is one single highest score. If so, this action record will be passed on to the interpreter for execution and the parsing has ended.

  3. If there are more winning action records (e.g. in case of no rules they will all win), the parser will check actor/subject/specifier hits, pick one that is ambiguous and ask the player which one they mean.

  4. Now that the player has resolved 1 ambiguity, the parser will start from point 1 again, but now with less action records.

That’s it.

I considered to print all winning action records as a numbered list of player commands and let the player pick one, but in my personal opinion it would interrupt the game play too much. So I went for the approach to ask the player to resolve one ambiguity and then repeat the whole process with the new information.

Some sample code and output:

We have following disambiguation rules:

[code]“%o_actor, get %o_subject”
disambiguation_rules

it’s less likely to want to get something you already have

if owns(o_actor, o_subject) then score(-5)

end_rules

“%o_actor, drop %o_subject”
disambiguation_rules

it’s more likely to want to drop something that you are carrying

if owns(o_actor, o_subject) then score(5)

end_rules

“%o_actor, put %o_subject in %o_spec”
disambiguation_rules
# it’s more likely to put something that you are carrying
if owns(o_actor, o_subject) then score(5)
# it’s very likely that the blue man wants to put the blue cube in something
if equal(o_actor, o_blue_man) and equal(o_subject, o_blue_cube) then score(25)
end_rules[/code]

Sample output1:

[code]> l
Room

There’s a red man with a mission here.
There’s a blue man with a mission here.
There’s a green man with a mission here.
There’s a red bowl here.
There’s a green bowl here.
There’s a blue bowl here.
There’s an orange bowl here.
There’s a red cube here.
There’s a green cube here.
There’s a blue cube here.
There’s an orange cube here.
There’s a purple cube here.

get cube
Which cube do you mean?
The red cube, the green cube, the blue cube, the orange cube or the purple cube?

red
red cube: taken.

get green cube, orange cube
Green cube: taken.
Orange cube: taken.

i
You are carrying:
a red cube
a green cube
an orange cube

drop cube
Which cube do you mean?
The red cube, the green cube or the orange cube?

orange
orange cube: dropped.

drop cube
Which cube do you mean?
The red cube or the green cube?

red
red cube: dropped.

drop cube
Green cube: dropped.

transcript
Turning off transcript mode.[/code]

Sample output 2:

[code]> l
Room

There’s a red man with a mission here.
There’s a blue man with a mission here.
There’s a green man with a mission here.
There’s a red bowl here.
There’s a green bowl here.
There’s a blue bowl here.
There’s an orange bowl here.
There’s a red cube here.
There’s a green cube here.
There’s a blue cube here.
There’s an orange cube here.
There’s a purple cube here.

red man, get red cube, green cube
Red cube: taken.
Green cube: taken.

red man, put cube in green bowl
Which cube do you mean?
The red cube or the green cube?

red
The red cube is now in the green bowl

red man, put cube in green bowl
The green cube is now in the green bowl

man, put cube in red bowl
[Taking the blue cube first]
The blue cube is now in the red bowl

green man, put cube in bowl
Which cube do you mean?
The blue cube, the red cube, the green cube, the orange cube or the purple cube?

orange cube
Which bowl do you mean?
The red bowl, the green bowl, the blue bowl or the orange bowl?

orange bowl
[Taking the orange cube first]
The orange cube is now in the orange bowl

l
Room

There’s a red man with a mission here.
There’s a blue man with a mission here.
There’s a green man with a mission here.
There’s a red bowl here.
There is a blue cube in the red bowl.
There’s a green bowl here.
There is a red cube in the green bowl.
There is a green cube in the green bowl.
There’s a blue bowl here.
There’s an orange bowl here.
There is an orange cube in the orange bowl.
There’s a purple cube here.

transcript
Turning off transcript mode.[/code]

Thanks for reading!

This is incredibly interesting! If (or when) you have something that a third party can play around with, I’d love to take a look at this stuff.

I really like the part where you narrow things down one ambiguity at a time. Inform processes disambiguation requests by sticking the player’s response back into the original command and reparsing it, which I think often has the same response but which has some other problems.

Also, this works better than the Inform parser when there’s a tie; in Inform, if A, B, and C are possible ways of reading the command, and the does the player mean rules give a tie between A and B, then the disambiguation will still ask the player to choose between A, B, and C.

Sure. Windows versions + docs are ready. I can give you these whenever you want, Linux in a couple of days.

…aw shoot, I use a Mac. Maybe this should inspire me to finally do one of those things that lets me run another system. Anyway, keep us posted about this, I will follow it with interest.

Well, I wrote all source code myself (apart from the Glk libraries for the Glk version). It’s plain C and I use the code::blocks IDE to make builds. So, maybe with cb on a Mac it will build from the source code. I believe there are Glk libraries for the Mac so building a Glk Mac version might work as well.

I’m now working on the no-such-thing object that Zarf mentioned. During testing it came out that I need this.

Here’s test output for the ‘drop cube’ command when you’re not holding any, but they are all on the floor. In that case the parser will ask which one you mean and next the interpreter will tell you you’re not holding the object.

[code]XVAN transcript for: test ambiguities
version: 1.0
Room

look
Room

There’s a red man with a mission here.
There’s a blue man with a mission here.
There’s a green man with a mission here.
There’s a red bowl here.
There’s a green bowl here.
There’s a blue bowl here.
There’s an orange bowl here.
There’s a red cube here.
There’s a green cube here.
There’s a blue cube here.
There’s an orange cube here.
There’s a purple cube here.

i
You are carrying:
Nothing, you are empty-handed.

drop cube
Which cube do you mean?
The red cube, the green cube, the blue cube, the orange cube or the purple cube?

red
One must hold something before it can be dropped…

transcript
Turning off transcript mode.[/code]

Of course it shouldn’t ask which cube, but should say something like you’re not holding a cube or similar message.

I think this is where the no-such-thing object can help out:

  • in step 1 when generating all possible action records, generate 1 extra with no-such-thing.
  • the no-such-thing record gets a default score of 1, the others get 0.
  • now with ‘drop cube’ when not holding any, after applying the disambiguation rules, the no-such-thing record will have won because nobody got their score updated. The rules will assign points when the object is being held.
  • next, the interpreter will get the no-such-thing record from the parser. It should check on this particular value and then print something like ‘you have no such thing to drop’.

I’m building it right now and I’m pretty sure this will work for user input with 1 noun, like get . But what if there are 2 nouns, like attach to and you need to be holding them both?

Why not have the “no such thing”-“no such thing” option start at 1 and then that would win because the other options don’t get updated?

Would this even work where, say, you have to be holding two things and you only are holding one? So if you have the red cube and you “attach cube to cube” then the only option that gets a score above 1 is “attach red cube to no such thing,” which would allow for a message like “You don’t have anything to attach that to.”

Getting it to work for 1 noun was rather easy. 2 nouns was a bit more complicated. Suppose you have noun1 and noun2 and noun2 has 2 hits where noun1 gets no-such-thing. At that point there’s no use asking disambiguation questions about noun2 because we know there will be an upcoming no-such-thing message from noun1.

On the other hand, if noun2 has 1 unique hit and noun1 has no-such-thing, we may want to include noun2 in the error message because the player mentioned it.

So what I did was the following, I have 1 no-such-thing action record with fields for actor, subject and specifier. All 3 fields are initialized with a no-such-thing keyword. When the no-such-thing record is the winner after running the disambiguation rules I check actor, subject and specifier and whenever one has 1 unique hit, I copy that value to the no-such-thing record. So the n-s-t record will have 1, 2 or 3 n-s-t objects when it wins. It does require some additional code in the verb, because it has to check 3 possible n-s-t values to print the most accurate complaint message.

Here’s an output ecample:

[code]> look
Room

There’s a red man with a mission here.
There’s a blue man with a mission here.
There’s a green man with a mission here.
There’s a red bowl here.
There’s a green bowl here.
There’s a blue bowl here.
There’s an orange bowl here.
There’s a red cube here.
There’s a green cube here.
There’s a blue cube here.
There’s an orange cube here.
There’s a purple cube here.

drop cube
You are holding no such thing that can be dropped.

red man, drop cube
The red man with a mission is holding no such thing that can be dropped.

man, drop red cube
No one is holding the red cube.

man, drop cube
No one is holding any such thing.

transcript
Turning off transcript mode.[/code]

And this is what the verb would look like. It checks for 2 no-such-thing values (actor and subject).

[code]VERB drop
“drop”
# code for drop
printcr(“What do you want to drop?”)
getsubject()

“%o_actor, drop %o_subject”
“drop %o_subject”
DISAMBIGUATION_RULES
if owns(o_actor, o_subject) then score(5) endif
END_RULES
# code for drop subject
# nst is no-such-thing object
if equal(o_actor, o_nst) then
print(“No one is holding “)
if equal(o_subject, o_nst) then
print(o_nst.d_any) # any such thing
else
print(”%the %o_subject”)
endif
printcr(“.”)
else
if equal(o_subject, o_nst) then
print(“%the %o_actor “)
print(o_actor.r_to_be)
print(” holding “)
print(o_nst.d_no) # no such thing
printcr(” that can be dropped.”)
else
if (owns(o_actor, o_subject)) then
clearflag(o_subject.f_bypass)
move(o_subject, owner(owner(o_subject)))
print(“%the %o_actor”)
if equal(o_actor, o_player) then
print(" drop “)
else
print(” drops “)
endif
printcr(”%the %o_subject.“)
else
print(”%the %o_actor “)
print(o_actor.r_to_be)
printcr(” not holding the %o_subject.")

DEFAULT
printcr(“I only understood you as far as willing to drop something.”)
ENDVERB[/code]

If we also want to handle input like , put in then there would be a third check on no-such-thing. The verb code grows because of the disambiguation checks, but all verbs are in a separate file that can be re-used for different stories.

I agree with this. I have always thought that the need for disambiguation in a game is a UI shortcoming that indicates a suboptimal design decision, and should be fixed in the way you describe.

Someone might say: “but if in the room that I am imagining there is a red box and a green box, which are otherwise identical, why wouldn’t I have them in the game? Why should I impose such limitations on my creation?” The answer is for the same reason that in a point-and-click adventure game, you wouldn’t generally place an important clickable object behind another so that it’s invisible from the player’s viewpoint. Or for the same reason that you don’t typically get movies whose three main characters are called John, John and John and interact with people that just refer to them as John (unless if this is done specifically for comedic reasons). Because it is pointless to confuse the player, or the viewer, unnecessarily.

Of course, there may be exceptions, you might really need the objects to be similar for expressive reasons - a version of “The Matrix” wouldn’t really click with a red pill and a blue syrup bottle. But even in those cases, I think giving priority to an author-specified object, or just choosing an arbitrary object, is a better solution than asking in the overwhelming majority of the cases. If I am seeing a red box and a blue box and my reaction is to type “open box”, probably I just want to open any of them because any will do, or I plan to open the other one later anyway. If I really wanted to open the red box, I would have typed “open the red box” from the get go.

In fact, I struggle to remember any situation where I found a disambiguation question actually helpful as a player. Normally I just find them due to some serious design problem (e.g. the descriptions mention only one box, but there are actually two, and you find about the second one from the disambiguation question) and I find them to be an annoyance.