Problematic parsing of possessive pronouns for parts of people

Suppose we’re writing a game with a heavy focus on characters: their appearance, their wardrobe, and their possessions. We want to encourage the player to interact with these things via the parser, so for each character, we create their possessions, clothes, and body parts as objects and give them all fitting descriptions. Naturally, this also includes the player character themselves.

Now let’s say we get the player in a room with a character named Gregothan who’s very similar to the player in several respects:

  1. He and the player are both holding a pen;
  2. He and the player are both wearing a shirt; and
  3. He and the player both have a pair of eyes.

Here’s the code for this example:

Code
The player carries your pen. The description of your pen is "It's your pen." The player wears your shirt. The description of your shirt is "It's your shirt." Your eyes are part of the player. The description of your eyes is "You can hardly get a good look at them."

Gregothan is a man. Gregothan carries Gregothan's pen. The description of Gregothan's pen is "It's Greg's pen." Gregothan wears Gregothan's shirt. The description of Gregothan's shirt is "It's Greg's shirt." Gregothan's eyes are part of Gregothan. The description of Gregothan's eyes is "It's Greg's eyes."

The office is a room. Gregothan is here.

Test me with "x pen / x Gregothan's pen / x his pen / x shirt / x Gregothan's shirt / x his shirt / x eyes / x Gregothan's eyes / x his eyes".

Now if the player tries to examine Greg’s pen without providing sufficient detail, the parser will (reasonably!) assume the player means their own pen:

> x pen
(your pen)
It's your pen.

To fix this, the player can name Greg specifically in their command:

> x gregothan's pen
It's Greg's pen.

Or, more likely, they’ll just use a possessive pronoun, as it’s faster to type and sounds a bit more natural:

> x his pen
It's Greg's pen.

Naturally, the same set of responses all hold true for examining Greg’s shirt:

> x shirt
(your shirt)
It's your shirt.

> x gregothan's shirt
It's Greg's shirt.

> x his shirt
It's Greg's shirt.

All is well and good until the player tries to look Greg in the eyes, at which point a baffling incongruity occurs in the parser’s responses:

> x eyes
Which do you mean, your eyes or Gregothan's eyes?

> x gregothan's eyes
It's Greg's eyes.

> x his eyes
You can't see any such thing.

For an unfamiliar player, this is kind of shocking! The default prompt for clarification on x eyes is fairly benign – that can easily be cleared up with a Does the player mean: rule by the programmer. But the parser’s complete failure to recognize “his eyes” as referring to a part of Gregothan is as confusing for the player as it is for me!

From the player’s point of view, there is no good reason why you should be able to type “his shirt” to mean Greg’s shirt, but not be able to type “his eyes” to mean Greg’s eyes. In English and, indeed, in most languages, no grammatical distinction is made between something which belongs to something else and something which is a part of something else. If the parser simply rejected possessive pronouns altogether, then it would at least be consistent in a way the player could learn to type around; it’s the disjoint that bothers me!

On a technical level, I assume the disjoint comes from the fact that the “part of” (incorporation) relation is separate from the carrying relation. Presumably, when the parser encounters a possessive pronoun, it searches the pockets of the person the pronoun refers to for a matching item, but it doesn’t search the list of things which are part of said person.

This can be patched over by explicitly specifying

Understand "his eyes" as Gregothan's eyes.

but this quickly becomes tiresome to type out when we have many characters with many body parts created in assembly, especially because we may already want to have several “understand as” statements for each kind of body part (e.g. Understand 'peepers' as some eyes, etc). For a game of sufficient length and nuance, you would need to have an entire document of “understand” statements just to account for everything.

It would be preferable to just patch the parser’s behavior to include parts of things when resolving possessive pronouns, but I haven’t been able to figure out where in the standard rules this behavior crops up – it might be written in Inform 6, which I’m pretty inexperienced with.

So, there’s my problem! Is there an obvious solution I’m missing? Is this indeed something that can easily be tweaked in the standard rules? Or is the issue something much deeper, and I’d be better off simply discouraging the player from using pronouns at all?

3 Likes

Looking at 13.16 of Writing with inform, it looks as though body parts are handled differently from other objects. There seems to a method of dealing with the issue there.

1 Like

This is an oversight of the parser’s. When it’s evaluating the applicability of something with a possessive pronoun, it discounts parts and only looks at what the person has (i.e., carries or wears).

The following changes only one line: if (indef_owner ~= 0 && its_owner == indef_owner) met++; becomes if (indef_owner ~= 0 && ((its_owner == indef_owner) || (CoreOf(obj) == indef_owner))) met++; but Parser.i6t tends toward very long functions and so it’s a big replacement.

Include (-
Constant SCORE__CHOOSEOBJ = 1000;
Constant SCORE__IFGOOD = 500;
Constant SCORE__UNCONCEALED = 100;
Constant SCORE__BESTLOC = 60;
Constant SCORE__NEXTBESTLOC = 40;
Constant SCORE__NOTCOMPASS = 20;
Constant SCORE__NOTSCENERY = 10;
Constant SCORE__NOTACTOR = 5;
Constant SCORE__GNA = 1;
Constant SCORE__DIVISOR = 20;

Constant PREFER_HELD;
[ ScoreMatchL context its_owner its_score obj i j threshold met a_s l_s;
!   if (indef_type & OTHER_BIT ~= 0) threshold++;
    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

    #ifdef PREFER_HELD;
    a_s = SCORE__BESTLOC; l_s = SCORE__NEXTBESTLOC;
    if (action_to_be == ##Take or ##Remove) {
        a_s = SCORE__NEXTBESTLOC; l_s = SCORE__BESTLOC;
    }
    context = context;  ! silence warning
    #ifnot;
    a_s = SCORE__NEXTBESTLOC; l_s = SCORE__BESTLOC;
    if (context == HELD_TOKEN or MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN) {
        a_s = SCORE__BESTLOC; l_s = SCORE__NEXTBESTLOC;
    }
    #endif; ! PREFER_HELD

    for (i=0 : i<number_matched : i++) {
        obj = match_list-->i; its_owner = parent(obj); its_score=0; met=0;

        !      if (indef_type & OTHER_BIT ~= 0
        !          &&  obj ~= itobj or himobj or herobj) met++;
        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++;
print "met: ", met, " threshold: ", threshold, "^";
        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 == actor) its_score = its_score + a_s;
            else
                if (its_owner == actors_location) its_score = its_score + l_s;
                else
                    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, " (", 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--;
        }
    }
];


-) instead of "ScoreMatchL" in "Parser.i6t".
7 Likes

Oh, perfect! This is just what I was looking for. I thought the trick was something like this, but it’s the sort of thing where without a preexisting familiarity with the parser’s logic and terminology, I would never have known where to look. Thanks a bunch!

1 Like

I hoped to trump Zed with a few lines of I7 code, but I found what I tried was rife with negative side-effects, depending on who’s present and of what sexes they are when typing his/hers/their. Still, I’ll share the attempt because it might stir ideas.

The following two lines worked well just for the original case –

Definition: a thing is non-selfish if it is part of a person
 and it is not part of the player.
Understand "his" as a thing when the item described is non-selfish.

– but break if a second male NPC is present. Even more breakage occurs if you try to expand this system with cover for “her” and “their”.

-Wade

4 Likes

PS – I might add, I’ve unwittingly avoided the original case ever being a problem in my own games by always using the Numbered Disambiguation Choices extension. Then the player would be presented with:

Which do you mean, 1) your eyes or 2) Gregothan’s eyes?

and can type the number and press return.

2 Likes