how could I do dynamic parsing? Inform 6 or TADS or what?

I’d like to be able to write fairly complex rules to print descriptions of things, and have the parser understand the descriptions that are printed as referring to the things. As a simple example, where the player is looking at colored blocks through glasses that change color:

[more under the spoiler tag]

Now, I got that to happen in Inform 7 by means of an ugly hack: I created a new action for “take [text]” and had it compare the topic understood to the result of the rules for printing the name of every visible item (as indexed text!). (I realize that in this particular instance there are much simpler solutions, like defining another property for the apparent colors of the blocks, but suppose that the rules for printing names of objects were much more complicated.) Code under the spoiler:

[spoiler][code]Use American dialect and the serial comma.

Section - Colors

[This is a bunch of stuff to make the color of a block vary dynamically depending on its real color and the color of the player’s glasses.]

A color is a kind of value. The colors are red, blue, and yellow.

A block is a kind of thing. A block has a color.

The player wears some glasses. The glasses have a color. The description of the glasses is “The glasses are currently colored [color of the glasses]. Push the button to change the color.” Understand “button” as the glasses.

Carry out pushing the glasses:
now the color of the glasses is the color after the color of the glasses.
Report pushing the glasses:
say “The glasses are now colored [color of the glasses].”;
rule succeeds.

For printing the name of a block (called the cube):
if the player does not wear the glasses:
say “a [color of the cube] block”;
otherwise:
if the color of the glasses is red:
if the color of the cube is:
– red: say “a red block”;
– blue: say “a purple block”;
– yellow: say “an orange block”;
otherwise if the color of the glasses is blue:
if the color of the cube is:
– red: say “a purple block”;
– blue: say “a blue block”;
– yellow: say “a green block”;
otherwise: [the color of the glasses is yellow]
if the color of the cube is:
– red: say “an orange block”;
– blue: say “a green block”;
– yellow: say “a yellow block”.

Section - Taking and Examining By Name

[This is where the dynamic parsing happens, such as it is.]

Examining by name is an action applying to one topic. Understand “examine [text]” as examining by name.

Carry out examining by name:
repeat with the item running through visible things:
if “[the item]” matches the text the topic understood:
try examining the item; [really I should be collecting this into a match list, but you get the point]
rule succeeds;
say “You can’t see any such thing.”

Taking by name is an action applying to one topic. Understand “take [text]” as taking by name.

Carry out taking by name:
repeat with the item running through visible things:
if “[the item]” matches the text the topic understood:
try taking the item;
rule succeeds;
say “You can’t see any such thing.”

The Playroom is a room. Block1 is a red block in The Playroom. Block2 is a blue block in The Playroom. Block3 is a yellow block in The Playroom.[/code][/spoiler]

Which is no good. It basically throws out the parser, I’d have to create a new action with a text token for every action I wanted to work (if you try to drop the purple block with the code I’ve written, you’re SOL), and anyway it won’t work for two-noun actions because you can’t have two text tokens in an understand line. (Also articles get messed up here, but I could maybe take care of that along these lines.)

Ideally I’d like to have a way to have these dynamic texts hooked into “[something]” tokens.

So my question is: What if anything can I do to make this happen? Possibilities:

  1. A parser hack in I7. I’m pretty sure this can’t happen; poking around Ron Newcomb’s Original Parser extension, it seems as though before the command gets to the parser (as Ron translated into I7) it’s already been resolved into dictionary words, so there’s no way to get something not in the dictionary hooked into a [something] token.

  2. A parser hack in I6. From the code Felix kindly posted here, that seems like it might be possible; it looks like the Swedish extension has a way to cast a snippet into indexed text and hook it back into a “something” token. In order to make this work, I’d have to learn I6.

(That code won’t work for me as is, because the text I want to understand isn’t actually the printed name; the blocks retain printed names like “Block1” even if the rules for printing the names output something different.)

  1. Something completely different. Would TADS make this easier?

  2. Work on one of my less insane ideas instead.

Any thoughts? How deep into I6 would I wind up if I chose route 2?

