Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I7 Autopsy of an Action

10 views
Skip to first unread message

Neil Cerutti

unread,
Jun 29, 2006, 4:30:15 PM6/29/06
to
In Inform 7, I can intervene in several places:

1. Before: This is before anything has been checked, even
touchability. Not terribly useful, that. On the other hand, I6's
before properties worked this way, and most players ignored the
thousands of unfixed bugs this caused. Authors who routinely used
ObjectIsUntouchable() in their before routines are exempt from
this criticism. I don't see many hands up. ;)

2. Instead: This is after touchability has been determined, but
before any check rules have been run. This can be useful, but I
don't think it's as applicable as it first appears. Most check
rules are just as fundemental as touchability. If I to trigger
the pail-of-water-over-the-door trap with an instead rule, I've
got to make sure the door is unlocked myself, since I'll be
intefering before that check is run.

3. Carry Out: I can make something entirely different happen
here. I'm prohibited from passing control back to the normal
action mechanism, so it is not the place for additions or
commentary. It is the right place to intervene when I need to
block an action after the check rules have ensured it is entirely
sensible.

4. After: Here the action has taken place. I can report it in my
own way, or cause something to happen in addition to the normal
behavior. I think this is the most useful phase in which to
intervene.

5. Report: I'll never need to use this unless I'm writing my own
new action.

In conclusion, I think Carry Out and After should be your first
considerations when creating special rules. Use Carry Out to
block, and After to comment and elaborate. Do not use Before, and
consider carefully before using Instead.

But I've got less than month of I7 under my belt, and so I could
be talking nonsense.

--
Neil Cerutti
After finding no qualified candidates for the position of
principal, the school board is pleased to announce the
appointment of David Steele to the post. --Philip Streifer

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php

ems...@mindspring.com

unread,
Jun 29, 2006, 5:17:50 PM6/29/06
to

Neil Cerutti wrote:
> In Inform 7, I can intervene in several places:
>
> 1. Before: This is before anything has been checked, even
> touchability. Not terribly useful, that.

I find I most often use this in one of these ways:

1) to generate an implicit action which needs to happen before the
check or even the touchability rules. For instance, if I want to have
the player automatically try opening a glass case before doing anything
with the ivory elephant inside, this would be a good place to put that
in.

2) to refuse actions that are not just physically impossible but
illogical or prohibited by the PC's morals or taste. After all, I would
want a "You're allergic to chocolate!" refusal message to take
precedence over all other refusals in an attempt to eat the chocolate;
I don't want "The plastic lunchpail is closed" some of the time,
encouraging the player to open the lunchpail and try again, when this
action is prohibited from the outset.

Poster

unread,
Jun 29, 2006, 6:10:35 PM6/29/06
to

I never really had a problem with touchability because most of the
objects I've coded are touchable. (The clocks in Building were the only
untouchable object I've done, I think.) I guess that makes me an author
of games which aren't fantastically complex, which is OK by me. *shrugs*
I've used before for Emily's case #2 most of the time, or for standard
default actions. Where else am I going to put a Smell: "It smells like
your brother's toejam!" if not in a before? React_before?

Also, I'm not too sure that intervening after an action has transpired
counts as intervening. The action is over, done, kaput. The code can
react to it, but you sure can't prevent it from happening.

-- Poster

www.intaligo.com Look for Seasons in the upcoming IF IntroComp!

ChicagoDave

unread,
Jun 29, 2006, 6:26:49 PM6/29/06
to
>Neil Cerutti wrote:
> In Inform 7, I can intervene in several places:
>
> 1. Before: This is before anything has been checked, even
> touchability. Not terribly useful, that. On the other hand, I6's
> before properties worked this way, and most players ignored the
> thousands of unfixed bugs this caused. Authors who routinely used
> ObjectIsUntouchable() in their before routines are exempt from
> this criticism. I don't see many hands up. ;)

Yeah, I hardly ever use this unless it's for a blurb entering a
location.

I have always thought that an IF platform should be able to build the
entire chain of events that makes up the turn and then have a hook
where you can review and validate the event list or cut the list down
to a certain point, add a hint, then ask the parser to rebuild the
list. When it's finally in a state that has no hooks, it's validated
and executed.

That might be overkill. So then there might be a way to have a
transactional list, where some things are comitted as parser executes.

So maybe the right hook should be before_commit and after_commit for
each action taken, including reports.

I need to come up with an example of why I think this is a good idea.

> 2. Instead: This is after touchability has been determined, but
> before any check rules have been run. This can be useful, but I
> don't think it's as applicable as it first appears. Most check
> rules are just as fundemental as touchability. If I to trigger
> the pail-of-water-over-the-door trap with an instead rule, I've
> got to make sure the door is unlocked myself, since I'll be
> intefering before that check is run.

I use this all the time. Wham. Use the sledge hammer. Yah, we are the
IFinator. We are going to pump up this code.

> 3. Carry Out: I can make something entirely different happen
> here. I'm prohibited from passing control back to the normal
> action mechanism, so it is not the place for additions or
> commentary. It is the right place to intervene when I need to
> block an action after the check rules have ensured it is entirely
> sensible.

I still haven't figured out when I need this. But I've mostly focused
on settings and scenery so far. Dialogue and NPC actions are on the
list for July.

> 4. After: Here the action has taken place. I can report it in my
> own way, or cause something to happen in addition to the normal
> behavior. I think this is the most useful phase in which to
> intervene.

Again - I like to report stuff after every thing is done somethimes.
But rarely.

> 5. Report: I'll never need to use this unless I'm writing my own
> new action.

I just started using this to hack the implied second noun stuff.

--

I think I'm still thinking about most of this. Mostly I think the
underlying I6 library needs a kick in the ass to be more suitable for
I7 rules, but I've mentioned that already.

David C.

David Fisher

unread,
Jun 29, 2006, 7:17:27 PM6/29/06
to
"ChicagoDave" <david.c...@gmail.com> wrote in message
news:1151620009.1...@x69g2000cwx.googlegroups.com...

> I have always thought that an IF platform should be able to build the
> entire chain of events that makes up the turn and then have a hook
> where you can review and validate the event list or cut the list down
> to a certain point, add a hint, then ask the parser to rebuild the
> list. When it's finally in a state that has no hooks, it's validated
> and executed.

I love that idea.

> I need to come up with an example of why I think this is a good idea.

Me, too. I am sure that the ability to look ahead at the sequence of events
could be useful, though.

