Problem with similarly-named nouns

I’m having a little trouble with the following code. Despite specifying that “phone” should be understood as the payphone, “take phone” will inevitably result in “>take phone (the phone booth).” I wouldn’t mind if this only happened when the phone booth was closed and/or the player was outside it (making that the more likely interpretation), but the “understand” code simply seems to have no effect under any circumstances.

The phone booth is a transparent closed openable enterable container in Demerara_and_Maple. It is fixed in place.
The description of the phone booth is "A typical phone booth in a typical poor state of repair. There's a payphone inside."
Before entering the phone booth when the phone booth is closed, try opening the phone booth.
Instead of smelling the phone booth, say "It smells of pee. Regrettably, you have a pretty good idea why."
Instead of tasting the phone booth, say "That would be frightfully unsanitary."
Instead of taking the phone booth, say "Pick up the phone booth? And die???"

The payphone is in the phone booth.
Understand "phone" as the payphone.
It is undescribed.
The description of the payphone is "A chunky yellow handset resting on a chunky metal keypad."
Instead of taking the payphone, say "It might be a phone, but it's far from mobile."
Instead of inserting the quarter into the phone booth, try inserting the quarter into the payphone.
Instead of inserting the quarter into the payphone, say "Why? You don't need to make a call."
Does the player mean taking the payphone: it is likely.

The handset is part of the payphone.
The description of the handset is "Cellular, modular, interactivodular this thing sure isn't."
Instead of tasting the handset, say "Ring, ring, ring, ring, ring, ring, ring, banana flavour."
Instead of taking the phone, try taking the handset. Instead of taking the handset, say "It isn't ringing, so there's no need to pick it up."
Does the player mean taking the handset: it is likely.

A little searching around here suggests that the simplest solution would be to rename the objects to have less overlap between them, but “payphone” and “phone booth” both feel like natural choices: I’m not sure there are any neat alternatives that won’t include “phone” in both of them.

In any case, I’d find it useful in general to have a way to genuinely make one particular word understood as one particular noun. I expect I could be a bit firmer with that “does the player mean…” rule, or add one to make the booth less likely where the command doesn’t specifically include the word “booth,” but I don’t want to go too far and redirect genuine attempts to take the phone booth. Really what I’d like is for “Understand ‘X’ as the Y” to behave as expected. Is there something I’m doing wrong with it, or is there some other reasonably elegant approach that would achieve the result I’m looking for?

The problem here is that, when Inform sees only a single best match for the noun you typed, it chooses it automatically instead of disambiguating. And in this case, the phone booth is in the location (a plus), and not portable (a minus), and the payphone is not portable (a minus), and undescribed (a huge minus), and gets a “does the player mean” bonus (an even bigger plus)…and in the end, it seems the phone booth is winning.

But the “does the player mean” bonus is designed to override everything else (it works in multiples of 1000, while everything else is 100 or less), so I’m surprised it’s not here. Can you turn on tracing (the “TRACE [number]” command in the game), then try TAKE PHONE again? I think you need tracing level 3 for this, but I’m afraid I don’t remember off the top of my head.

1 Like

For reference, here are the weights.

2 Likes

Inform really does not support this idea. Inform is built with the assumption that you might always add a completely new room with completely new objects. A “phone” in that room should behave normally. If you created a global restriction such that the word “phone” only referred to the first phone, then all future phones would break, even if they were in separated areas (or separate chapters).

In this situation, you might write

The phone-booth is a transparent closed openable enterable container...
Understand "phonebooth", "phone booth", "booth" as the phone-booth.

Now “phone” by itself cannot refer to the booth. Which might be what you want, or not.

2 Likes

just curious - i don’t know inform 7 at all but i’d heard there was some way to drop back into I6 within I7 code? is it possible to use a parse_name property within I7?

parse_name is unfortunately very difficult to get into. I think I worked out how to do it once, but not for the current version of I7.

Yeah, you can write GPRs in I6 and assign them to I7 Understand tokens (the bracketed bits like [something] in an Understand line), which gets you most of the way to a parse_name, but it’s not quite the same because you can’t reference self. Anything self-related has to be done on the I7 level.

The simple solution is to make the phone booth privately-named and require that the word “phone” be used as part of the phrase “phone booth.”

The phone booth is privately-named. Understand "phone/-- booth" as the phone booth.

I can, but I have to admit I have no idea what the output means or how I’d ever find out. The Inform documentation doesn’t exactly give a lot to go on. If you can make sense of this, though, I’d be very happy to know more!

>trace 3
[Parser tracing set to level 3.]
 
>take phone
[ "take" take / "phone" phone ]
[Parsing for the verb 'take' (6 lines)]
 
[line 0 * 'inventory' -> Inv]
[line rejected for not ending with correct preposition]
 
[line 1 * multi -> Take]
 [line 1 token 1 word 2 : multi]
  [Object list from word 2]
  [Calling NounDomain on location and actor]
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 1 Pass 2: 1 Pass 3: 1
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
  [ND returned the phone booth]
  [token resulted in success]
 [line 1 token 2 word 3 : END]
[Line successfully parsed]
(the phone booth)
Pick up the phone booth? And die???

Thank you! When it comes to getting the parser to match “phone” to “payphone” specifically, this is just the solution I was looking for.

