Topic Resolution of Conversation matchObj Lists

I ran into a perceived gap in conversation capabilities. The situation is this, I have a pretty similar topic response that would like to be mildly tailored to the object under discussion, which means I need to know which object actually matched the Topic out of a list. ie

++ AskTellTopic [pokemon, neopet, bakugan, digimon]
    "\"I don\'t know what <<[which one matched here???]>> is.\"  "
;

My first attempt was

++ AskTellTopic [pokemon, neopet, bakugan, digimon]
    "\"I don\'t know what <<gAction.getTopic().getBestMatch().aName>> is.\"  "
;

This seemed to work, but had a pretty fatal flaw. If any of the vocabulary was shared by items NOT in the list, say >ask ash about electric mouse , the topic would be activated correctly, indicating an initial match, but the reported object could be different! Ie, I might activate the topic via Pikachu, but get the message "I don't know what a computer mouse is." For some reason I could not figure out, it does not necessarily resolve to the same/original object! I assume this has to do with the ā€˜arbitraryā€™ matching described in the documentation.

Ultimately, the way I chose to address this was to modify the base TopicMatchTopic class:

modify TopicMatchTopic
    actualMatch_ = nil // new property - JJMcC
    findMatchObj(obj, rt) {
        /* check the "in scope" list */
        if (rt.inScopeList.indexOf(obj) != nil) {
            actualMatch_ = obj; // added property setting - JJMcC
            return true;
        }

        /* check the "likely" list */
        if (rt.likelyList.indexOf(obj) != nil) {
            actualMatch_ = obj; // added property setting - JJMcC
            return true;
        }
        actualMatch_ = nil;
        return nil;
    }    
;

Then, I can safely reference things as follows:

++ AskTellTopic [pokemon, neopet, bakugan, digimon]
    "\"I don\'t know what <<actualMatch_.aName>> is.\"  "
;

I offer this, as this was a DEEP hole of reverse engineering maybe someone else can avoid. (And in case there was an easier solution that eluded me).

One might need to make an analagous change to ThingMatchTopicā€™s matchTopic if similar customization is needed for Give or Show.

2 Likes

I donā€™t know anything about Pokemon so Iā€™m not sure I know what you mean by the vocabulary overlap!
I will say that I have defined numerous TopicEntrys with getBestMatch embedded in the topicResponse, and have never gotten thrown for a loop with the reported object the way youā€™re talking about.
Maybe the only thing that comes to mind as an alternative would be more typing, a la:

class PokAskTell : AskTellTopic
    topicResponse = "... <<matchObj.aName>> ..."
;

(ActorState)
++ PokAskTell @pokemon;
++ PokAskTell @neopet;
++ PokAskTell @bakugan;
++ PokAskTell @digimon;

or if the list was really long, maybe use a preinit foreach loop with new PokAskTell(arg) and addTopic.
Dunno, hope youā€™ve got it working for your needs!

1 Like

I was afraid I might not be able to recreate it simply, but I did! Here is an example of what Iā€™m on about:

#charset "us-ascii"
//
// sample.t
// Version 1.0
// Copyright 2023 JJMcC
//
// This is a very simple demonstration "game" for the conversation
// "getBestMatch" matching problem
//
// It can be compiled via the included makefile with
//
//  # t3make -f makefile_bestMatch.t3m
//
// ...or the equivalent, depending on what TADS development environment
// youre using.
//
// This "game" is distributed under the MIT License, see LICENSE.txt
// for details.
//
#include <adv3.h>
#include <en_us.h>

versionInfo: GameID
    IFID = '12345'
    name = 'CG demo'
    byline = '(c) 2024 Jeff J McCoskey'
    version = '0.1'
    licenseType = 'Freeware'
;

startRoom : OutdoorRoom 'Front Yard'
    "This is a featureless front yard.  A house is to the north. "
    north = house
    in asExit(north)
    vocabWords = 'outside'