I vaguely remember a post about actions being split into lower level, more
basic actions ("open door" involves "touch the door", which involves "move
hand to door", which fails if you are tied up) - and thinking that looking
ahead would be useful for this somehow ... but I'm sleepy and I don't
remember the details right now.

David Fisher


Michael Martin

unread,
Jun 29, 2006, 7:48:08 PM6/29/06
to
I too have been playing with it. I've reached some slightly different
conclusions, and picked up a few fun tricks as well. Don't take this
as a refutation, merely as a different set of experiences...

Neil Cerutti wrote:
> 1. Before: This is before anything has been checked, even
> touchability. Not terribly useful, that. On the other hand, I6's
> before properties worked this way, and most players ignored the
> thousands of unfixed bugs this caused. Authors who routinely used
> ObjectIsUntouchable() in their before routines are exempt from
> this criticism. I don't see many hands up. ;)

It's also done before checking whether you can actually go in a
direction. So, a generic can't go message can use "Instead of going
nowhere from the Kitchen", but a rule for "Instead of going north from
the Kitchen" will never fire. You can, however, do a "Before going
north when the location is the Kitchen" rule for custom
direction-refusal messages.

> 2. Instead: This is after touchability has been determined, but
> before any check rules have been run. This can be useful, but I
> don't think it's as applicable as it first appears. Most check
> rules are just as fundemental as touchability. If I to trigger
> the pail-of-water-over-the-door trap with an instead rule, I've
> got to make sure the door is unlocked myself, since I'll be
> intefering before that check is run.

Sounds like a trap like that should be an after rule.

> 3. Carry Out: It is the right place to intervene when I need to


> block an action after the check rules have ensured it is entirely
> sensible.

I think I'd end up blocking it by writing additional check rules.

> 4. After: Here the action has taken place. I can report it in my
> own way, or cause something to happen in addition to the normal
> behavior. I think this is the most useful phase in which to
> intervene.

As long as the action does the intended thing (opening or unlocking a
door, etc.), then yes. Some actions block at the check phase, though,
so after rules will never run. You need instead rules for those.

> 5. Report: I'll never need to use this unless I'm writing my own
> new action.

Pretty much, though I think you can vary messages by swapping them out
instead of writing extremely general After rules.

> Do not use Before, and consider carefully before using Instead.

I'd say that Before is strictly for interlocutory actions or for
actions that the world model says should be impossible, but which you
don't want to have be impossible.

Instead is for making things that should be legal impossible. For
example, I have a room in my WIP called "Limbo". Some rooms can change
their exits, but you can't really *remove* an exit as far as I've been
able to tell. So, it instead points at Limbo, and Instead of going to
Limbo, say "You can't go that way." Instead rules are also for
intervening with the "actions that do nothing unless rules intervene",
which have no carry out phase and which are by default blocked during
Check. This is most of the exotic actions.

--Michael

Will Green

unread,
Jun 29, 2006, 10:26:36 PM6/29/06
to
Michael Martin wrote:

> It's also done before checking whether you can actually go in a
> direction. So, a generic can't go message can use "Instead of going
> nowhere from the Kitchen", but a rule for "Instead of going north from
> the Kitchen" will never fire. You can, however, do a "Before going
> north when the location is the Kitchen" rule for custom
> direction-refusal messages.

You can also do

Instead of going north in the Kitchen...

-Will

Neil Cerutti

unread,
Jun 30, 2006, 8:44:51 AM6/30/06
to
On 2006-06-29, ems...@mindspring.com <ems...@mindspring.com> wrote:
>
> Neil Cerutti wrote:
>> In Inform 7, I can intervene in several places:
>>
>> 1. Before: This is before anything has been checked, even
>> touchability. Not terribly useful, that.
>
> I find I most often use this in one of these ways:
>
> 1) to generate an implicit action which needs to happen before
> the check or even the touchability rules. For instance, if I
> want to have the player automatically try opening a glass case
> before doing anything with the ivory elephant inside, this
> would be a good place to put that in.

The above requires some thinking. It may happen that I don't want
an implicit action to be generated in preperation for an action
that would be stopped by check rules preventing obvious abuses.
Whenever your second point, below, conflicts with your first
point, a before rule will turn out wrong. For "eat ivory
elephant", I would consider it wrong to open the case just to say
"That's not edible."

> 2) to refuse actions that are not just physically impossible
> but illogical or prohibited by the PC's morals or taste. After
> all, I would want a "You're allergic to chocolate!" refusal
> message to take precedence over all other refusals in an
> attempt to eat the chocolate; I don't want "The plastic
> lunchpail is closed" some of the time, encouraging the player
> to open the lunchpail and try again, when this action is
> prohibited from the outset.

That's a good use of Before I didn't think of. Thanks.

When I wrote my autopsy notes I was, without meaning to, thinking
only of a small class of actions: those with interesting check
and carry out rules. There are plenty of actions provided in the
Standard Rules that are just grammar-to-generate and one check
rule, which by default prints a refusal. Instead rules will be
fine for intercepting all those actions.

--
Neil Cerutti

Neil Cerutti

unread,
Jun 30, 2006, 8:55:39 AM6/30/06
to
On 2006-06-29, Michael Martin <mcma...@gmail.com> wrote:
> I too have been playing with it. I've reached some slightly
> different conclusions, and picked up a few fun tricks as well.
> Don't take this as a refutation, merely as a different set of
> experiences...

Thanks for your thoughts. This sort of discussion is what I was
hoping for. On usenet, it helps to make bold, over-generalized
pronouncements when starting a discussion. ;)

> Neil Cerutti wrote:
>> 1. Before: This is before anything has been checked, even
>> touchability. Not terribly useful, that. On the other hand,
>> I6's before properties worked this way, and most players
>> ignored the thousands of unfixed bugs this caused. Authors who
>> routinely used ObjectIsUntouchable() in their before routines
>> are exempt from this criticism. I don't see many hands up. ;)
>
> It's also done before checking whether you can actually go in a
> direction. So, a generic can't go message can use "Instead of
> going nowhere from the Kitchen", but a rule for "Instead of
> going north from the Kitchen" will never fire. You can,
> however, do a "Before going north when the location is the
> Kitchen" rule for custom direction-refusal messages.

Thanks. I didn't know that, and will definitely run into that
wrinkle in my WIP.

>> 2. Instead: This is after touchability has been determined,
>> but before any check rules have been run. This can be useful,
>> but I don't think it's as applicable as it first appears.
>> Most check rules are just as fundemental as touchability. If I
>> to trigger the pail-of-water-over-the-door trap with an
>> instead rule, I've got to make sure the door is unlocked
>> myself, since I'll be intefering before that check is run.
>
> Sounds like a trap like that should be an after rule.

Yup.

>> 3. Carry Out: It is the right place to intervene when I need
>> to block an action after the check rules have ensured it is
>> entirely sensible.
>
> I think I'd end up blocking it by writing additional check rules.

That's the phase I left out; I find it very frustrating to
intervene with check rules, because often the order that check
rules take place is criticial; I often want to place my new rule
precisely in the evaluation order of check rules, but the tools
for this are heavy and blunt.

