Coffee disambiguation (Dialog example)
From IFWiki
To do our disambiguating, we partly rely on the predicate (heads $), which effectively tells the program, "If disambiguating, ignore all names except these."
As helpful as this is, the real star of our show is (unlikely $), which allows us to not only prioritize our cupful of coffee but also make some versatile code that can disambiguate in a variety of contexts.
(story title) Coffee Disambiguation Example
(story author) Karona
(story noun) for IFWiki
(current player #player)
#kitchen
(name *) Test Kitchen
(room *)
(look *)
This test kitchen is very clean. It's so clean, it hardly has anything in
it. The living room is to the south.
(#urn is #in *)
(#mug is #in *)
(from * go #south to #room)
#urn
(name *) coffee urn
(heads *) urn
%% We use the item trait to make it possible to take an object:
(item *)
(container *)
(descr *)
The urn is large, round, and heavy. It has to be large to hold the endless
supply of coffee inside it. Perhaps you'd like to pour some into a mug?
(appearance *)
You see (a *) here.
(#supply is #in *)
%% We override the standard library response.
(prevent [empty *])
(#supply is #in *)
You can't empty the urn.
(unlikely [pour $ into *])
(#supply is #in *)
#supply
(name *) endless supply of coffee
(an *)
(potable *)
(descr *)
Hello, tall, dark, and endless.
(before [pour *])
(#player is in room $Room)
(#mug is in room $Room)
~(#mug is #heldby #player)
(first try [take #mug])
(unlikely [drink/taste *])
(* is in room $Room)
(#cupful is in room $Room)
(prevent [drink *])
How rude! Use a mug!
(prevent [pour * into $Container])
~($Container = #mug)
You can't pour coffee into that.
(prevent [pour * into $Container])
(#cupful is #in $Container)
($Container = #mug)
But the mug is full!
(perform [pour * into #mug])
Using the urn, you fill the mug with hot coffee.
(now)(#cupful is #in #mug)
(unlikely [smell *])
(* is in room $Room)
(#cupful is in room $Room)
(perform [smell *])
Smells good. Endlessly good.
#mug
(name *) coffee mug
(heads *) mug
(item *)
(container *)
(descr *)
The mug has the phrase "WORLD'S BEST EXAMPLE CODER" prominently on the
outside. The inside of the mug is
(if)(#cupful is #in *)(then)
full of coffee.
(else)
empty.
(endif)
(appearance *)
You see (a *) here.
(instead of [fill *])
(#player is in room $Room)
(#supply is in room $Room)
(try [pour #supply into *])
(instead of [drink *])
*($Stuff is #in *)
(potable $Stuff)
(try [drink $Stuff])
(prevent [pour *])
(#player is in room $Room)
~(* is in room $Room)
But you don't have a mug!
#cupful
(name *) cupful of coffee
(potable *)
(descr *)
The coffee in the mug looks quite drinkable.
(prevent [pour * into $Container])
~($Container = #urn)
You can't pour the cupful of coffee into that.
(prevent [pour * into #urn])
(#player is in room $Room)
(#urn is in room $Room)
The supply of coffee is already endless.
(prevent [empty (container $Container)])
(* is #in $Container)
That would be a waste of perfectly good coffee!
(prevent [empty (container $Container)])
~(* is #in $Container)
~(#supply is #in $Container)
(The $Container) is already empty!
(perform [smell *])
Smells good. A cupful of good.
(perform [drink *])
You drink the mug of coffee. Aaah. The satisfaction.
(now)(#cupful is nowhere)
#room
(name *) Living Room
(room *)
(look *)
This pleasant living room is ever-so-lightly furnished with a coffee table.
A kitchen can be found to the north.
(from * go #north to #kitchen)
(#player is #in *)
(#table is #in *)
#table
(name *) coffee table
(heads *) table
%% We make the table a supporter -- and not an actor supporter -- to allow
%% objects to be put on the table without allowing the PC to get on the table:
(supporter *)
(descr *)
The coffee table is a modern piece of furniture with metal legs and a
square glass top.
%% We put general code after specific code.
%% Liquids
%% We define all things that are potable (and thus our #supply and our #cupful)
%% to be liquids. Our code would work if we excluded this out and instead used
%% the predicate (potable $) pervasively, but the author might want to add other
%% liquids later, and using predicates in generic code is good practice.
(liquid $Stuff) *(potable $Stuff)
(grammar [pour [single] [into in] [single]] for [pour $ into $])
(grammar [fill [single] with [single]] for [pour $ into $] reversed)
(instead of [pour $Obj into $Container])
*($Stuff is #in $Obj)
(liquid $Stuff)
(try [pour $Stuff into $Container])
%% When actual coffee is in scope, we do not want the parser to understand POUR
%% COFFEE to be about the coffee table, the urn, or the mug. Declaring "table",
%% "urn", and "mug" to be heads (as we did above) would be sufficient, but here
%% we include versatile code that will handle liquids the author might include
%% later.
(unlikely [pour ~(liquid $Object)])
(prevent [pour $ into $Object])
~(container $Object)
(The $Object) is not a container.
(prevent [pour $Object into $])
~(potable $Object)
(The $Object) is not a liquid.
%% If there is an ambiguity, we assume that the player does not want to pour a
%% liquid into the container that already holds it.
(unlikely [pour $Liquid into $Object])
($Liquid is #in $Object)
(unlikely [pour $ into $Object])
~(container $Object)
(unlikely [pour $Object into $])
~(liquid $Object)
(grammar [pour [single]] for [pour $])
(unlikely [pour $Object])
~(liquid $Object)
(instead of [pour $Obj])
*($Liquid is #in $Obj)
(liquid $Liquid)
(try [pour $Liquid])
(instead of [pour $Stuff])
(#player is in room $Room)
(#mug is in room $Room)
(try [pour $Stuff into #mug])
(prevent [pour $Object])
~(liquid $Object)
(The $Object) is not a liquid.
(grammar [fill [single]] for [fill $])
(grammar [empty [single]] for [empty $])
%% Potable
(unlikely [drink/taste ~(potable $Object)])
%% We divert TASTE to DRINK but only if the object is potable.
(instead of [taste (potable $Object)])
(try [drink $Object])