;
+me : Person;
+rock : Thing 'ordinary rock/mineral' 'rock'
    "An ordinary rock.  "
;
+stone : Thing 'notable stone/mineral' 'stone'
    "A notable stone.  "
;
house : Room 'Inside House'
    "This is the one room house (apparently with no door).
        The front yard lies to the south.  "
    vocabWords = 'inside/house'
    south = startRoom
    out asExit(south)
;
+pebble : Thing 'extraordinary pebble/mineral' 'pebble'
    "An extraordinary pebble.  "
;
+talker : Actor 'talky person' 'talky person';
++ AskTopic [pebble, rock]
    "\"It\'s a good looking <<gAction.getTopic().getBestMatch().name>>.\"  "
;
gameMain : GameMainDef
    initialPlayerChar = me
;

A few things to note here: note all objects share the same noun vocab word ā€˜mineralā€™ and note the Actor only has responses for rocks and pebbles, NOT stones. This provides the transcript:

Front Yard
This is a featureless front yard.  A house is to the north.

You see a stone and a rock here.

>get rock
Taken.

>n
Inside House
This is the one room house (apparently with no door).  The front yard lies to
the south.

You see a pebble here.

The talky person is standing here.

>a person about mineral
"It's a good looking stone."

>a person about ordinary mineral
"It's a good looking rock."

>a person about notable mineral
The talky person does not respond.

>a person about stone
The talky person does not respond.

Note the first response: It's a good looking stone. The Actor provides a response, but that is only possible for rocks and pebbles. Nevertheless, once activated, the Topic response resolves gActor.getTopic().getBestMatch() to stone! Ie, it resolves differently than the original topic parsing.

Above workaround resolves this.

FWIW, I have done the multiple-instance solution for other artifacts in the past. Donā€™t know why this one rubbed me the wrong way!

1 Like

One thing to note is that getBestMatch is a method of ResolvedTopic, and is agnostic to the TopicEntry and its matchObj. So when you say getBestMatch.aName it isnā€™t the AskTell with its pokemon list thatā€™s trying to find a ā€œbest matchā€, itā€™s the parserā€™s list of all game objects that matched the command line vocab via the Resolver.
A person could probably add a getBestMatch(topic) method to TopicEntry (as distinct from that of ResolvedTopic), which uses the same logic as gBM but only looks amongst objects that appear in matchObj (or could match matchPattern).

1 Like

Agreed, I was assuming getBestMatch() was similar enough to the original Topicā€™s resolution algorithm, which, clearly not! Agree that limiting the search pool as you describe would also work (exercise for the reader :] ). For me, was ultimately more satisfying to just stuff the original match into a property as it was decoded.

You miss this, donā€™t you? Working on anything new?

1 Like

Ha, does it show that bad?!

In TADS3, I regret to say no, Iā€™m not. There are two reasons:

  1. I havenā€™t been visited by inspiration for a new storyline or a new puzzleset as of yet, although if I write another work thereā€™s a high probability that I will reuse the Dwindeldornian game world and (partial) cast of characters. Maybe zeroing in on one of the supporting roles in Quisborne. If I ever come up with a story idea compelling enough, Prince Quisborne also hints that we may someday hear the tale of his daughter, Princess Quiselda.
  2. Iā€™m actively trying to make a career switch from carpentry/remodeling to something in the software development world, and any free time I have that I might spend on the computer is consumed by tasks relating to that pursuit. Currently Iā€™m self-teaching CAD, particularly Onshape and the related FeatureScript language, because I have a friend who recommended me highly to a company heā€™s connected with that works in those things. Also, Iā€™m working towards putting all of my C++ projects on GitHub so that potential employers have the option of viewing/using code Iā€™ve written, and itā€™s consuming a suprising amount of time repackaging the old code into a more professional-looking layout and making sure that itā€™s usable to the public (for just one instance, I hardcoded paths to resource files all over the place.)

But writing TADS3 games has been the most enjoyable and satisfying thing Iā€™ve done with programming to dateā€¦

3 Likes