ainslec / adventuron-issue-tracker

Adventuron Issues Tracker
4 stars 0 forks source link

s2_has_trait fails due to re-evaluation of s2 when two objects share a common noun #258

Open warrigal24 opened 3 years ago

warrigal24 commented 3 years ago

I am trying to implement an implicit give if the indirect object is not specified. In other words, if you enter something like GIVE APPLE, but you don't specify who or what to give it to, then it checks to see whether a character is present and implicitly gives it to that character, otherwise it tells you that there is no one to give it to. This fails under some unusual circumstances.

In my case, I have two characters in different rooms that share a common noun, specifically Santa Claus and Mrs Claus. Adventuron, in its wisdom, decides that the noun for both of these characters is to be reduced to 'claus'. Thanks to some debugging code, I can see that it correctly identifies s2 as 'santa_claus' before discovering Mrs Claus, but as soon as s2_has_trait is used, it appears to re-evaluate s2 and returns 'ambiguous' so that the test for the trait fails. This re-evaluation should not be done and it should never return 'ambiguous', as both characters are in different rooms and can never be in scope at the same time. On the first pass, Mrs Claus hasn't even been discovered.

Here's an example:

>GIVE COIN
(to Santa Claus)
Expected: Santa gratefully accepts your coin, then gives it back to you so that you can continue testing.
Actual: You can only give the coin to living things.

The debugging code indicates that s2 is correctly identified as 'santa_claus', then as soon as s2_has_trait is used, it changes to 'ambiguous'. Let's continue:

>S

>GIVE COIN
(to Mrs Claus)
Expected: Mrs Claus gratefully accepts your coin, then gives it back to you so that you can continue testing.
Actual: You can only give the coin to living things.

In this case, we can see that Mrs Claus is now regarded as ambiguous. Let's return to Santa Claus:

>GIVE COIN
(to Santa Claus)
Expected: Santa gratefully accepts your coin, then gives it back to you so that you can continue testing.
Actual: You can only give the coin to living things.

This time, s2 is 'ambiguous', rather than 'santa_claus' and s2_has_trait fails once again. Incidentally, in all cases, if you GIVE COIN TO CLAUS, the test for s2_has_trait passes.

Here's a sample program with debugging code:

start_at = room01

game_settings {
   add_standard_prepositions = false
   experimental_new_parser = true
}

strings {
   is_or_are : dynamic_string {(s1_has_trait "plural_t" ? "are" : "is")}
   it_or_them : dynamic_string {(s1_has_trait "plural_t" ? "them" : "it")}
}

traits {
   character_t : trait;
   plural_t : trait;
}

locations {
   room01 : location "You're in the lounge room.";
   room02 : location "You're in the kitchen.";
}

connections {
   from, direction, to = [
      room01, south, room02
   ]
}

objects {
   coin : object "a coin" at = "inventory";
   christmas_tree : scenery "a Christmas tree" at = "room01";
   santa_claus : scenery "Santa Claus" at = "room01" {experimental_matching_text_sequences = ["santa claus", "mr claus", "santa", "claus"] traits = [character_t]}
   mrs_claus : scenery "Mrs Claus" at = "room02" {experimental_matching_text_sequences = ["mrs claus", "mrs", "claus"] traits = [character_t]}
}

on_pre_command {
   : match "give -" {
      : print {("You'll have to tell me what to " + original "verb" + ".")}
      : done;
   }
   : match "give *" {
      : if (preposition2_is "" && !noun2_is "") {
         : set_sentence "give $2 to $1";
      }
      : disambiguate_s1 "carried";
      : disambiguate_s2 "present";
      : if (!is_carried (s1())) {
         : print {("You're not carrying any " + original "noun1" + ".")}
         : done;
      }
      : if (is_worn(s1())) {
         : print "You'll have to remove {it_or_them} first.";
         : done;
      }
      : if ((preposition2_is "" || preposition2_is "to") && noun2_is "") {
         : if (is_present "santa_claus") {
            : print "^n^(to Santa Claus)";
            : set_sentence "give $1 to santa claus";
         }
         : else_if (is_present "mrs_claus") {
            : print "^n^(to Mrs Claus)";
            : set_sentence "give $1 to mrs claus";
         }
         : else {
            : print "You can't see anyone to give {it_them} to.";
            : done;
         }
      }
      : gosub "test_parser";
      : if (s2_has_trait "character_t") {
         : print "s2 is character";
      }
      : else {
         : print "s2 isn't character";
      }
      : if ((preposition2_is "" || preposition2_is "to") && !noun2_is "" && !s2_has_trait "character_t") {
         : print {("You can only give " + definite(d(s1())) + " to living things.")}
         : done;
      }
   }
}