>> 4. After: Here the action has taken place. I can report it in
>> my own way, or cause something to happen in addition to the
>> normal behavior. I think this is the most useful phase in
>> which to intervene.
>
> As long as the action does the intended thing (opening or
> unlocking a door, etc.), then yes. Some actions block at the
> check phase, though, so after rules will never run. You need
> instead rules for those.
>
>> 5. Report: I'll never need to use this unless I'm writing my
>> own new action.
>
> Pretty much, though I think you can vary messages by swapping
> them out instead of writing extremely general After rules.

This runs up against a (possible) efficiency problem with
over-using procedural rules. They get called a *lot*. Run a game
with "rules all" and just one procedural rule. It's scary, and
can turn out to be a big deal, as it did with the first version
of the Library Messages extension.

>> Do not use Before, and consider carefully before using
>> Instead.
>
> I'd say that Before is strictly for interlocutory actions or
> for actions that the world model says should be impossible, but
> which you don't want to have be impossible.
>
> Instead is for making things that should be legal impossible.
> For example, I have a room in my WIP called "Limbo". Some
> rooms can change their exits, but you can't really *remove* an
> exit as far as I've been able to tell. So, it instead points
> at Limbo, and Instead of going to Limbo, say "You can't go that
> way." Instead rules are also for intervening with the "actions
> that do nothing unless rules intervene", which have no carry
> out phase and which are by default blocked during Check. This
> is most of the exotic actions.

Yes, good thoughts.

--
Neil Cerutti
Facts are stupid things. --Ronald Reagan

Rioshin an'Harthen

unread,
Jun 30, 2006, 8:58:41 AM6/30/06
to
"Neil Cerutti" <lead...@email.com> wrote:
> On 2006-06-29, Michael Martin <mcma...@gmail.com> wrote:
>> Neil Cerutti wrote:
>>> 1. Before: This is before anything has been checked, even
>>> touchability. Not terribly useful, that. On the other hand,
>>> I6's before properties worked this way, and most players
>>> ignored the thousands of unfixed bugs this caused. Authors who
>>> routinely used ObjectIsUntouchable() in their before routines
>>> are exempt from this criticism. I don't see many hands up. ;)
>>
>> It's also done before checking whether you can actually go in a
>> direction. So, a generic can't go message can use "Instead of
>> going nowhere from the Kitchen", but a rule for "Instead of
>> going north from the Kitchen" will never fire. You can,
>> however, do a "Before going north when the location is the
>> Kitchen" rule for custom direction-refusal messages.
>
> Thanks. I didn't know that, and will definitely run into that
> wrinkle in my WIP.

Or you can use the extension "Instead of Going", where you can set some text
properties on rooms and let the extension take care of displaying the
required messages. Currently available at the if-archive, in

http://www.ifarchive.org/indexes/if-archiveXinfocomXcompilersXinform7Xextensions.html


Andrew Plotkin

unread,
Jul 4, 2006, 12:15:31 PM7/4/06
to
Here, ems...@mindspring.com <ems...@mindspring.com> wrote:
>
> Neil Cerutti wrote:
> > In Inform 7, I can intervene in several places:
> >
> > 1. Before: This is before anything has been checked, even
> > touchability. Not terribly useful, that.
>
> I find I most often use this in one of these ways:
>
> 1) to generate an implicit action which needs to happen before the
> check or even the touchability rules. For instance, if I want to have
> the player automatically try opening a glass case before doing anything
> with the ivory elephant inside, this would be a good place to put that
> in.
>
> 2) to refuse actions that are not just physically impossible but
> illogical or prohibited by the PC's morals or taste.

Also to "redirect" actions:

Before taking the aspirin: instead try eating the aspirin.

Touchability is not an issue, because it will be checked in the
"eating" action.

But I admit that I tend to write:

Instead of taking the aspirin: try eating the aspirin.

...purely because it reads more smoothly. This does a redundant
touchability check, but I don't care. (If eating had special reach
rules, I might care.)

For the record, I consider this entire thread to be an indictment of
the "divide each action into N phases" pattern.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
If the Bush administration hasn't subjected you to searches without a
warrant, it's for one reason: they don't feel like it. Not because of
the Fourth Amendment.

ems...@mindspring.com

unread,
Jul 4, 2006, 2:47:50 PM7/4/06
to

Andrew Plotkin wrote:
> For the record, I consider this entire thread to be an indictment of
> the "divide each action into N phases" pattern.