In I6 you can write a parse_name routine to understand any set of words, or sequence of words, or whatever you want. If you can boil the logic down to a boolean function on a list of words, you’re good. If not all of your words are in the I6 dictionary, it gets harder (you have to do letter-by-letter comparisons for the word chunks, instead of an equality test) but it’s not logically more difficult.

(Really, it’s not a boolean function on a list. It’s a function that matches as many words as possible from a given list – the player’s command starting at word N. This is subtly different, and it can be hard to get a grip on, but once you’ve got the trick of it it’s okay.)

I7 really wants you to use a simpler form: a set of conditional word and word sequences. I.e.: “Understand ‘purple’ as X if…”, “Understand ‘letter box’ as X if…”. This is not as flexible but it has sufficed for all actual-IF-game cases that I’ve run into.

That is true, but your “after reading a command” rule can rewrite the command and tell the parser to re-resolve it into dictionary words. This is a powerful (though sometimes awkward) way to hammer a command into a more-easily-parseable form.

In Tads, you would change the vocabulary of the objects as needed. For example, remove the word “red” and add the word “purple” to the block object’s vocabulary when the glasses change their color to blue.

You can do this in Tads 3 as well as Tads 2.

It wouldn’t just be simpler to have rules that change the actual properties of things, rather than have rules that change their descriptions? In your example, for instance, you could have pushing the button simply change the colour of all the things in the world, and you would have no parser problems. (I can imagine that there are scenario’s in which this solution doesn’t work well or doesn’t work fast enough.)

That certainly would be simpler in this case, but I’m somewhat quixotically envisioning something where that probably wouldn’t be practical. Something like “If it is late afternoon and the item is metallic and there is a window mapped west of the location, now the elaborate name of the item is ‘shiny [elaborate name of the item]’” and a bunch of similar things. The idea would be to have procedural generation of text that has enough variety that it wouldn’t get monotonous for the reader even after many such generations, and that matters enough to the gameplay that you can interact with it.

(I mentioned the project a bit more here. That thread reminds me that “Objects Matching Snippets” would probably have taken care of the example I posted, and that Ron posted an I6 fix for a previous attempt at this that I of course don’t understand.)

Definitely quixotic, as I said, but it seems like it might be fun for me to try it. I like platformers, so my idea of fun must include banging my head on my desk in frustration. On which note, I guess I need to go learn some I6.

Or TADS, maybe. RealNC, can the words that you add to an item’s vocabulary be variables? That is, instead of adding ‘purple’ to the vocabulary of the block, could I carry out some rules for determining the appearance of the block and add the resulting strings to the vocabulary of the block?

How about something like this?

[spoiler][code]“Test”

Understand “Examine [things]” as examining.

Colour is a kind of value. The colours are defined by the Table of Colour Codes.

Table of Colour Codes
colour R G B
black 0 0 0
red 255 0 0
blue 0 0 255
green 0 255 0
yellow 255 255 0
cyan 0 255 255
magenta 255 0 255
white 255 255 255

A block is a kind of thing. A block has a colour called the actual colour. A block has a colour called the perceived colour. The description of a block is “[if the player is not wearing the glasses]This block is [the actual colour of the item described][otherwise if the actual colour of the item described is the perceived colour of the item described]This block appears [the perceived colour of the item described] and is [the actual colour of the item described][otherwise]This block appears [the perceived colour of the item described], but it is actually [the actual colour of the item described][end if].”. Understand the perceived colour property as describing a block when the player is wearing the glasses. Understand the actual colour property as describing a block when the player is not wearing the glasses.

Before printing the name of a block (called the chosen block) (this is the new block name printing rule):
if the player wears the glasses begin;
say "[the perceived colour of the chosen block] ";
otherwise;
say "[the actual colour of the chosen block] ";
end if.

Before printing the plural name of a block (called the chosen block) (this is the new block plural name printing rule):
if the player wears the glasses begin;
say "[the perceived colour of the chosen block] ";
otherwise;
say "[the actual colour of the chosen block] ";
end if.

To decide what number is the smaller of (N - number) and (M - number):
if N is less than M begin;
decide on N;
otherwise;
decide on M;
end if.

To say padded (value - a number):
if the value is less than 100, say “0”;
if the value is less than 10, say “0”;
say the value.