on_command {
   : if (is_present "santa_claus") {
      : match "give coin" {
         : print "Santa gratefully accepts your coin, then gives it back to you so that you can continue testing.";
         : done;
      }
   }
   : if (is_present "mrs_claus") {
      : match "give coin" {
         : print "Mrs Claus gratefully accepts your coin, then gives it back to you so that you can continue testing.";
         : done;
      }
   }
}

vocabulary {
   : verb / aliases = [give, offer]
   : preposition / aliases = [to]
}

subroutines {
   test_parser : subroutine {
      : match "_ _" {
         : mask {
            : print {("^n^verb = " + original "verb")}
            : print {("^n^preposition1 = " + original "preposition1")}
            : print {("^n^noun1 = " + original "noun1")}
            : print {("^n^preposition2 = " + original "preposition2")}
            : print {("^n^noun2 = " + original "noun2")}
            : print {("^n^s1 = " + s1())}
            : print {("^n^s2 = " + s2() + "^m^")}
         }
      }
   }
}
ainslec commented 3 years ago

After changing the logical sentence, the s1 and s2 disambiguations are cleared down (as you might expect) so you should hint ot adenturon what s1 and s2 represent again.

      : if ((preposition2_is "" || preposition2_is "to") && noun2_is "") {
         : if (is_present "santa_claus") {
            : print "^n^(to Santa Claus)";
            : set_sentence "give $1 to santa claus";
            : disambiguate_s1 "carried";
            : disambiguate_s2 "present";
         }
         : else_if (is_present "mrs_claus") {
            : print "^n^(to Mrs Claus)";
            : set_sentence "give $1 to mrs claus";
            : disambiguate_s1 "carried";
            : disambiguate_s2 "present";
         }
         : else {
            : print "You can't see anyone to give {it_them} to.";
            : done;
         }
warrigal24 commented 3 years ago

OK. I'm not sure what 'cleared down' means or what exactly disambiguation does, but if I redo the disambiguation just before : if (s2_has_trait "character_t") (to avoid excessive duplication), that seems to do the trick.

Perhaps you can add something to the doco describing exactly how disambiguation and set_sentence work and include a warning that the former needs to be refreshed after the latter.

ainslec commented 3 years ago

OK to close this issue?

warrigal24 commented 3 years ago

Yes, although there are now lots of caveats with the new disambiguation. For example, I rely on s1 in and s2 in a number of dynamic strings and these are now likely to fail.

ainslec commented 3 years ago

Can you show me the type of dynamic string you are using with S1() in it?

On Mon, Jan 11, 2021, 12:32 Garry Francis notifications@github.com wrote:

Yes, although there are now lots of caveats with the new disambiguation. For example, I rely on s1 in and s2 in a number of dynamic strings and these are now likely to fail.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ainslec/adventuron-issue-tracker/issues/258#issuecomment-757922786, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABRJDVP7QLOAFAKUCYG6BLSZLVWPANCNFSM4V4A2FJA .

warrigal24 commented 3 years ago
strings {
   def_noun1_phrase : dynamic_string {(definite(d(s1())) )}
   uc_def_noun1_phrase : dynamic_string {(first_cap(definite(d(s1()))) )}
   def_noun2_phrase : dynamic_string {(definite(d(s2())) )}
   uc_def_noun2_phrase : dynamic_string {(first_cap(definite(d(s2()))) )}
   is_or_are : dynamic_string {(s1_has_trait "plural_t" ? "are" : "is")}
   it_or_them : dynamic_string {(s1_has_trait "plural_t" ? "them" : s1_has_trait "male_t" ? "him" : s1_has_trait "female_t" ? "her" : "it")}
   that_or_those : dynamic_string {(s1_has_trait "plural_t" ? "those" : s1_has_trait "male_t" ? "him" : s1_has_trait "female_t" ? "her" : "that")}
   you_can : dynamic_string {("You {verb_phrase} {def_noun1_phrase}.")}
   you_cant : dynamic_string {("You can't {verb_phrase} {def_noun1_phrase}.")}
}