Hm. Obviously there are times when one wants to intervene in an unusual
place (but I've generally been able to figure out how to do this). On
the other hand, I think not having the phases there for shorthand would
*usually* make actions take much longer and be much more cumbersome to
write.

Possibly I am not correctly imagining the alternatives, though.

Andrew Plotkin

unread,
Jul 4, 2006, 11:30:57 PM7/4/06
to
Here, ems...@mindspring.com <ems...@mindspring.com> wrote:
>
> Andrew Plotkin wrote:
> > For the record, I consider this entire thread to be an indictment of
> > the "divide each action into N phases" pattern.
>
> Hm. Obviously there are times when one wants to intervene in an unusual
> place (but I've generally been able to figure out how to do this). On
> the other hand, I think not having the phases there for shorthand would
> *usually* make actions take much longer and be much more cumbersome to
> write.

The problem I'm trying to pin down is that it's *not* a shorthand, in
any clear sense. We all seem to be going through this process where we
try to use before/instead/check/report; get confused; chart out
exactly what happens at each step; decide which steps we want to
insert the hook at; pick the phase that matches our desire.

If this is shorthand, why does it feel like poking with a stick and
then looking to see what the stick hit? And what's the wordier but
more generic structure that each kind of rule is shorthand *for*?

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

It used to be that "conservatives" were in favor of smaller government,
fiscal responsibility, and tighter constraints on the Man's ability to
monitor you, arrest you, and control your life.

Stephen Granade

unread,
Jul 5, 2006, 9:56:35 AM7/5/06
to
Andrew Plotkin <erky...@eblong.com> writes:

> Here, ems...@mindspring.com <ems...@mindspring.com> wrote:
> >
> > Andrew Plotkin wrote:
> > > For the record, I consider this entire thread to be an indictment of
> > > the "divide each action into N phases" pattern.
> >
> > Hm. Obviously there are times when one wants to intervene in an unusual
> > place (but I've generally been able to figure out how to do this). On
> > the other hand, I think not having the phases there for shorthand would
> > *usually* make actions take much longer and be much more cumbersome to
> > write.
>
> The problem I'm trying to pin down is that it's *not* a shorthand, in
> any clear sense. We all seem to be going through this process where we
> try to use before/instead/check/report; get confused; chart out
> exactly what happens at each step; decide which steps we want to
> insert the hook at; pick the phase that matches our desire.

I go through that process on occasion, but far more often I'm able to
pick a phase and be right. The only alternative I can see would be to
have every rule named, and then specify what old rule a new rule goes
before or after. Otherwise you're lumping rules into rulebooks, and
that's effectively what the before/instead/check/after/report phases
are doing. The action-in-phases approach has a number of edge cases
which require brow-furrowing thought, but that doesn't happen enough
for me to want to junk the whole system.

Stephen

--
Stephen Granade
stephen...@granades.com

Andrew Plotkin

unread,
Jul 5, 2006, 1:04:00 PM7/5/06
to
Here, Stephen Granade <stephen...@granades.com> wrote:
> Andrew Plotkin <erky...@eblong.com> writes:
>
> > Here, ems...@mindspring.com <ems...@mindspring.com> wrote:
> > >
> > > Andrew Plotkin wrote:
> > > > For the record, I consider this entire thread to be an indictment of
> > > > the "divide each action into N phases" pattern.
> > >
> > > Hm. Obviously there are times when one wants to intervene in an unusual
> > > place (but I've generally been able to figure out how to do this). On
> > > the other hand, I think not having the phases there for shorthand would
> > > *usually* make actions take much longer and be much more cumbersome to
> > > write.
> >
> > The problem I'm trying to pin down is that it's *not* a shorthand, in
> > any clear sense. We all seem to be going through this process where we
> > try to use before/instead/check/report; get confused; chart out
> > exactly what happens at each step; decide which steps we want to
> > insert the hook at; pick the phase that matches our desire.
>
> I go through that process on occasion, but far more often I'm able to
> pick a phase and be right. The only alternative I can see would be to
> have every rule named, and then specify what old rule a new rule goes
> before or after.

I agree that this would be terrible.

> Otherwise you're lumping rules into rulebooks, and
> that's effectively what the before/instead/check/after/report phases
> are doing.

Yes. Except your "otherwise" is unduly pessimistic. The lack of
obvious alternatives has not caused me to give up.

Nor should it stop us from diagnosing the flaws of the system we have,
which was my actual point. I7 does not seem to have a general model
for which before/instead/etc. are convenient shortcuts. They are
instead primary elements of the model, which makes them (IMHO)
unnecessarily ponderous.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

na...@natecull.org

unread,
Jul 5, 2006, 9:09:36 PM7/5/06
to

Andrew Plotkin wrote:
> Nor should it stop us from diagnosing the flaws of the system we have,
> which was my actual point. I7 does not seem to have a general model
> for which before/instead/etc. are convenient shortcuts. They are
> instead primary elements of the model, which makes them (IMHO)
> unnecessarily ponderous.


Hmm.

I've been doing some poking at Prolog for IF, and it seems like in many
ways it's the IF platform of my dreams. From raw string atoms and
predicates I can not only construct all the low-level I7 semantics of
objects, values, and relationships, but I can also do advanced AI-type
search queries. Best of all, since there's no semantics for symbols
inferred by the compiler at all, I can essentially write my own
domain-specific language very similar to I7 and 'compile' it when the
game first starts - do nice things like infer rules that aren't
specified - ie, given just a symbolic name for an object, assume that
its printing name is the same unless overridden... given a compass
direction exit from a room, assume that the reverse direction leads
back unless otherwise told... all that good I7 stuff. But without
requiring a natural language syntax. (But if we wanted a natural
language syntax, there's a recursive descent parser built right in, and
I don't think it would be that hard to implement most of I7's NI syntax
as a thin layer over Prolog predicates.) Forward declarations of
symbols (which are so nice to have in IF, and are a real pain in
conventional languages like Python or Javascript) are not a problem.
It's such a raw, bare-metal yet extensible system that we can
essentially sculpt it to be anything we want. (The downside is it might
be a bit slower to do property accesses, especially if implemented over
a VM like Glulx - it's always a tradeoff of efficiency vs flexibility).

One thing Prolog doesn't have built-in though, is rules of the I7 form
that match in order of generality, or with names so they can be turned
on or off. I can implement a mechanism like this, I think, given a bit
of sorting of the rules at load-time - but I'm wondering what might be
the best, most general way to represent these kind of rules.

Sample syntax:

rule(rulebook, my-rule-name, [list of conditions], [list of actions])

where the conditions and actions would be Prolog predicates to be run.
That represents what we have in I7 right now - but is that the best
form for rules to be in?

Another issue with Prolog is that, though it has a global namespace,
using it for global variables is considered poor form. I *could* write
Inform in Prolog, with lots of globals, but I'm not sure if it's the
best way of passing things like 'current action' around. (The only
other way that comes to mind is passing 'current action' as a parameter
to every rule, which seems a bit bondage-and-discipline.)

But anyway, my point is, if we wanted to start hacking on ideas about
how best to represent rule-type-things, Prolog could be a really useful
testbed environment. (I'd really like to implement a Warren Abstract
Machine in Glulx, but I read the WAM book and it melted my brain, so
that may take a while.)

Richard Bos

unread,
Jul 6, 2006, 5:45:05 PM7/6/06
to
na...@natecull.org wrote:

> Andrew Plotkin wrote:
> > Nor should it stop us from diagnosing the flaws of the system we have,
> > which was my actual point. I7 does not seem to have a general model
> > for which before/instead/etc. are convenient shortcuts. They are
> > instead primary elements of the model, which makes them (IMHO)
> > unnecessarily ponderous.
>
> Hmm.
>
> I've been doing some poking at Prolog for IF, and it seems like in many
> ways it's the IF platform of my dreams.

In theory, for the decision engine, yes, for all the reasons you
mention. It's a bugger to get the gameplay mechanics (main loop, text
entry, parser, restoring the game state on a restart &c.) working in it,
though. In the end, I just gave up.
IYAM, what you really need is a hybrid of something else, probably
something ordinarily imperative, for the crude mechanicals, with a
Prolog-alike for the decision making. Somewhat like I7 uses I6
underneath, but more out in the open.

Richard

Theodore Murdock

unread,
Jul 7, 2006, 4:34:36 AM7/7/06
to
Andrew Plotkin wrote:
> Before taking the aspirin: instead try eating the aspirin.
>
> Touchability is not an issue, because it will be checked in the
> "eating" action.
>
> But I admit that I tend to write:
>
> Instead of taking the aspirin: try eating the aspirin.

You're making a very good point here, and I'm sure you could come up
with a better example of what you're talking about, but both of these
examples are abysmal code, if you think of the consequences.

This is the perfect example of something that is very, very hard to
implement in any of the phases discussed here. Instead, it must
primarily be implemented the 0th phase: grammar. Otherwise, since the
command "get" results in the action 'take', typing "get aspirin" will
result in an attempt to 'eat' it, which will, in turn, result in an
attempt to 'take' it (if it is not held). There is a danger of infinite
recursion here, though the parser is smart enough to break the
loop--but not in a graceful way. We get some pretty ugly output:

[results]
>get aspirin
You eat the aspirin. Not bad.

Taken.
[/results]

The way the parser breaks the loop causes the messages to be printed in
the wrong order, so the aspirin appears to have been eaten before it
was picked up, but that's hardly the worst part: the player just
attempted to pick the aspirin up, but now the aspirin no longer exists.
If you had any plans for that aspirin--that the player must take it at
the right time, or give it to the right person--all of those plans are
now moot, because the player can't even pick it up witout swallowing
it! If there was a poster child for avoiding the use of 'before' or
'instead of' rules, this is it.

The right way to do this is with grammar. If there's only one pill in
the game, we would simply write:

Understand "take [the aspirin]" as eating.

...and if there's more than one, we'd create a class:

A pill is a kind of thing.
The aspirin is a pill.
Understand "take [a pill]" as eating.

There's still one minor issue here: if the player is used to writing
"take" when they want to pick things up, they may eat it when they try
picking it up. If we can assume they will have access to the "undo"
command, and that they will actually undo the action and try typing
"get aspirin" instead, it's not too big of a problem. There's
definately a trade-off going on here: we're trying to make the game
react better to English, but we're losing a bit of predictability--the
same words no longer result in the same actions.

If we want to make "take aspirin" react according to some more detailed
context (not just whether it's a pill, but also any other testable
condition), we could use a faux action. In this case, I'm going to
assume the player wants to get the pill if they aren't holding it, and
eat it if they already are holding it (using a faux action named
"swaking"--a portmanteau of "swallowing" and "taking"):

[code]
Understand "take [the aspirin]" as swaking.

Swaking is an action applying to one thing.

Before swaking:
if the noun is carried begin;
try eating the noun instead;
otherwise;
try taking the noun instead;
end if.
[/code]

...now if the player tries to "take" the aspirin, they will pick it up
if they aren't holding it, but they'll eat it if they're already
holding it. We still can't tell what the player wants to do when they
say "take", but at least this way we're being moderately safe and
moderately helpful: it's unlikely that they'll swallow the pill
accidentally, potentially putting the game in an unwinnable state, and
it's still possible to swallow the pill by saying "take the aspirin".

Using a before rule is a little safer than a "carrying out" rulebook
for faux actions like this, which play a role as executable grammar,
since some actions you might generate based on the player's input might
not require touchability, but a default verb like this does require
touchability. In this case, however, the only difference would be a
redundant touchability check if the rulebook were used instead of a
before rule.


On second thought, it might be better to just ask the player what they
want to do in ambiguous situations like this, preserving the
predictability of commands, while suggesting unambiguous alternative
phrasings to the player. It would still require a faux action with a
before rule (touchability should *not* be checked) but give a different
result:

Before swaking:
say "I'm sorry, I didn't understand. Do you want to swallow [the
noun] or pick it up?";
stop the action.

...it's also necessary to add grammar so that the pill can be swallowed
(otherwise you'll discover that "there's nothing suitable to drink
here"):

Understand "swallow [the aspirin]" as eating.

--Theodore

Neil Cerutti

unread,
Jul 7, 2006, 8:35:17 AM7/7/06
to
On 2006-07-07, Theodore Murdock <theodor...@yahoo.com> wrote:
> On second thought, it might be better to just ask the player
> what they want to do in ambiguous situations like this,
> preserving the predictability of commands, while suggesting
> unambiguous alternative phrasings to the player. It would still
> require a faux action with a before rule (touchability should
> *not* be checked) but give a different result:

Check out the section on Understanding mistakes. That mechanism
would allow you to avoid creating an action just for an error
message.

--
Neil Cerutti

Andrew Plotkin

unread,
Jul 7, 2006, 4:19:40 PM7/7/06
to
Here, Theodore Murdock <theodor...@yahoo.com> wrote:
> Andrew Plotkin wrote:
> > Before taking the aspirin: instead try eating the aspirin.
> >
> > Touchability is not an issue, because it will be checked in the
> > "eating" action.
> >
> > But I admit that I tend to write:
> >
> > Instead of taking the aspirin: try eating the aspirin.
>
> You're making a very good point here, and I'm sure you could come up
> with a better example of what you're talking about, but both of these
> examples are abysmal code, if you think of the consequences.

Okay, you're right. I was scrabbling for an example of "action
redirection", and I didn't think about the consequences. :)
(Auto-take, in this case.)

If I had used an example from actual code I'd written, it would have
been:

Instead of entering the ivied arch, try going north.

or

Instead of tying something (called X) to something (called Y), try
contacting X with Y.

> This is the perfect example of something that is very, very hard to
> implement in any of the phases discussed here. Instead, it must
> primarily be implemented the 0th phase: grammar.

One of the hard problems I keep confusing myself with is: what kind of
rule model would let you wrap an exception "around" existing code,
without disturbing what was inside? So that you *could* say what I
said, and the initial redirect (to "eat") would occur, but the inner
action (auto-take) would not be affected?

In other words, it should be possible to define something analogous to
a closure for rules.

(You can of course break up the idea of "taking" into two sorts --
explicit and implicit -- but this is just what I don't want to have to
do. In functional programming, an identifier is bound to two different
values in two different contexts -- that's the meaning of a closure --
but the programmer doesn't have to grot around with renaming them.)

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't thrown you in military prison without trial,
it's for one reason: they don't feel like it. Not because you're an American.

na...@natecull.org

unread,
Jul 8, 2006, 3:12:36 AM7/8/06
to

Andrew Plotkin wrote:
> One of the hard problems I keep confusing myself with is: what kind of
> rule model would let you wrap an exception "around" existing code,
> without disturbing what was inside? So that you *could* say what I
> said, and the initial redirect (to "eat") would occur, but the inner
> action (auto-take) would not be affected?

> In other words, it should be possible to define something analogous to
> a closure for rules.

Not quite following you - can you give another example? Do you want to
redirect "eat" without triggering the auto-take, or leave the auto-take
trigger in place?

I guess my first reaction to the aspirin example is none of the above:
I would naturally try implementing it as:

Instead of taking the aspirin when the noun is carried: try eating the
noun.

Though I suppose that may fall foul of things like the pre-checks for
reachability and such so might still be a useful example.

I presume you want a model where pretty much everything is a rule - and
maybe we could group rules together and give them a name as a nestable
block?

Let's see:

* "take [object]" -> action(take, [object])
* "take [object]" (if object is a medicine and object is carried) ->
action(eat, [object])

(Ouch, we already need a way to unambiguously determine which of two
rules takes precedence - a rigid compile-time kind hierarchy like I7 is
one way, and easy enough to predict, but I'm not entirely convinced
that it's the way forward. Seems to me that most IF world objects are
dynamically typed and are more likely to have adjectives/attributes
that change at runtime than inviolate kinds).

Also it seems to me that there ought to be a reasonably hard line
between "parser" (or narrator) and "world" - on the assumption that we
should have a model that scales up nicely to deal with MUD-type
multiplayer. The parser module should concern itself with resolving a
player's text string into an unambiguous action that can be submitted
to a separate world module that treats action events coming from
multiple players or NPCs equally. So the resolution between "take" as
'pick up' and as 'eat' should be sorted long before the results of the
action are evaluated.

Also cases like "enter doorway" redirecting to "go north", in this
parser/narrator vs world separation model, are things that would belong
fairly specifically to the narrator module - they both resolve to the
same identical player action before the world model gets to care. So I
think there should be at least two separate phases. Well, three. Parse,
Act, Report. (Since Parse and Report would belong to the narrator
module, and Act to the world module). Beyond that, I'm not sure.

Andrew Plotkin

unread,
Jul 8, 2006, 10:26:39 AM7/8/06
to
Here, na...@natecull.org wrote:
>
> Andrew Plotkin wrote:
> > One of the hard problems I keep confusing myself with is: what kind of
> > rule model would let you wrap an exception "around" existing code,
> > without disturbing what was inside? So that you *could* say what I
> > said, and the initial redirect (to "eat") would occur, but the inner
> > action (auto-take) would not be affected?
>
> > In other words, it should be possible to define something analogous to
> > a closure for rules.
>
> Not quite following you - can you give another example? Do you want to
> redirect "eat" without triggering the auto-take, or leave the auto-take
> trigger in place?

I meant, leaving the auto-take in place.

This is, I agree, a bad way of handling the game-design case of an
aspirin that the player will swallow. But it's still an example of a
rule customization that I might want: override "take X" without
damaging the autotake functionality of other verbs. It can easily be
done by thinking in phases or having two kinds of "take" action. How
would it be done from a strictly rules perspective? (Keeping in mind
that, of course, sometimes you *do* want to override both explicit and
implicit take.)

> Also it seems to me that there ought to be a reasonably hard line
> between "parser" (or narrator) and "world"

Yes, I agree. But this doesn't free us from the desire to be able to
do anything *inside* the action/world model. If the rule system can't
handle this stuff, it isn't good enough.

As usual, this is easy to denote for the simple case. Ignore the ugly
syntax:

Replace Take (if noun is pill) with Take2: [ <Eat pill> ].

Replace Take (if noun is pill) with Take: [ <Eat pill> ].

Each of these overrides the <Take pill> action. With the first form,
the original Take action is still called Take (after the
customization), and the new version is called Take2. The implicit
action code, calling <Take pill>, will *not* be diverted into an Eat.

In the latter form, the original action winds up nameless, and the new
version is called Take. The implicit action code will be diverted.
(Into an infinite loop, but that's not the point here.)

So this notation does express what I want, but it's doing it by
rearranging a global namespace. That doesn't scale: as soon as you
write two customizations on the same action, you have a headache. This
is why I think of functional closures, which let you "reassign"
identifiers in a tiny little world, without affecting the rest of the
program.

> So I think there should be at least two separate phases. Well,
> three. Parse, Act, Report. (Since Parse and Report would belong to
> the narrator module, and Act to the world module). Beyond that, I'm
> not sure.

I'll go with Parse and Act as a clear division. Report is harder,
because actions nest inside other actions -- implicit actions, "take
all", etc. There's no point in time that is after all the doing but
before all the printing. (For a single command -- the player's view
thereof, I mean. I am not worried about "take pill. eat pill" here.)

So Report isn't a phase in the sense that the others are. You
certainly want to be able to customize just the reporting part of an
action, but I think if you insist on viewing it as sticking diversions
into a linear stream, you are doomed to disappointment.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

It's a nice distinction to tell American soldiers (and Iraqis) to die in
Iraq for the sake of democracy (ignoring the question of whether it's
*working*) and then whine that "The Constitution is not a suicide pact."

Theodore Murdock

unread,
Jul 9, 2006, 2:50:51 PM7/9/06
to

Andrew Plotkin wrote:
> Replace Take (if noun is pill) with Take2: [ <Eat pill> ].
>
> Replace Take (if noun is pill) with Take: [ <Eat pill> ].
>
> Each of these overrides the <Take pill> action. With the first form,
> the original Take action is still called Take (after the
> customization), and the new version is called Take2. The implicit
> action code, calling <Take pill>, will *not* be diverted into an Eat.
>
> In the latter form, the original action winds up nameless, and the new
> version is called Take. The implicit action code will be diverted.
> (Into an infinite loop, but that's not the point here.)
>
> So this notation does express what I want, but it's doing it by
> rearranging a global namespace. That doesn't scale: as soon as you
> write two customizations on the same action, you have a headache. This
> is why I think of functional closures, which let you "reassign"
> identifiers in a tiny little world, without affecting the rest of the
> program.

Since one of the goals of I7 is making programming accessable to
non-programmers, I'm not sure it's intelligent to start building in a
lot of different kinds of name-space...we already have
chapters/sections playing a namespace role, and the problem you're
suggesting exists here is easily avoided by using names intelligently.

It is *never* a good idea to name a verb (or any variable or function)
randomly, with a meaningless name like "take2", and yes, if you use
meaningless, non-specific names, you will have lots of problems with
namespace. If, on the other hand, we use meaningful, specific names,
like "TakePill", then if we find the need to re-implement the verb Take
again for another purpose, we don't find ourselves scratching our heads
to remember what number we're on, and we don't have to worry about
namespace.

When it comes to the time that we're implemeting something tricky that
requires us to re-implement the verb again, we just give it another
sensible, unique, and meaningful name...if we're implementing a Niffler
(JK Rowling's gold-loving magical creature), and we find that it's
easier to re-implement Take than to modify Take to respond properly to
the Niffler, we'll call the new verb "TakeNiffler". Not only will we
avoid namespace problems, but when we come back and look at the code
later, we'll be able to remember what it's for much more quickly.

I don't think we need a new kind of namespace to resolve this kind of
issue: we just need to use best coding practices, including
self-commenting, meaningful names. The bottom line is, if you have two
verbs that do slightly different things, there must be a reason for
that difference. If you put that reason into the name for the verb, you
will automatically have a unique name for every verb. Some of those
names might become a little verbose when they need to, but they save
you a lot of pain in the end.

Andrew Plotkin

unread,
Jul 9, 2006, 3:37:55 PM7/9/06
to
Here, Theodore Murdock <theodor...@yahoo.com> wrote:
>
> Andrew Plotkin wrote:
> > Replace Take (if noun is pill) with Take2: [ <Eat pill> ].
> >
> > Replace Take (if noun is pill) with Take: [ <Eat pill> ].
> >
> > Each of these overrides the <Take pill> action. With the first form,
> > the original Take action is still called Take (after the
> > customization), and the new version is called Take2. The implicit
> > action code, calling <Take pill>, will *not* be diverted into an Eat.
> >
> > In the latter form, the original action winds up nameless, and the new
> > version is called Take. The implicit action code will be diverted.
> > (Into an infinite loop, but that's not the point here.)
> >
> > So this notation does express what I want, but it's doing it by
> > rearranging a global namespace. That doesn't scale: as soon as you
> > write two customizations on the same action, you have a headache. This
> > is why I think of functional closures, which let you "reassign"
> > identifiers in a tiny little world, without affecting the rest of the
> > program.
>
> Since one of the goals of I7 is making programming accessable to
> non-programmers, I'm not sure it's intelligent to start building in a
> lot of different kinds of name-space...we already have
> chapters/sections playing a namespace role, and the problem you're
> suggesting exists here is easily avoided by using names intelligently.

I'm not sure it's so easily avoided. Giving everything a separate name
is like giving everything a separate line number in BASIC: the perfect
solution for your first program, and a disaster for the long term.

> It is *never* a good idea to name a verb (or any variable or function)
> randomly, with a meaningless name like "take2"

I did say the syntax was ugly. I don't think that syntax is good
enough, *regardless* of what labels are chosen. It doesn't scale; you
cannot keep throwing in new names without winding up in spaghetti
code. The point of that example was to distinguish two different
things that "replacing the take action" might mean. If we can't do
that, we don't even have a start of a solution.

> The bottom line is, if you have two verbs that do slightly different
> things, there must be a reason for that difference.

It's not two verbs. It's one verb that can do two slightly different
things, in different contexts. We do not currently have a clean notion
of the context of an action; we have, at best, some global variables
that get torqued around. (Again, see BASIC.)

No, I don't want to throw new IF programmers in with namespaces, day
1. But the idea of closures is not necessarily a complex or confusing
idea. Closures are a functional-language notion of "context", so I
think they, or something like them, may have leverage here.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't thrown you in military prison
without trial, it's for one reason: they don't feel like it. Not

because of the Fifth Amendment.

Andrew Plotkin

unread,
Jul 9, 2006, 3:46:42 PM7/9/06
to
Here, Andrew Plotkin <erky...@eblong.com> wrote:
> We do not currently have a clean notion of the context of an action;
> we have, at best, some global variables that get torqued around.

On second thought, the I7 "activity" model is a notion of contexts.
You can say "Rule for X while taking the pill..." and so on. And
activities can happen inside other activities, so it's better than
global variables.

To stretch an analogy -- maybe not too far: I7 uses dynamic scoping
for its action context model. I'd be more comfortable with static
scoping. That's why I keep thinking of pure-functional languages,
and closures, as a model. (But I don't think static scoping is prima
facie better; I just want to consider it as a tool to solve these
problems.)

Daryl McCullough

unread,
Jul 9, 2006, 7:29:57 PM7/9/06
to
Andrew Plotkin says...

>
>Here, Andrew Plotkin <erky...@eblong.com> wrote:
>> We do not currently have a clean notion of the context of an action;
>> we have, at best, some global variables that get torqued around.
>
>On second thought, the I7 "activity" model is a notion of contexts.
>You can say "Rule for X while taking the pill..." and so on. And
>activities can happen inside other activities, so it's better than
>global variables.
>
>To stretch an analogy -- maybe not too far: I7 uses dynamic scoping
>for its action context model. I'd be more comfortable with static
>scoping. That's why I keep thinking of pure-functional languages,
>and closures, as a model. (But I don't think static scoping is prima
>facie better; I just want to consider it as a tool to solve these
>problems.)

Interesting. The only thing I know about dynamic scoping was
some comments about the original implementation of Lisp interpreters.
The author considered it to be a "mistake", although it's hard to
tell a bug from a feature sometimes.

As I understand it, the distinction between dynamic and static scoping
is illustrated as follows. I don't remember Lisp syntax, so I'll
just make up some syntax. I'll do it Inform style, with the programmers
commands prefaced by a prompt, followed by the interpreter's response.

>Let x = 5.
x defined.

>Define plus_x(y) = y+x;
plus_x defined.

>plus_x(2)
7

>Let x = 3.
x redefined.

>plus_x(2)
5

So in dynamically scoped Lisp, to evaluate a function, one
uses the *current* values of state variables, rather than the values
at the time the function is defined.

The "correct" way to do it is to save the state of all variables
at the time that a function is defined, and to use that saved
state to compute the function. Is that what is meant by a "closure"?

--
Daryl McCullough
Ithaca, NY

John Prevost

unread,
Jul 9, 2006, 9:54:21 PM7/9/06
to

Andrew Plotkin wrote:
> It's not two verbs. It's one verb that can do two slightly different
> things, in different contexts. We do not currently have a clean notion
> of the context of an action; we have, at best, some global variables
> that get torqued around. (Again, see BASIC.)

I agree that there's a problem, but not that there's only one verb
here. In my eyes, the right thing to do for "take pill" is something
like:

Medicine is a kind of thing. Understand "take [medicine]" as eating.
A pill is on the table. The pill is medicine.

Just because the morphemes are the same (the shape of the words)
doesn't mean that they represent the same lexeme (lexical entry). This
is even more obvious with an idiom like "take [something] down", which
has a more specific form that must be followed, and maps that entire
form to one lexeme.

The trouble is that knowing which lexical entry (understood phrase)
will map to which action (lexical verb) potentially becomes very
difficult as times goes on.

In addition, there's the trouble that implicit behaviors in I7 are very
much under-the-covers, which means that even though a person will
understand "take X" as meaning to ingest medicine, they could also mean
"take X" to pick it up (standard informese), and you're right that
there doesn't seem easy way to hook into the process of "taking while
eating" here.

There's a part of me that thinks that part of the problem is the mix of
an I6 base and an I7 topping. I understand why: the standard I6
library has all of these wonderful elaborations in the parser which
make "informese" so powerful. But on the downside, using that instead
of constructing everything specifically for I7 means that some
behaviors (like implicit actions) are very black magic from the Inform
7 side. They behave sort of like you'd write implicit actions in I7...
but not entirely. And the kinds and relations that I6 knows about
behave mostly like relations defined in I7... but not entirely.

I *think* that the subtyping system of I7 combined with the ability to
write more specialized patterns for things can deal with a good amount
of the spaghetti-code confusion--although it might be nice to have an
interactive tool that you can ask "what will 'foo bar baz' mean?" It
may require some care, and some portions of the game's model will
almost certainly have to change as new problems as discovered, but I
think it can be done.


I'm very interested to see how things go, in any case.

Andrew Plotkin

unread,
Jul 9, 2006, 10:14:39 PM7/9/06
to
Here, John Prevost <j.pr...@gmail.com> wrote:
>
> Andrew Plotkin wrote:
> > It's not two verbs.

(Footnote: would have been clearer if I'd said "actions", not "verbs.")

> > It's one verb that can do two slightly different
> > things, in different contexts. We do not currently have a clean notion
> > of the context of an action; we have, at best, some global variables
> > that get torqued around. (Again, see BASIC.)
>
> I agree that there's a problem, but not that there's only one verb
> here. In my eyes, the right thing to do for "take pill" is something
> like:
>
> Medicine is a kind of thing. Understand "take [medicine]" as eating.
> A pill is on the table. The pill is medicine.

Sigh, that's just what Nate was saying when I *gave* that example. My
note about it was:

> But this doesn't free us from the desire to be able to do anything
> *inside* the action/world model. If the rule system can't handle
> this stuff, it isn't good enough.

In other words, *forget* the parser here: I am talking about what
capabilities the action system must have. There are many ways of
triggering an action -- in this example, two of them are parsing "take
aspirin" and the implicit-take mechanism. Maybe elsewhere in the code
there's a "try taking the aspirin" line; that would be a third.

The question is, are we able to add a customization in one aspect of
this taking action without disturbing the others? Can we, in other
words, extend the system without breaking the parts that already exist
(and already work)?

And can we take the other path: customize all parts of the system,
without missing any? Because sometimes we want to do one, and
sometimes we want to do the other. If the rule model can't fluently
handle both, it's not good enough.



> There's a part of me that thinks that part of the problem is the mix of
> an I6 base and an I7 topping.

That is a problem, in that we don't have a consistent solution to
these questions. I like to think that we will know I7 is successful
when darkness, implicit taking, containers, and so forth are deleted
from the standard world model entirely, and are instead available as
(short) (pure-)I7 extensions.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't shipped you to Syria for interrogation,
it's for one reason: they don't feel like it. Not because you're patriotic.

Andrew Plotkin

unread,
Jul 10, 2006, 1:33:38 AM7/10/06
to
Here, Daryl McCullough <stevend...@yahoo.com> wrote:
> Andrew Plotkin says...

Yes.



> The "correct" way to do it is to save the state of all variables
> at the time that a function is defined, and to use that saved
> state to compute the function. Is that what is meant by a "closure"?

Yes; a closure is the function plus all the state saved at the time it
was defined.

But for actions, don't think of state (action definitions) changing
over time, the way your example does it. Think of state changing across
different *conditions*. That's what an action rule is: a definition of
an action under a particular condition. And the question is, what is
the scope of this redefinition? No single answer is right, so the
model needs some way of letting the author decide.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

na...@natecull.org

unread,
Jul 11, 2006, 7:44:57 AM7/11/06
to

Andrew Plotkin wrote:
> This is, I agree, a bad way of handling the game-design case of an
> aspirin that the player will swallow. But it's still an example of a
> rule customization that I might want: override "take X" without
> damaging the autotake functionality of other verbs. It can easily be
> done by thinking in phases or having two kinds of "take" action. How
> would it be done from a strictly rules perspective? (Keeping in mind
> that, of course, sometimes you *do* want to override both explicit and
> implicit take.)

Hmm... so: (thinking in Prolog for a moment here, since that's where my
brain is currently at)

run(Action, ActionResult),
Action = action(Actor, eat, Object,_,Result),
isa(Object, pill),
not(holding(player, Object)),
BeforeAction = action(Actor, take, Object, nothing)
run(BeforeAction,BeforeResult),
BeforeResult = succeeded,
run(Action, succeeded).

.. which is on a slight tangent, since I'm looking just at one rule and
you're talking more about how rules would interact and supercede each
other.

... and even there I'm running up against Prolog's lack of decent
conditionals or any block structure within clauses, and it still feels
a bit alien and in need of refactoring. I'm starting to think that
maybe I need a mechanism more general than naive Prolog rules (which is
what I figure anyway, since we need, eg, the ability to name any rule
so it can be replaced or modified by later code - and rule precedence
is a huge pain).

Break down everything into pattern-matching rewrite rules of some kind,
that grab events/messages as they go through a message-passing ether?
Some kind of weird mutant of OO and logic programming? I still think
logic programming solves a lot of problems associated with IF parsing
type situations, where you want to sort of tentatively propose a number
of options in various states of completeness until you settle on one
that satisfies all the constraints, and let that collapse as the
solution.. but OO message passing is also the natural way of looking at
some kinds of simulation. But more and more I'm thinking that the
standard OO inheritance-hierarchy and single-dispatch of methods is
pretty much useless in most IF simulation worlds (or frankly almost any
business model more complicated than toy examples, but most obvious in
the kinds of things we do in IF). And if you generalise multiple
dispatch far enough, you end up with a rule-based mechanism looking a
bit like I7's. What we want to do, it seems, is generalise that
mechanism until it can maybe encompass the whole of the game.

One of the major wins of logic programming, it seems to me, still
trying to get my head around it, is that it's trivially easy to have
data structures which are only partially filled in - as long as they
have a predictable *structure*, and rules which can infer the blank
bits from what's given. A lot of real-world information is like this -
partial knowledge plus overlapping rules of thumb. The trick though is
to know what it is that we're trying to find out - and running a
simulation isn't *quite* the same thing is querying a knowledge base.

But suppose we had a rewrite rule:

rewrite_action(Action, ActionList) :-
Action = action(Actor, eat, Object,_),
isa(Object, pill),
ActionList = [action(Actor,take,Object)|Action].

rewrite_action(Action, [Action]).

... run this in a recursive loop until it stops wriggling, then we get
a list of actions to attempt? And try them in order, stopping if one
fails? Still not a general rule mechanism, I know, and we should
probably be passing back results somehow... but if we can essentially
use higher-order functions/predicates on the OO-like messages that
we're passing between simulation objects, we could do a lot of this
kind of introspection stuff, I think.

> > So I think there should be at least two separate phases. Well,
> > three. Parse, Act, Report. (Since Parse and Report would belong to
> > the narrator module, and Act to the world module). Beyond that, I'm
> > not sure.
>
> I'll go with Parse and Act as a clear division. Report is harder,
> because actions nest inside other actions -- implicit actions, "take
> all", etc. There's no point in time that is after all the doing but
> before all the printing. (For a single command -- the player's view
> thereof, I mean. I am not worried about "take pill. eat pill" here.)

Mmm. Yes, I realised after I wrote that that I'm actually thinking
about modules, not necessarily phases - like a World module should send
a message to the Narrator module saying 'now Blofeld is shooting Bond'
and the Narrator should generate the text to describe this... but these
events would be intermixed in time and multiple of them could happen in
a single turn. Of course, for a typical IF all-sealed-in-one-unit game
it may well be simpler to just print a message as the event happens,
but carelessness about that seems to be where much
library-messages-replacement and NPC-unfriendly-events hell comes from.

0 new messages