Grammar token question

i’m trying to implement a “follow” command. it works but i’m having odd issues.

in this sample code there are 2 rooms with 2 inanimate objects (a red and green apple) and on animate NPC.

the grammar rule for follow takes [any animate] but the parser seems to just blow by this and interpret is as simply [any].

if you comment out the (prevent) predicate that explicitly prevents non-animate objects, the parser will happily let you follow each apple from room to room.

even if the prevent predicate IS active, typing “follow apple” will lead to a disambiguation question “which apple do you want to follow…?” which is obviously not what is desired.

and finally (sorry, long question), without the ~(refuse) predicate then you can’t follow something in the next room because it’s out of scope. but isn’t the “any animate” token supposed to work regardless of scope?

(intro)
            "Test" 
			(try [look])

#player
(current player *)
(* is #in #test_room_1)

#test_room_1
(name *)     Room No. 1
(room *)
(look *)    It's an empty room. There's a doorway leading west.
(from * go #west to #test_room_2)

#test_room_2
(name *)     Room No. 2
(room *)
(look *)    It's an empty room. There's a doorway leading east.
(from * go #east to #test_room_1)

#red_apple
(name *)    red apple
(item *)
(descr *)   it's a red apple
(appearance *)
            You see a red apple here.
(* is #in #test_room_1)

#green_apple
(name *)    green apple
(item *)
(descr *)   it's a green apple
(appearance *)
            You see a green apple here.
(* is #in #test_room_2)

#person
(name *)    Person
(descr *)   A nondescript animate human being.
(animate *)
(appearance *)  
            The person is here.
(* is #in #test_room_2)

%% FOLLOW
(grammar [follow [any animate]] for [follow $])
~(refuse [follow $])
(prevent [follow $obj])
                ~(animate $obj)
                You can't follow that.
(prevent [follow $npc])
                ($npc is in room $Room)
                (current room $Room)
                (The $npc) is already here.
(prevent [follow $npc])
                ~($npc is one room away)
(perform [follow $npc])
                (current room $CR)
                ($npc is #in $ZR)
                (from $CR go $dir to $ZR)
                You follow (the $npc) to the (the $dir).
                (enter $ZR)
($npc is one room away)
                (current room $CR)
                *(from $CR go $ to $ZR)
                ($npc is #in $ZR)

1 Like

The library does not enforce [any animate] token, it eliminates non-animates only if there is at least one animate object match. You have to use prevent rules to eliminate non-animates. Otherwise it eliminates nothing due to (from library):

(apply policy to $Input $Policy $Output)
	(collect $Obj)
		*($Obj is one of $Input)
		(verify object policy $Policy $Obj)
	(into $Output)
	(nonempty $Output) <-- Fail to next rule if no candidates remain

(apply policy to $Input $ $Input) %% <-- If no object remains in the list due to policy, just use all candidates.

From the manual(emphasis mine):

In addition to the above, you can guide the parser towards certain classes of objects, to help resolve ambiguities as well as decide what the word ALL refers to. The following constraints are not enforced strictly—you must use (prevent $) rules for that.

[animate]

A single, animate object in scope.

[any animate]

A single, animate object, not necessarily in scope. For e.g. CALL MOTHER.

[any] and [any animate] tokens will match out-of scope objects, only if the object is in a visited room and not marked as hidden. In your example, if you go west and and back to east, you can follow the person, because now it is in a visited room.

From the manual:

[any]

A single object, not necessarily in scope. The object must be located in a visited room, and cannot be marked as hidden.

Sorry for double post, just noticed the last question.

This is not exactly true. [any animate] token will match out of scope objects (in the parsing stage), given the right conditions, in my previous post. ~(refuse $) rule will block out of reach refusal (in the action processing stage). So you need both in your example.

Ahh.

So is there any way to prevent the parser from disambiguating the “follow apple” problem? the (prevent) predicates are apparently happening too late to head this off.

or another way, is there a way to enforce scope and token (i.e. animate, non-animate) for a given action BEFORE the parser gets to the disambiguation stage?

That’s correct, disambiguation happens in parsing phase which happens before action processing (refuse, before, prevent, etc.)

You can prepend an extra (apply policy ...)rule to stop the parser dead in its track to enforce animate policy, like this:

(apply policy to $Input $Policy $Output)
	($Policy = {(animate $_)})
	(collect $Obj)
		*($Obj is one of $Input)
		(verify object policy $Policy $Obj)
	(into $Output)
	(if) (empty $Output) (then)  %% Enforces preferably animate policy
		(just) (fail)
	(endif)

(apply policy to $Input $Policy $Output)
	(collect $Obj)
		*($Obj is one of $Input)
		(verify object policy $Policy $Obj)
	(into $Output)
	(nonempty $Output)

(apply policy to $Input $ $Input)

This will affect all actions with animate policies in the library in addition to your “follow” action.

Instead of responses like these:

> follow apple
You can't follow that.

> kiss apple  
The red apple is unmoved by your display of affection.

> talk apple  
There is no reply.

You will get:


> follow apple
(I only understood you as far as wanting to follow someone.)

> kiss apple
(I only understood you as far as wanting to kiss someone.)

> talk apple
(I only understood you as far as wanting to talk to someone.)
2 Likes

Did I understand what you wanted exactly? Or would you rather enforce animate policy only for out of scope objects, and not for in scope ones?

The second option requires changes directly in the library, but it’s possible as well. I can provide code for it if you want.

yes, that is helpful. thx! that gives me some insight in what the parser is doing behind the scenes.

i think what i’m looking for is what inform 6 has. that is, a fallback grammar token called “scope” that will let you dynamically specify the scope and object of an action on a per-action basis.

i’ve looked into the custom token section in the dialog manual but, like much of the advanced topics in the manual, it’s light on detail. i get the overlying concept but have trouble with the nuts and bolts.

ok, i think i finally figured it out.

(understand $Words as followable $Foll)
                *(parse $Words as any object $Output {(animate $_)} [1])
                (current room $CR)
                {($Output is one room away)(or)($Output is #in $CR)}
                ($Foll = $Output)
~(refuse [follow $])
@(grammar transformer [[followable] | $Tail] $SoFar $Verb $Action $Rev)
	(grammar transformer $Tail [90 | $SoFar] $Verb $Action $Rev)
(match grammar token 90 against $Words $ into $Foll)
	*(understand $Words as followable $Foll)
(grammar [follow [followable]] for [follow $])
(prevent [follow $npc])
                (current room $CR)
                ($npc is #in $CR)
                (The $npc) is already here.
(prevent [follow $npc])
                ~(animate $npc)
(perform [follow $npc])
                ($npc is #in $ZR)
                (current room $CR)
                (from $CR go $dir to $ZR)
                You follow (the $npc) to the (the $dir).(line)
                (enter $ZR)
($npc is one room away)
                ($npc is #in $ZR)
                (current room $CR)
                *(from $CR go $ to $ZR)
                    ($npc is #in $ZR)

i’m pretty certain this is not the most efficient way of doing it. but it does seem to work.

i’ve been staring at stdlib.dg for hours and now i’m going to bed!

1 Like

Nice custom token example. Here is my take without using tokens or grammar lines:

%% FOLLOW
(understand [follow | $Words] as [follow $Object])
	(current room $CR)
	(collect $O)
		*(understand $Words as any object $O)
		{($O is one room away) (or) ($O is in room $CR)} %% Enforcing custom scope
	(into $Candidates)
	(apply policy to $Candidates {(animate $_)} $ObjList)

	%% Note that, at this point $ObjList either contains all animate objects
	%% or none, due to the policy. Next we set up a multiquery in case all objects
	%% in the list are animate, so the parser asks disambiguation question.

	*($Object is one of $ObjList)

	%% If none of the objects in the list are animate, we excise the choice points
	%% of the encompassing rule and any others created since the start of this rule.
	%% Specifically this will delete the choice point extant from the multiquery
	%% above and turn it into a simple query. The net effect is that if it's all
	%% non-animates we just return the first one in the list, so that the prevent
	%% rule below for non-animates can fire off. Thus we eliminate the choice of
	%% failures, "Would you like to fail with the red apple or the green apple".

	(if) ~(animate $Object) (then)
		(just)
	(endif)

~(refuse [follow $])
(prevent [follow $npc]) %% Relocated this rule so it can fire off first
                ~(animate $npc)
				You can't follow that.
(prevent [follow $npc])
                (current room $CR)
                ($npc is #in $CR)
                (The $npc) is already here.
(perform [follow $npc])
                ($npc is #in $ZR)
                (current room $CR)
                (from $CR go $dir to room $ZR) %% Changed this query to support doors
                You follow (the $npc) to the (the $dir).(line)
                (enter $ZR)
($npc is one room away)
                ($npc is #in $ZR)
                (current room $CR)
                *(from $CR go $ to room $ZR) %% Changed this query to support doors
                    ($npc is #in $ZR)

Edit: Added another comment.

1 Like

that’s definitely much cleaner that what i did. and i hadn’t even considered an issue with doors.

thx greatly for the help.

and, BTW, if anyone is still following this thread - i have a game (written using dialog of course) that’s ready for play-testing. it’s an old-school infocom-like parser game (but with some user-friendly features and the intent is that it not be as punishing as an infocom game). i’ll probably enter it in parsercomp or spring thing, depending on feedback. hints and transcript provided.

i already posted over on the ‘play-testing help wanted’ category, but if anyone is interested let me know.

1 Like

My code is for proof of concept really, it lacks some polish. For example it is not wired for specific parse error messages, so it gives the most generic error message if the player types “follow xyzzy”. It needs little more scaffolding if one wants “… follow someone.” error message. Also the way it sets the pronouns can also be weird.

Since your code uses library facilities to implement the action, those things are already polished in comparison.