In case it’s any help to anyone else in the same situation, @Draconis’ response also steered me towards changing the payphone to be no longer undescribed. This seems to allow “phone” to be understood based on context when the phone booth is named “phone booth”:

>take phone
(the payphone)
The phone booth isn't open.
 
>open phone
(the phone booth)
You open the phone booth.
 
>take phone
(the payphone)
It might be a phone, but it's far from mobile.

I feel as though it’s probably good to offer players that flexibility even though I probably wouldn’t use “phone” to refer to the phone booth myself.

In terms of the rationale for “understand,” though, I still really don’t like that this results in the modern search engine scenario of stuff I explicitly type in being treated as only the loosest of suggestions. If I’d written “understand ‘phone’ as the payphone” and it broke some other phone I added later, the problem I’d created would be trivial to diagnose. As it is, the parser latches onto “phone booth” as the best match for “phone” despite the game including a line much the same as the “Understand ‘dog’ as the St Bernard” example in the documentation, and it’s not at all obvious why. In hindsight I see why the parser might guess the player is referring to a described object over an undescribed one, but I feel as though a guess shouldn’t take precedence over an explicit instruction.

The short answer is that “undescribed” is deliberately undocumented (or did they add it and just discourage its use now?) because it’s needed to make a couple things in the Standard Library work, and that’s why it has the side effects you’re seeing. The one place it’s used by default is on the player object, so from the library’s perspective this is a feature, not a bug—it’s meant to prevent X PERSON or TALK TO PERSON or GIVE PARROT TO PERSON from asking “which person do you mean, Alice or yourself?”, even if you explicitly say to understand “person” as a person.

It might be useful in the future to remove this behavior from “undescribed” and attach it to the player object specifically, but since the only place “undescribed” is normally used is on the player, it hasn’t been considered a high priority.

Ugh, I misremembered, sorry—it looks like TRACE 3 doesn’t give enough detail still! Try TRACE 5? One of these levels shows what “score” the parser assigned to each object within the NounDomain call (that’s what “ND returned the phone booth” is short for), and that’s what we need here.

But if removing undescribed is the culprit, then the trace output would just tell us the same thing. In that case, using a more extreme “does the player mean” outcome can also override it.

2 Likes

Having already made several small tweaks I don’t think I can check exactly what was going on originally, but in the current version (with the payphone no longer undescribed) I get:

>take phone
[ "take" take / "phone" phone ]
[Parsing for the verb 'take' (6 lines)]
 
[line 0 * 'inventory' -> Inv]
[line rejected for not ending with correct preposition]
 
[line 1 * multi -> Take]
 [line 1 token 1 word 2 : multi]
  [Object list from word 2]
  [Calling NounDomain on location and actor]
   [NounDomain called at word 2 (domain1 Demerara and Maple, domain2 yourself)
   seeking definite object
    Trying the north at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the northeast at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the northwest at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the south at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the southeast at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the southwest at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the east at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the west at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the up at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the down at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the inside at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the outside at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying yourself at word 2
    Trying the phone booth at word 2
Parse_name called
Pass 1: 1 Pass 2: 1 Pass 3: 1
    Matched (1)
    Trying the payphone at word 2
Parse_name called
Pass 1: 1 Pass 2: 1 Pass 3: 1
    Matched (1)
    Trying the handset at word 2
    Trying the keypad at word 2
    Trying the fedora at word 2
    Trying the trench coat at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the car key at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying hi top trainers at word 2
Parse_name called
Pass 1: 0 Pass 2: 0 Pass 3: 0
    Trying the watch at word 2
   [ND made 2 matches]
   [Adjudicating match list of size 2 in context 2
   definite object
   Scoring match list: indef mode 0 type 0, satisfying 0 requirements:
 
     The phone booth in Demerara and Maple : 3176 points
 
     The payphone in the phone booth : 4136 points
   Single best-scoring object returned.]
  [ND returned the payphone]
  [token resulted in success]
 [line 1 token 2 word 3 : END]
[Line successfully parsed]
(the payphone)
The phone booth isn't open.

If I make the payphone undescribed once more, no point values are ever compared: the parser simply doesn’t seem to consider the payphone a contender.

Aha! Okay, that’s useful. I suppose undescribed objects are getting ruled out at an earlier stage than the point-counting system.

Yep, that’s what’s happening. This is happening in Adjudicate before it gets to ScoreMatchL. The first section of this routine looks at how many obvious candidates there are, and if there’s only one, it doesn’t do any further analysis.

It counts up the number of obvious choices for the given context — all to do with where a candidate is, except for 6 (animate) which is to do with whether it is animate or not — and then:

(a) if only one obvious choice is found, that is returned;
(b) if we are in indefinite mode (don’t care which) one of the obvious choices is returned, or if there is no obvious choice then an unobvious one is made;
(c) at this stage, we work out whether the objects are distinguishable from each other or not: if they are all indistinguishable from each other, then choose one, it doesn’t matter which;
(d) otherwise, 0 (meaning, unable to decide) is returned (but remember that the equivalence classes we’ve just worked out will be needed by other routines to clear up this mess, so we can’t economise on working them out).

And when it’s looking for obvious matches for a [things] token, it skips over anything undescribed or scenery (or the actor, or not in the same scope ceiling).

    if (context==MULTI_TOKEN && ultimate==ScopeCeiling(actor)
        && n~=actor && n hasnt concealed && n hasnt scenery)
    {   good_ones++; last=n; }
2 Likes