To decide what colour is the calculated colour of the/-- (chosen block - a block):
let the redvalue be the smaller of the R of the actual colour of the chosen block and the R of the colour of the glasses;
let the greenvalue be the smaller of the G of the actual colour of the chosen block and the G of the colour of the glasses;
let the bluevalue be the smaller of the B of the actual colour of the chosen block and the B of the colour of the glasses;
repeat through the table of colour codes begin;
if the redvalue is the R entry and the greenvalue is the G entry and the bluevalue is the B entry, decide on the colour entry;
end repeat;
say “Error - Undefined Colour => R - [padded redvalue] | G - [padded greenvalue] | B - [padded bluevalue]!”.

The player wears some glasses. The glasses have a colour. The description of the glasses is “The glasses are currently coloured [colour of the glasses]. Push the button to change the colour.”. Understand “button” as the glasses.

Carry out pushing the glasses (this is the new carry out pushing the glasses rule):
now the colour of the glasses is the colour after the colour of the glasses;
repeat with the chosen block running through blocks begin;
now the perceived colour of the chosen block is the calculated colour of the chosen block;
end repeat;

Report pushing the glasses (this is the new report pushing the glasses rule):
say “The glasses are now coloured [colour of the glasses].”;
try looking;
rule succeeds.

Report wearing the glasses (this is the new report wearing the glasses rule):
say “You put on the glasses.”;
try looking;
rule succeeds.

Report taking off the glasses (this is the new report taking off the glasses rule):
say “You take off the glasses.”;
try looking;
rule succeeds.

When play begins (this is the initialise colours rule):
let count be zero;
repeat with the chosen block running through blocks begin;
increment count;
choose row count from table of colour codes;
now the actual colour of the chosen block is the colour entry;
now the perceived colour of the chosen block is the calculated colour of the chosen block;
end repeat.

The Testing Room is A Room. There are eight blocks in the testing room.

Test me with “x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses / x blocks / x white / remove glasses / x white / wear glasses / push glasses”.[/code][/spoiler]

Hope this helps.

The vocabulary is a list of strings. You can insert and remove from it programmatically, either string constants or strings that you construct and modify at runtime and store in variables.

The routines you use to do this are described here:

tads.org/t3doc/doc/sysman/dict.htm

The adv3 library provides a default Dictionary, cmdDict. You call the various methods described in the above URL on that object. For example, to add an adjective to the block object, you do:

cmdDict.addWord(block, myAdjective, &adjective);

“block” is the object you want to modify, “myAdjective” is a string variable (you could have also passed a string constant there, for example ‘blue’), and “&adjective” is a property reference; it tells the addWord() method that the string you’re adding should be inserted to the list of adjectives. You could have also passed “&noun” instead of “&adjective” to add to the list of nouns instead.

So in your case, to replace “red” with “purple”, you do:

cmdDict.removeWord(block, 'red', &adjective);
cmdDict.addWord(block, 'purple', &adjective);

Again, instead of ‘red’ and ‘purple’, you can use variables. You can also use lists. With lists, you can add and remove multiple words with a single call.

climbingstars – That’s an excellent implementation for this case, but I don’t think it’ll generalize to the case I describe.

To be clear: Getting things into a situation where you can type something like “Understand the perceived colour property as describing a block when the player is wearing the glasses,” that’s surely better than the general approach I’m talking about. But I still want to figure out how to do things my way, partly because of the challenge, but mostly because I’d like an approach that works when I have enough crazy complicated rules for printing text that I’m not always quite sure myself what they’ll produce, and one that doesn’t require me to add a new value whenever I decide to add a new bit of text. That’s why I want something that lets me access the text that the complicated rules are printing about an item and compare the player’s command to it.

realNC – thanks, I’ll give that a look.

Understanding by relations is pretty powerful - you might be able to use it here. But it’s really slow.

I get your point, but you are seriously working against the grain here in both I6 and I7.

Possible route in I6: print the name to a memory array, tokenize it into dict words, and store the list of words somewhere.

[quote="zarf"I get your point, but you are seriously working against the grain here in both I6 and I7.[/quote]
I was afraid of that. Well, I’ll keep investigating. Thanks for the I6 suggestion.