I7 Planner extension V1 has been uploaded to ifarchive

11 views
Skip to first unread message

na...@natecull.org

unread,
Jun 7, 2006, 6:46:16 PM6/7/06
to
Uploaded via the Web form so not sure how long it will take...

Filename is I7PlannerV1.zip

I guess it appears in unprocessed and then should ultimately find its
way to
http://ifarchive.org/indexes/if-archiveXinfocomXcompilersXinform7Xextensions.html

steve....@gmail.com

unread,
Jun 7, 2006, 8:00:25 PM6/7/06
to
na...@natecull.org wrote:
> Uploaded via the Web form so not sure how long it will take...
>
> Filename is I7PlannerV1.zip

Surprising lack of introduction. Thanks anyway.

steve....@gmail.com

unread,
Jun 7, 2006, 8:08:23 PM6/7/06
to
I wrote:
> Surprising lack of introduction.

Oops, I forgot: it's self-documenting code. ;)

na...@natecull.org

unread,
Jun 7, 2006, 11:38:02 PM6/7/06
to

I did have a slightly more substantial post a few weeks back, when I
originally released it (though not to the ifarchive). And yes, the code
is documented, though somewhat minimally (via DOCUMENTATION section).
However raif is pretty high traffic at the moment and things tend to
scroll off so a precis is probably in order.

Planner is the I7 port of RAP, which is a cut-down bare-bones
goal-seeking library inspired by the Oz Project's HAP planner. I
released the original version for TADS around 1999, then an I6 version,
intended to release a Platypus version but got stuck, and now that I7
is out I've reimplemented it yet again.

You give it a triad of (relation, object, object) and a library of
rules that implement plans, and it then tries to make that statement
come true by backward-chaining a shortest path from the desired future
state to the current world state.

Its intelligence depends on what plans are programmed into it. Version
1 has some basic rules for travelling to rooms (using I7's built-in
shortest path routefinder), opening closed and locked objects, and
manipulating contained/supported objects. It does not yet cope
automatically with finding keys for locked doors, since that would
require completely rewriting the routefinder and I am lazy (and also
wanted to demo the non-routefinding aspects of Planner, since the first
question I often get is 'but doesn't I7 do routefinding automatically
so what's the point?')

There is an included demo 'game' which is amazingly lame but hopefully
shows a glimpse of what the engine is capable of and how to use it. The
syntax is rather scarily baroque but it's the best I can manage so far:
it really needs a language with list constructions, or at least more
generic data structures than the Z-machine provides. Hopefully it's
understandable. Drop me an email if you want help.

I don't pretend to actually know how to integrate Planner into a real
game. I wrote it because it was a fun thing to do, not because it
solves an actual problem.

I haven't yet specified licencing because I'm not sure what the
official Inform 7 standard for extensions will be (I presume CC-BY-SA,
but Public Domain may be more appropriate). Permission is hereby
granted to do whatever the heck you like with it.

chev...@gmail.com

unread,
Jun 8, 2006, 3:58:34 AM6/8/06
to
na...@natecull.org wrote:

> I don't pretend to actually know how to integrate Planner into a real
> game. I wrote it because it was a fun thing to do, not because it
> solves an actual problem.

I have high hopes for Planner. I'm hoping to use it to create a nasty
NPC that sneaks around looking for a weapon and ammunition and then
goes off trying to kill any NPCs that are friendly to the player and
then the player.

Alexander Deubelbeiss

unread,
Jun 9, 2006, 3:42:45 AM6/9/06
to
chev...@gmail.com wrote:

> I have high hopes for Planner. I'm hoping to use it to create a nasty
> NPC that sneaks around looking for a weapon and ammunition and then
> goes off trying to kill any NPCs that are friendly to the player and
> then the player.

And the PC's name will be Marjorie Hopkirk, of course.

Brian Campbell

unread,
Jun 9, 2006, 11:05:31 AM6/9/06
to
na...@natecull.org wrote:
> I haven't yet specified licencing because I'm not sure what the
> official Inform 7 standard for extensions will be (I presume CC-BY-SA,
> but Public Domain may be more appropriate). Permission is hereby
> granted to do whatever the heck you like with it.

Isn't the standard license the most permissive Creative Commons license
(CC-BY)? That's what it is according to
<http://inform-fiction.org/I7/Download%20-%20Extensions.html>, which is
admittedly under construction. It was my impression that that's what
license it had to be under to be eligible for the official I7
extensions page. Given that I7 extensions pretty much require you to
credit the author when you use them ("Include Locksmith by Emily
Short"), the creative commons attribution license makes perfect sense.
Of course, given that the public domain is even more permissive, that
would probably be fine, too.

-- Brian

steve....@gmail.com

unread,
Jun 10, 2006, 5:04:39 AM6/10/06
to
The extension has appeared in the ifarchive, thanks again. A few
questions.

I don't understand the claims you've made about how this version is
much different than previous versions. I look at it and I think, yes
it's the same algorithm. Could you identify where is the critical
difference, and why it's critical?

You complain that the language does not support lists. But you use
tables, and that seems to work fine. What's the advantage of doing the
same thing with lists?

You noted that the code is baroque, but it doesn't seem particularly
more (or less) baroque than other versions. What strikes me is how
unnatural it is, and I think this is what you mean -- but unnatural in
which way? By "baroque," do you mean that it reads like (*gasp*)
computer code? Are you making a point about programming in I7's NL-like
syntax?

If not the latter, could you share your feelings programming in I7's
NL-like syntax? This is the first bit of real programming I've seen
written in I7, and while I think it very obviously demolishes the NL
pretense, it also shows that I7 is a programming language (in the sense
that "programming language" is a good thing, after all). Still, it
seems counter-optimised for writing code; I wouldn't say baroque, as
that implies artistic. Kludgy perhaps?

Zonk the Troll Ghost

unread,
Jun 10, 2006, 10:51:02 AM6/10/06
to

steve....@gmail.com wrote:
> This is the first bit of real programming I've seen
> written in I7

Then what are, say, the full sample games written in I7? Examples of
non-programming? Wouldn't that imply that creating a complete work of
intereactive fiction with I7 doesn't require programming, an
implication that would undermine your thesis?

na...@natecull.org

unread,
Jun 11, 2006, 3:11:46 AM6/11/06
to
> I don't understand the claims you've made about how this version is
> much different than previous versions. I look at it and I think, yes
> it's the same algorithm. Could you identify where is the critical
> difference, and why it's critical?

It's the same core search algorithm, yes. The main difference is in how
it uses I7 rules to structure the rulebase. There are a few changes to
the internal storage of the planning table - no 'opcode' field, as it
uses Kind to distinguish between planning-relations and
planning-actions. Terminology has also changed to match I7, so it
refers to 'relations' rather than 'conditions'.

The way plans are written is similar to the I6 approach: each plan is
essentially a function responding to (actor, relation, object, object,
plan#, step#), but 'when' clauses in I7 rules are used to catch (actor,
relation, object, object). The 'plan [number]' and 'suggest [relation]
with [object] and [object]' phrase syntaxes are completely new. You
don't have to manually keep track of how many steps are in each plan
and report that number as 'step 0' as you did for I6. This should
making writing simple plans a lot easier.


> You complain that the language does not support lists. But you use
> tables, and that seems to work fine. What's the advantage of doing the
> same thing with lists?

When I originally wrote RAP, it was using TADS2 lists to store a plan.
So a plan there looked roughly like:

[
[
[<relation> <object1> <object2>]
[<relation> <object1> <object2>]
...
[<action> <object1> <object2>]
]
[
[ <relation> <object1> <object2>]
...
[<action> <object1> <object2]
]
...
]

so you could, from one 'generate me a plan' function, return a single
list construct containing a variable number of alternative plans, each
consisting of a variable number of steps. You could also put multiple
objects in each 'object' slot just by putting a list in, eo, eg, you
could handle >GET THE KEY AND THE PADLOCK as an action step. It could
also be expanded indefinitely if, for instance, at a later date you
decided you wanted to handle object specifications (>TAKE ALL THE RED
THINGS FROM THE BOX) etc, or add adverbs or a third object to
sentences. I never wrote code to handle any of these cases, and some of
them may have been impossible given the limitations of the TADS2
parser, but the capability for unlimited future expansion was certainly
there. Still is, in the TADS world.

Another very useful thing one could do with lists, which I didn't
implement in TADS but wrote some initial code to do in I6, was build a
capability for actors to not use *real* knowledge of the world state,
but each keep track of what they *believed* was the current state of
any given property of any given object. So they could, eg, when trying
to obtain a portable object, first try looking in the location where
they last knew it to be. This is a whole bigger kettle of fish, but it
would be the first step towards making RAP/Planner much more
interesting. Again, it *can* be implemented, to a first approximation,
using rigidly fixed-sized arrays in a Z-machine/I6 type world, but
doing so pretty much means that you force design constraints onto what
type of information can be stored, right up front. There's no
flexibility for change if the world model changes.

That's why lists are more flexible than arrays - they're infinitely
flexible. But they're also a real pain to implement in a language
because you have to build a dynamic memory allocator and garbage
collection system. TADS has this; the Z-machine really doesn't have
space to do it; Glulx has the capacity but would require the dynamic
memory allocation machinery built on top of it, and, probably, a new
language constructed from the ground up to use that capability.


> You noted that the code is baroque, but it doesn't seem particularly
> more (or less) baroque than other versions. What strikes me is how
> unnatural it is, and I think this is what you mean -- but unnatural in
> which way? By "baroque," do you mean that it reads like (*gasp*)
> computer code? Are you making a point about programming in I7's NL-like
> syntax?

Yes, the syntax reads like very tortured English in some cases - except
in the definition of rules, where it is mostly clearer. The main thing
that makes it cumbersome to me is the need to use lots of long 'when'
clauses on the rules, but also there is a fair bit of complication
based on the absence of any complex data structure type (not just
lists, but the simplest implementation of the 'plan' data structure
would use either lists or arrays). This is shared with the I6 version.

I probably need to write some documentation explaining exactly how the
'suggest...' phrase works, because it is not very straightforward, even
to me. The planning rules are reexamined for every step of every plan,
and that's not very efficient. But I don't think there's any more
straightforward way of doing what I'm trying to do, given the
facilities available in I6 and the Z-machine.

I should point out that creating extensible plans is pretty much
impossible to do properly in I6 compared to I7. The rule-based design
really, really shines here. Doesn't quite do everything right, but at
least each rule can be overridden. Trying to do that with object
inheritance was a nightmare of hooks and a large reason of why I
abandoned the project.


> If not the latter, could you share your feelings programming in I7's
> NL-like syntax? This is the first bit of real programming I've seen
> written in I7, and while I think it very obviously demolishes the NL
> pretense, it also shows that I7 is a programming language (in the sense
> that "programming language" is a good thing, after all). Still, it
> seems counter-optimised for writing code; I wouldn't say baroque, as
> that implies artistic. Kludgy perhaps?

Some random observations:

The 'phrase' construct is very powerful, but it can become very hard to
tell exactly what words in a sentence are purely syntax markers and
what are parameters.

The NL seems to work best when it is directly describing world model
elements. When one is writing code to deal with abstractions, it gets
trickier.

The table routines are pretty useful, though again I'm uncomfortable
with the way one is expected to just pile words into a phrase and hope
the compiler guesses correctly what is syntax, what is a literal, and
what is a variable name. Maybe parentheses will help here.

I don't like that I have to use lots and lots of globals, and that in
fact almost every operation (such as table operations) relies on lots
of implicit shared global state (such as which row is 'the current
row') that can break if, eg, you run a function between doing a table
row lookup and testing a table field. This seems to me a very 1950s way
of programming and I'd much prefer to be able to make things
function-call-safe. I think mostly this comes about because the
Z-machine is such a small machine, but it is also the way the I6
library is designed.


I'm interested, for the future, in trying to build a very small dynamic
language - maybe similar to Floo or Joy - on top of Glulx, with the
hope that this would make it possible to create an I7-like coding
environment inside the VM itself. I'm not sure that this is an entirely
sane dream, but given 3Ghz processors and a 2GB virtual RAM capacity
I'm not sure it's unfeasible either.

What if we were able to type something like this at a Glulxe prompt:

>CONSTRUCT MODE ENGLISH
Entering construction mode (English)

>>A CAT IS A KIND OF ANIMAL
Understood: (a cat) (is a kind of) (animal). Created new class 'Cat' as
child of class 'Animal'.

>>CONSTRUCT MODE LISP
Entering construction mode (Lisp)

>>(THING CAT TABBY)
Understood: (tabby) (is an instance of) (cat). Created new object
'Tabby' of class 'Cat'.

... and so on? There's probably a whole set of reasons why this is a
Bad Idea, but I'm kind of interested in exploring them.

Andrew Plotkin

unread,
Jun 11, 2006, 11:00:29 AM6/11/06
to
Here, na...@natecull.org wrote:
>
> That's why lists are more flexible than arrays - they're infinitely
> flexible. But they're also a real pain to implement in a language
> because you have to build a dynamic memory allocator and garbage
> collection system. TADS has this; the Z-machine really doesn't have
> space to do it; Glulx has the capacity but would require the dynamic
> memory allocation machinery built on top of it, and, probably, a new
> language constructed from the ground up to use that capability.

I have been seriously thinking about that dynamic malloc extension for
Glulx. It is not entirely trivial, but not too hard either. (I'd have
to either keep the heap organization description -- the equivalent of
the malloc arena -- in VM memory, or be able to serialize it for
save/restore. Neither is pleasant. I'm leaning towards the latter.)

Would it require a new language? I7 phrases for cons/car/cdr would let
you get some stuff done.

--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."

steve....@gmail.com

unread,
Jun 11, 2006, 6:02:39 PM6/11/06
to
Nate Cull wrote, quoting me:

> > I don't understand the claims you've made about how this version is

> > much different than previous versions. [...]


> > Could you identify where is the critical
> > difference, and why it's critical?
>
> It's the same core search algorithm, yes. The main difference is in how
> it uses I7 rules to structure the rulebase.

I looked at the code, and while I see that the rulebase is structured
differently, I don't see that it is structured in any way better. I see
the restructuring as minor and cosmetic. Could you please explain where
there's some substantial gain?

> There are a few changes to
> the internal storage of the planning table - no 'opcode' field, as it
> uses Kind to distinguish between planning-relations and
> planning-actions. Terminology has also changed to match I7, so it
> refers to 'relations' rather than 'conditions'.

I was thinking of eliminating the opcode in the TADS 3 version. I
decided to keep it because it makes things clearer.

> The way plans are written is similar to the I6 approach: each plan is
> essentially a function responding to (actor, relation, object, object,
> plan#, step#), but 'when' clauses in I7 rules are used to catch (actor,
> relation, object, object). The 'plan [number]' and 'suggest [relation]
> with [object] and [object]' phrase syntaxes are completely new. You
> don't have to manually keep track of how many steps are in each plan
> and report that number as 'step 0' as you did for I6. This should
> making writing simple plans a lot easier.

Oh, I've just worked on the TADS side of the thing. I was unaware of
these problems.

It's my sense that I6 is difficult to program in. It looks like I7, as
bad as it is syntactically for programming, is slightly better to
program in. Ironic, perhaps.

But you made some statement that this I7Planner is the first version
that's really usable. Now, I don't know whether or not the I6 version
was usable -- I never tried. Were you counting your TADS 2 version,
when you said this? Or were you meaning only that this is the first
usable planner available in Inform?

> > You complain that the language does not support lists. But you use
> > tables, and that seems to work fine. What's the advantage of doing the
> > same thing with lists?
>
> When I originally wrote RAP, it was using TADS2 lists to store a plan.
> So a plan there looked roughly like:
>
> [
> [
> [<relation> <object1> <object2>]
> [<relation> <object1> <object2>]
> ...
> [<action> <object1> <object2>]
> ]
> [
> [ <relation> <object1> <object2>]
> ...
> [<action> <object1> <object2]
> ]
> ...
> ]
>
> so you could, from one 'generate me a plan' function, return a single
> list construct containing a variable number of alternative plans, each
> consisting of a variable number of steps. You could also put multiple
> objects in each 'object' slot just by putting a list in, eo, eg, you
> could handle >GET THE KEY AND THE PADLOCK as an action step. It could
> also be expanded indefinitely if, for instance, at a later date you
> decided you wanted to handle object specifications (>TAKE ALL THE RED
> THINGS FROM THE BOX) etc, or add adverbs or a third object to

> sentences. [...]

So is the problem that you can't nest tables in I7? (I.e., an element
in the table is another table, or a pointer to a table.)

> Another very useful thing one could do with lists, which I didn't
> implement in TADS but wrote some initial code to do in I6, was build a
> capability for actors to not use *real* knowledge of the world state,
> but each keep track of what they *believed* was the current state of
> any given property of any given object.

Yes, it was easy to do this in TADS. The TADS 3 version supports this,
and quite a bit more.

> Yes, the syntax reads like very tortured English in some cases - except
> in the definition of rules, where it is mostly clearer.

To whom? The programmer?

> I should point out that creating extensible plans is pretty much
> impossible to do properly in I6 compared to I7. The rule-based design
> really, really shines here. Doesn't quite do everything right, but at
> least each rule can be overridden. Trying to do that with object
> inheritance was a nightmare of hooks and a large reason of why I
> abandoned the project.

I don't understand. What do you mean by "extensible plan"?

I suspect that this is the major point, so please elaborate.

> The NL seems to work best when it is directly describing world model
> elements. When one is writing code to deal with abstractions, it gets
> trickier.

The syntax is a programming syntax, desighed to be disguised as NL so
long as you're within the trivial target, which is basically filling in
a database. But outside of that, it's just a normal programming syntax,
right? Could you explain what you mean by "tricky"?

na...@natecull.org

unread,
Jun 11, 2006, 8:36:21 PM6/11/06
to

Andrew Plotkin wrote:
> I have been seriously thinking about that dynamic malloc extension for
> Glulx. It is not entirely trivial, but not too hard either. (I'd have
> to either keep the heap organization description -- the equivalent of
> the malloc arena -- in VM memory, or be able to serialize it for
> save/restore. Neither is pleasant. I'm leaning towards the latter.)

Mmm. I was thinking about writing an allocator in Glulx bytecode
itself, which I guess would be slow. Can't quite get my head around how
one would organise it though. There seem to be so many different
strategies, all not-quite-optimal, and storing the free list itself
would take up a fair bit of VM RAM.


> Would it require a new language? I7 phrases for cons/car/cdr would let
> you get some stuff done.

I suppose. It seems that one would really want a list constructor
syntax otherwise it would be just awkward to work with.

I mean, if all we wanted was lists, and not dynamic strings, it would
be a lot simpler to write an allocator since we'd be dealing with
fixed-size memory cells (say 8 bytes). And we could probably do that in
I7 right now just with a table...

... that's worth playing with, that is.

Maybe we can use I7 syntax. It might be powerful enough. It's more that
I find the syntax intractable for *me* to get my head around, I can
never quite predict what's legally parseable.

I like the idea of a fully dynamic language, but I also like
precompiled strings and not having to deal with allocating and
garbage-collecting arbitrary chunks.

vaporware

unread,
Jun 11, 2006, 8:45:25 PM6/11/06
to
na...@natecull.org wrote:
[snip]

> I don't like that I have to use lots and lots of globals, and that in
> fact almost every operation (such as table operations) relies on lots
> of implicit shared global state (such as which row is 'the current
> row') that can break if, eg, you run a function between doing a table
> row lookup and testing a table field. This seems to me a very 1950s way
> of programming and I'd much prefer to be able to make things
> function-call-safe. I think mostly this comes about because the
> Z-machine is such a small machine, but it is also the way the I6
> library is designed.

Actually, tables use local state. The current table and current row are
stored in the I6 variables ct_0 and ct_1, which are local to any
phrase/rule that uses table operations. You can't nest one table loop
inside another (or use "listed in" inside a table loop, etc.), but you
should be able to call one phrase that uses tables from another without
disturbing the latter's state.

vw

na...@natecull.org

unread,
Jun 11, 2006, 9:25:33 PM6/11/06
to

steve....@gmail.com wrote:

> I looked at the code, and while I see that the rulebase is structured
> differently, I don't see that it is structured in any way better. I see
> the restructuring as minor and cosmetic. Could you please explain where
> there's some substantial gain?

Primarily with rules.


> It's my sense that I6 is difficult to program in. It looks like I7, as
> bad as it is syntactically for programming, is slightly better to
> program in. Ironic, perhaps.

Not really, since I7 was intended to be easier to program in...

> But you made some statement that this I7Planner is the first version
> that's really usable. Now, I don't know whether or not the I6 version
> was usable -- I never tried. Were you counting your TADS 2 version,
> when you said this? Or were you meaning only that this is the first
> usable planner available in Inform?

I was counting TADS too. Your mileage may have varied, but a big
drawback with both previous versions is that it's very hard to define a
library of generic default plans and then override just the special
cases you want special plans for. If you're only ever writing a game
for yourself, that may not be so much of an issue.

With I7's rules, it's a lot easier to cleanly separate library and game
code. Not quite as easy as it could be, since 'when' clauses don't seem
to be ordered by specificity, but


> So is the problem that you can't nest tables in I7? (I.e., an element
> in the table is another table, or a pointer to a table.)

You can do that, yes. But every subtable has to be given a unique name
and defined separately. So it's a facility best used sparingly. And
there's no clean syntax for defining a nested data structure inside a
table. It *can* be done, I think, but it's not pretty, it takes manual
housekeeping work, and the code you'd type into your story file would
not directly represent the structure of the data.

It might be an alternative approach to using rules, though. I prefer
rules because you can mix plans with code - not so easy to do that with
a table. (Say phrases, yes. Or the name of a rule in a table row. But
if you're going to do that you might as well just wrap the whole thing
in a rule.)


> > Yes, the syntax reads like very tortured English in some cases - except
> > in the definition of rules, where it is mostly clearer.
>
> To whom? The programmer?

Admittedly I just looked at Basic Plans (there's a bug in Version 1,
hooray) and didn't find it as clear as when I was writing it. :) Needs
lots more comments.

I would also like a much terser syntax. Hmm. Maybe the jury's still out
on how readable it is compared to I6. I think I could write a rule
class that did everything I7 rules do and was more flexible for my
needs:

planning rule when the relation is being-in and the desired param1 is
broth and the desired param2 is the crucible:

vs

Rule
with rel being-in,
par1 broth,
par2 crucible,
plan [
...
]
;


That could have legs. Anyone up for an I7 -> I6 backport project?
Implement a rule system, scenes, regions, NPC actions, values, tables,
maybe crude object specifiers... the core bits of the world model and
semantics.Then we could do direct apples to apples comparisons of just
the NL syntax.

(If I6 had compile-time macros, we could create arbitrary syntax for
things like lists, and probably also be able to make naming a lot
simpler - reproduce I7's trick of defining parse, display and internal
names all at once. Maybe a simple extensible preprocessor with a macro
facility?)


> I don't understand. What do you mean by "extensible plan"?

What I said above about separating generic library behaviour from
specific situational plans.

steve....@gmail.com

unread,
Jun 12, 2006, 11:07:48 AM6/12/06
to
Nate Cull wrote:
> > I looked at the code, and while I see that the rulebase is structured
> > differently, I don't see that it is structured in any way better. I see
> > the restructuring as minor and cosmetic. Could you please explain where
> > there's some substantial gain?
>
> Primarily with rules.
[...]

> I was counting TADS too. Your mileage may have varied, but a big
> drawback with both previous versions is that it's very hard to define a
> library of generic default plans and then override just the special
> cases you want special plans for.

The TADS 3 version supporte special case overrides. (The same hook
could have been built into the TADS 2 version.) Again I am not seeing
how the I7 version makes a really significant advance.

The only shortcoming of the TADS 3 version here is that you'll need to
resolve conflicts by hand. (A conflict occurs when more than one
parameter has a custom override.) Is that the thing you're talking
about that the I7 version handles better? Or is there something else?

> > It's my sense that I6 is difficult to program in. It looks like I7, as
> > bad as it is syntactically for programming, is slightly better to
> > program in. Ironic, perhaps.
>
> Not really, since I7 was intended to be easier to program in...

Of course I didn't mean "The hat is on the table"-style programming,
but conventional procedural programming like we're talking about and
looking at in this context. The amusing thing to me is that a language
targeted to "The hat is on the table" might be nevertheless better at
procedural programming than I6.

na...@natecull.org

unread,
Jun 12, 2006, 6:31:45 PM6/12/06
to

steve....@gmail.com wrote:

> The TADS 3 version supporte special case overrides. (The same hook
> could have been built into the TADS 2 version.) Again I am not seeing
> how the I7 version makes a really significant advance.

I can't speak for TADS3, but TADS2 certainly does not have rules.

I'm not sure how many more ways you need me to say 'The answer is
rules.'

> Of course I didn't mean "The hat is on the table"-style programming,
> but conventional procedural programming like we're talking about and
> looking at in this context. The amusing thing to me is that a language
> targeted to "The hat is on the table" might be nevertheless better at
> procedural programming than I6.

Well, see. The thing is. This is the thing. IF programming is *not*
ever merely 'procedural programming'. It's a mix of declarative and
procedural forms. This requirement is intrinsic to the problem domain.
The best language for this would a language that allows both. I6 and
I7 and TADS all approach this from slightly different angles.

That being said, yes, I7 provides somewhat better facilities (in some
senses) even for your narrow definition of "purely procedural"
programming (even though this can never be separated completely from
the data structures that you're manipulating in IF) - and this is not
really surprising, because, duh. It's the second take on a language. Of
course it will attempt to improve.

steve....@gmail.com

unread,
Jun 12, 2006, 8:09:41 PM6/12/06
to
Nate Cull wrote, quoting me:
> > The TADS 3 version supporte special case overrides. (The same hook
> > could have been built into the TADS 2 version.) Again I am not seeing
> > how the I7 version makes a really significant advance.
>
> I can't speak for TADS3, but TADS2 certainly does not have rules.

TADS 3 doesn't have "rules" but the TADS 3 version of RAP does allow
for easy special-case overrides.

> I'm not sure how many more ways you need me to say 'The answer is
> rules.'

I think you were saying that "rules" makes it easy/easier to do special
case overrides. Is that the main benefit? Are there any other benefits
of the rules? ("The answer is rules" is not a terribly enlightening
answer -- sorry if I'm being dense.)

na...@natecull.org

unread,
Jun 12, 2006, 8:29:35 PM6/12/06
to

steve....@gmail.com wrote:

> > I'm not sure how many more ways you need me to say 'The answer is
> > rules.'
>
> I think you were saying that "rules" makes it easy/easier to do special
> case overrides. Is that the main benefit? Are there any other benefits
> of the rules? ("The answer is rules" is not a terribly enlightening
> answer -- sorry if I'm being dense.)

Yes, you are being dense.

na...@natecull.org

unread,
Jun 12, 2006, 9:17:38 PM6/12/06
to

steve....@gmail.com wrote:
> I think you were saying that "rules" makes it easy/easier to do special
> case overrides. Is that the main benefit? Are there any other benefits
> of the rules? ("The answer is rules" is not a terribly enlightening
> answer -- sorry if I'm being dense.)

The long answer:

Special case overrides is what it's all about. Rules are nothing *but*
special case overrides. There's a big difference between providing
hooks for certain operations and allowing everything to be
configurable. Seriously, please go read the I7 docs and play with it a
bit. I don't want to have to explain everything from first principles.

But some examples:

Suppose you want to provide a library of plans for implementing (open
object)

1) For a simple openable container: easy, get within reach of it, find
the key and unlock it if it needs one, open it. This is the case Basic
Plans implements.

2) How about if it's a container locked, but with a combination lock
rather than a key? Then maybe you want to find the code, then enter it.

3) If it's a door, similar thing, only a door can be in two places at
once.

4) What about if it's a pressure door on a spaceship? Maybe you need to
check the pressure is equalised or that you're wearing a spacesuit
first. Perhaps that's defined in your Space Stories library.

5) Maybe it's a one-off special door that can't be opened normally.
Maybe you have to break it down. Maybe you need to bribe a guard to
open it. Maybe.... an infinity of game- and object- specific
possibilities.

6) Maybe the same container or door behaves differently if it's in a
different state, or during a different scene of the game. Maybe it's an
ordinary lockable door wih key during all except Power Failure scene,
when the fallen electric cable makes it electrocute anyone who touches
the handle, so you need to be wearing the rubber gloves before opening
it. You don't want to rewrite all of your door code just to handle that
one case - but you need to break that case out on its own, or bzzt,
fried NPC.

7) The player has a sonic screwdriver that can bypass locks. (open, any
door, with sonic screwdriver) should be treated differently than (open,
door).

Assuming you want your NPC to do these things and not just be content
with the generic 1) and 3) behaviour, then you're going to need a *lot*
of configurability. And there's three main objects involved in any
plan: the relation/condition, the first object, the second object.
Should all of these conditions be put on a method on the 'open' object?
The 'door' object? The 'sonic screwdriver' object? The 'power failure'
scene object?

This is where OO breaks down, because this logic does not belong with
any particular object of the three, so it can't be easily overridden
simply by subclassing one object and replacing one method. It's not a
matter of *specialising* already neatly compartmented functionality -
it's a matter of *completely throwing away and replacing arbitrarily
complex behaviour based on a tangled hierarchy of equally complex
conditions*. And it needs to be broken down into components that play
nicely with includable libraries, so the basic door rules go into Basic
Plans and the vacuum door rules go into Space Stories and my own game
Alien Time Doctor From Venus gets to use the sonic screwdriver
override... but not on Thursdays, when the moon is full and we're
playing as Godzilla in Venice.

You begin to see the complexity of the problem. If you don't, then
tough. The complexity remains regardless of your ability to see it.

Rules neatly solve this problem by abstracting override logic into,
essentially, a class of its own. Everything becomes a hook.

If you've developed an alternative configuration solution which is even
halfway as powerful as generic rules, do share. I'll be intrigued to
look at it.

na...@natecull.org

unread,
Jun 12, 2006, 9:55:38 PM6/12/06
to
A tangent:

Granted that I7 rules are so neat, I still find myself very cramped by
I7's 'look but don't touch' approach to the rest of the world model.
The compiler gets to play with lots of interesting markup such as
adjectives, definitions, relations, and the like, but I don't have
access to any of this at runtime.

This is a problem when it comes to wanting to write planning NPCs. The
complexity I just mentioned comes from the fact that writing plans is
essentially reverse-engineering the structure of the story world. So in
a game with planning NPCs, I'm writing rules twice: once to implement
the special-cases of the world behaviour, and once to make the NPCs
aware of this and know how to handle it.

This seems like a waste of both my time and the computer's, and
violates the principle of 'Don't Repeat Yourself'.

The logical thing to do would be to create data/code structures that
combine the two jobs: describing how the world works, and giving the
NPCs instructions on how to manipulate that world. I'd write code
*once*, and NPCs would Just Understand how to get things done. Then I
could stop micromanaging NPCs so much and get on with building the
world and creating puzzles and drama. Happiness for everyone, and much
more lifelike NPCs. Pretty much for free.

But I can't do this in Inform (6 or 7, but the gulf is wider in 7):
because only the compiler gets to touch the top-level description of
the world; because that description is written in such a complicated
and hard-to-parse language (pseudo-English) full of its own special
cases at the syntactic level let alone semantics, that merely turning
this into an abstract world definition must be a chore in its own right
and certainly not something to be done at runtime; because a lot of
this valuable information is either simply thrown away or compiled down
to inscrutable procedures with no runtime API; and leaving completely
aside the not-entirely-trivial question of source code access and
licencing - even if I did get to see NI source, can I then use any of
its algorithms in my game, or am I breaching copyright? This can be
solved by a rerelease with a sufficiently liberal licence, but the
basic design of the language syntax and compilation architecture can't
be.

The more I look at planning, the more I chafe at a language that ties
me to a very narrow, first-order view of the world. I want the
capability to read all of the world at runtime, to understand and
define new relations, to store arbitarily complex second- and
third-order data: 'where does character X believe character Y thinks
the location of the McGuffin is?'

And I probably want a sufficiently powerful logical-inferencing
language, like Prolog, to handle these kinds of things. Frankly, what I
want is a language simple, extensible and powerful enough to write the
compiler for an I7-like language, but available, along with all the
abstract syntax trees and world model inferences and intermediate
steps, at runtime.

Something like PicoLisp (http://software-lab.de/ref.html) or Factor
(http://www.factorcode.org), perhaps.

Andrew Plotkin

unread,
Jun 12, 2006, 11:50:35 PM6/12/06
to
Here, na...@natecull.org wrote:
>
> Granted that I7 rules are so neat, I still find myself very cramped by
> I7's 'look but don't touch' approach to the rest of the world model.
> The compiler gets to play with lots of interesting markup such as
> adjectives, definitions, relations, and the like, but I don't have
> access to any of this at runtime.
>
> This is a problem when it comes to wanting to write planning NPCs. The
> complexity I just mentioned comes from the fact that writing plans is
> essentially reverse-engineering the structure of the story world. So in
> a game with planning NPCs, I'm writing rules twice: once to implement
> the special-cases of the world behaviour, and once to make the NPCs
> aware of this and know how to handle it.

I am all with the idea of not writing code twice. But how do you see
using first-class world-model elements (run-time relations, rules,
etc) to solve this problem? I mean, what would your ideal solution
look like?

The I7 model for this stuff is, I guess, exemplified by the "try
silently" system. The library separates a "report" stage in its rules,
so an NPC can try something and (if it doesn't work) either print an
NPC-specific complaint or try something else. (No, I have no idea how
you're supposed to suppress "check" rules in this process.)

I'm reasonably sure (without having used it) that this is a pain in
the ass. Nonetheless, it seems like the right idea: declare the
structure of cases and exceptions at compile time, and then make use
of it at runtime in two different contexts.

Kevin Forchione

unread,
Jun 13, 2006, 12:50:03 AM6/13/06
to
<steve....@gmail.com> wrote in message
news:1150157381.4...@i40g2000cwc.googlegroups.com...

> Nate Cull wrote, quoting me:
>> > The TADS 3 version supporte special case overrides. (The same hook
>> > could have been built into the TADS 2 version.) Again I am not seeing
>> > how the I7 version makes a really significant advance.
>>
>> I can't speak for TADS3, but TADS2 certainly does not have rules.
>
> TADS 3 doesn't have "rules" but the TADS 3 version of RAP does allow
> for easy special-case overrides.

The TADS 3 module could be rewritten to be rule based. Don't see why not. As
I understand it the "rules" of I7 are nothing more than routines that return
either true (if successful or failure) and false (if not applicable).
There's no reason why the TADS 3 RAP mechanism couldn't do the same, if
rules are the bread and butter of your existence.

--Kevin


vaporware

unread,
Jun 13, 2006, 1:01:06 AM6/13/06
to
Kevin Forchione wrote:
> The TADS 3 module could be rewritten to be rule based. Don't see why not. As
> I understand it the "rules" of I7 are nothing more than routines that return
> either true (if successful or failure) and false (if not applicable).
> There's no reason why the TADS 3 RAP mechanism couldn't do the same, if
> rules are the bread and butter of your existence.

Well, one nice thing about I7's rules is that the compiler
automatically sorts them by specificity, so an "opening the cell door
during Power Outage" rule will always have a chance to run before the
plain old "opening a door" rule.

vw

na...@natecull.org

unread,
Jun 13, 2006, 1:18:27 AM6/13/06
to

Kevin Forchione wrote:
> The TADS 3 module could be rewritten to be rule based. Don't see why not. As
> I understand it the "rules" of I7 are nothing more than routines that return
> either true (if successful or failure) and false (if not applicable).
> There's no reason why the TADS 3 RAP mechanism couldn't do the same, if
> rules are the bread and butter of your existence.

Yes, and I think the I6 version could do this too. And quite possibly
an OO approach to rules would give you more flexibility than the
fixed-at-compile-time rule syntax in I7. (TADS3 quite possibly already
does a large part of the things I'm after - fully dynamic VM, hackable
parser, I'm not entirely sure why I haven't tried using it yet. Mostly
fatigue from its perpetual beta-ness and a shock reaction to the size
of the library. And an irrational fondness for the Z-machine, but I'm
reconciling myself to abandoning that anyway.)

My point was that I7 gives you rules 'for free', and this is a
non-trivial win. In the process of reimplementing Planner to be
'I7-like' I found it was a much more natural solution for the
configurability problem that I'd been struggling with for ages.

Like scenes, regions, and state machines for actors, rules I think are
one of those simple constructs that could be put in a library even in
an existing language and make life a lot simpler for everyone.

na...@natecull.org

unread,
Jun 13, 2006, 2:23:02 AM6/13/06
to

Andrew Plotkin wrote:
> I am all with the idea of not writing code twice. But how do you see
> using first-class world-model elements (run-time relations, rules,
> etc) to solve this problem? I mean, what would your ideal solution
> look like?

Not entirely sure at this point. I suspect some of what I want can be
done by sufficiently cunning abstraction of the 'world logic' to use,
eg, table lookup rather than direct rules. But I think that using
tables will only take one so far.

Eg, in the 'Alchemy' demo v1, currently I have a hacked-together rule
that transmutes three objects into one if they are together in the
crucible. Since I used a 'to decide if' phrase called from inside a
rule to do this (it was the simplest thing that came to mind), this is
opaque to the planning code, so I have to have a similar set of
statements inside my plan. What I should do instead, and will in the
next version, is have a 'table of transmutations' that lists pairs or
series of reagants and the resulting product. That way, the 'to have an
object' planning rule can be written to consult the table of
transmutations in reverse, and calculate plans on the fly. That bit
seems easy enough, and can be done within the current I7 paradigm.

I suppose I am visualising a system where more of the world is data
rather than code. Hmm. A Planner-friendly implementation of the
electrified door perhaps, would have some kind of data structure saying
something like:

* when the electrical cable is touching anything conductive, that thing
is electrified
(except for the following exceptions, etc)
* for a door to be opened, it must first be unlocked
---- if violated, give a "it's locked" message
*** [rule inserted here] it must also be electrically safe for the
opener
---- if violated, electrocute the opener
** the opener must then be able to touch the door (or the device which
opens the door)
--- if violated, this case will probably be caught by parsing rules
anyway
** the opener can then >OPEN THE DOOR and it will succeed, changing the
door's state to Open and giving the standard open message

Urgh. This is glossing over a lot of important details. I can see a lot
of trickiness there, since this would meld together multiple flows of
execution and I'm not sure how easy it would be to understand. It also
runs against the problem you mentioned of there not being an easy way
to tell when a given rule 'succeeds' or 'fails'. If you succeed in
getting electrocuted, that's not exactly a 'failure' of an action -
something certainly happens, and world state ends up being changed. A
turn is used. But the door does not get opened.

But, um. I would like for the planning engine to at least somehow be
aware of the existence of rules relating to the door, and preferably
somehow to be aware of what they logically do.

... otoh, I would also like for there to be room for different actors
to have different levels of knowledge and possibly whole different sets
of plans, and not necessarily automatically know the 'correct'
behaviour that the world implements. But have 'read world's mind'
available as a default.

Still groping towards ideas, really.


> The I7 model for this stuff is, I guess, exemplified by the "try
> silently" system. The library separates a "report" stage in its rules,
> so an NPC can try something and (if it doesn't work) either print an
> NPC-specific complaint or try something else. (No, I have no idea how
> you're supposed to suppress "check" rules in this process.)

Yes, I suppose. It's approaching the problem from one angle, and I
think I'm coming at it from the other: rather than having the runtime
implementation of an action be the definitive state, have some kind of
coded representation of the interaction of rules be the definitive
dataset, with both plans and runtime checks being inferred from this.

I mean, this may be hard. This may be NP-hard. It's probably very close
to the place where symbolic AI research finally woke up with a hangover
and three-day stubble and went 'ennnh, let's go hack Java instead and
get rich'.

I dunno. It *seems* like it should be easy, somehow, to be able to
Prolog something up that goes:
* >OPEN [THING] is an action. It changes the state of [THING] from
Closed to Open except where these rules apply: ...
* We want [THING] to be open
* Do any of these rules apply to us?
* Yes, the door is currently electrified (Rule X)
* Opening an electrified door kills the opener (Rule Y)
* We don't want to die unless it's scene Heroic Sacrifice (Rule A)
* The gloves prevent against electrification (Rule Z)
* Therefore we need the gloves - go find em first

Currently we don't have a way to say "the gloves prevent against
electrification" . We can't do much of anything with I7 rules other
than run 'em and see what pops out. It would be nice to be able to run
rules backwards, for one thing. "Give me a list of the preconditions
necessary for this rule to fire. Now apply a filter to that list and
make the best resulting one our goal."

No idea quite how we'd specify these rules, something Prologish perhaps
though I don't quite grok Prolog. I probably need to learn but the
examples seem very contrived and not terribly real-worldy. (There is a
proto-IF system, though -
http://www.ainewsletter.com/downloads/if_docs/ - which could be fun to
play with and see if it's useful. Needs a good library and a much
better example than Duck World.)

I like I7's adjectives and relations, I think they're a first step
towards this sort of thing. "The door is electrified if a powered on
cable is touching it" seems like a fundamental sort of logical
construct to be able to write. Not implemented as a function, though,
since that's only one-way, but as logic.

I'm also thinking in terms of the whole business of updating the world
being somehow modelled as state transitions or the like: with actions
as arcs (obviously not your standard state diagram since we're not
quite talking discrete states, but whole sets of things). There's
probably AI/CS terminology for this that I don't have. But something
where we cleanly separate the *world effect* of actions from the
*narrative effect* and description of them. But then we also may want a
'Director' AI that seeks certain meta-world narrative states, like
scenes, or 'if the player seems lost, suggest some help', so we don't
necessarily want "narrative effects" to be completely outside the world
model either. But something where we can say "The result of (actor,
go, north) when (location = this room) is that their location changes
to (that room), and if (this other condition applies) a message is
generated." and then answer "Ignoring (ordinary success messages), what
actions given this actor's location could result in the actor being in
that room?"

I think the idea being that we would somehow mark up messages as
narrative-state important or unimportant. Most of the 'you go north'
housekeeping type messages don't alter the plot of a game. But 'you
have died' or 'you have a flashback' sort of things are chunks of
plot-dump in themselves, and are things that we want to know if they've
happened or not. We do this already - the "achieved" list, scoring,
learning topics during conversation. Not that hard to imagine a more
general mechanism for it.

Maybe I need to go hack on AIFT a bit and see if it's usable as a real
IF system. The author seems to dislike the classic Infocom interface
which does not bode entirely well.

Stephen Granade

unread,
Jun 13, 2006, 8:56:07 AM6/13/06
to
"Kevin Forchione" <ke...@lysseus.com> writes:

> <steve....@gmail.com> wrote in message
> news:1150157381.4...@i40g2000cwc.googlegroups.com...
> > Nate Cull wrote, quoting me:
> >> > The TADS 3 version supporte special case overrides. (The same hook
> >> > could have been built into the TADS 2 version.) Again I am not seeing
> >> > how the I7 version makes a really significant advance.
> >>
> >> I can't speak for TADS3, but TADS2 certainly does not have rules.
> >
> > TADS 3 doesn't have "rules" but the TADS 3 version of RAP does allow
> > for easy special-case overrides.
>
> The TADS 3 module could be rewritten to be rule based. Don't see why
> not.

I agree with what Nate said downstream: certainly it could. There's
nothing magical about rules that keeps you from adding them to any
language, provided you're willing to do the heavy lifting. Reducing
the concept to routines that return a boolean is skipping past the
really hard parts, though, namely, how do you decide rule precedence?
And how do you allow on-the-fly reordering of them? Given recent
discussions on this newsgroup, that's where the tricky bits are, and
it's a problem we don't yet have a great solution to.

Stephen

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

Andrew Plotkin

unread,
Jun 13, 2006, 9:30:52 AM6/13/06
to
Here, Stephen Granade <stephen...@granades.com> wrote:
> "Kevin Forchione" <ke...@lysseus.com> writes:
>
> > <steve....@gmail.com> wrote in message
> > news:1150157381.4...@i40g2000cwc.googlegroups.com...
> > > Nate Cull wrote, quoting me:
> > >> > The TADS 3 version supporte special case overrides. (The same hook
> > >> > could have been built into the TADS 2 version.) Again I am not seeing
> > >> > how the I7 version makes a really significant advance.
> > >>
> > >> I can't speak for TADS3, but TADS2 certainly does not have rules.
> > >
> > > TADS 3 doesn't have "rules" but the TADS 3 version of RAP does allow
> > > for easy special-case overrides.
> >
> > The TADS 3 module could be rewritten to be rule based. Don't see why
> > not.
>
> I agree with what Nate said downstream: certainly it could. There's
> nothing magical about rules that keeps you from adding them to any
> language, provided you're willing to do the heavy lifting. Reducing
> the concept to routines that return a boolean is skipping past the
> really hard parts, though, namely, how do you decide rule precedence?
> And how do you allow on-the-fly reordering of them?

And how do you efficiently carry out the rules? (See David Fisher's
efforts to customize the standard library messages.) Again, this is a
place where I7 could be improved -- you can do many clever
optimizations at compile-time when you have a complete rule model in
hand. Trying to put those improvements into a library-level
implementation would be much harder, because that's mutable at
runtime.

--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 you're innocent.

Neil Cerutti

unread,
Jun 13, 2006, 11:48:36 AM6/13/06
to

In practice, I think you'll need to order your rules manually in
the code. The specificity of a rule can change through debugging,
and isn't necessarily obvious to the programmer.

--
Neil Cerutti
I think challenges keep you forever young. And I've discovered
the fountain of youth. I'm Peter Pan with this one. --Rick
Pitino

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

Andrew Plotkin

unread,
Jun 13, 2006, 12:13:45 PM6/13/06
to
Here, Neil Cerutti <lead...@email.com> wrote:
> On 2006-06-13, vaporware <jmc...@gmail.com> wrote:
> > Kevin Forchione wrote:
> >> The TADS 3 module could be rewritten to be rule based. Don't see why not. As
> >> I understand it the "rules" of I7 are nothing more than routines that return
> >> either true (if successful or failure) and false (if not applicable).
> >> There's no reason why the TADS 3 RAP mechanism couldn't do the same, if
> >> rules are the bread and butter of your existence.
> >
> > Well, one nice thing about I7's rules is that the compiler
> > automatically sorts them by specificity, so an "opening the
> > cell door during Power Outage" rule will always have a chance
> > to run before the plain old "opening a door" rule.
>
> In practice, I think you'll need to order your rules manually in
> the code. The specificity of a rule can change through debugging,
> and isn't necessarily obvious to the programmer.

This has not been my experience. The specificity of a rule is part of
the game design, like the class hierarchy. If I change it, it's on
purpose.

--Z

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

Just because you vote for the Republicans, doesn't mean they let you be one.

Stephen Granade

unread,
Jun 13, 2006, 1:33:33 PM6/13/06
to
Andrew Plotkin <erky...@eblong.com> writes:

> Here, Stephen Granade <stephen...@granades.com> wrote:
> > "Kevin Forchione" <ke...@lysseus.com> writes:
> >
> > > <steve....@gmail.com> wrote in message
> > > news:1150157381.4...@i40g2000cwc.googlegroups.com...
> > > > Nate Cull wrote, quoting me:
> > > >> > The TADS 3 version supporte special case overrides. (The same hook
> > > >> > could have been built into the TADS 2 version.) Again I am not seeing
> > > >> > how the I7 version makes a really significant advance.
> > > >>
> > > >> I can't speak for TADS3, but TADS2 certainly does not have rules.
> > > >
> > > > TADS 3 doesn't have "rules" but the TADS 3 version of RAP does allow
> > > > for easy special-case overrides.
> > >
> > > The TADS 3 module could be rewritten to be rule based. Don't see why
> > > not.
> >
> > I agree with what Nate said downstream: certainly it could. There's
> > nothing magical about rules that keeps you from adding them to any
> > language, provided you're willing to do the heavy lifting. Reducing
> > the concept to routines that return a boolean is skipping past the
> > really hard parts, though, namely, how do you decide rule precedence?
> > And how do you allow on-the-fly reordering of them?
>
> And how do you efficiently carry out the rules? (See David Fisher's
> efforts to customize the standard library messages.)

Plus, how do you specify when the rules hold true in a concise way?
When you get down to it, building this kind of an approach is
comparable to building a parser, and is not for the faint-of-heart.

steve....@gmail.com

unread,
Jun 13, 2006, 4:00:31 PM6/13/06
to
Nate Cull wrote:
> The long answer:

Thanks. This is what I was asking for.

> Special case overrides is what it's all about. Rules are nothing *but*
> special case overrides. There's a big difference between providing
> hooks for certain operations and allowing everything to be
> configurable.

I agree that you want everything to be configurable -- that's precisely
why I prefer procedural over rule-based programming. This motto "a
world of hooks," which Graham borrowed from Plotkin, seems to me PR for
the loss of control (and overview) which always accompanies rule-based
systems. If you want "everything to be configurable," you probably want
procedural programming. If you're satisfied with "providing hooks for
certain operations," rule-based programming might be the best choice.

> But some examples: [snip]

Ok, thanks for the examples -- they help, as always.

Your extended example would be handled by hooks which in TADS 3 are
built in to the system, but which could be easily added to the TADS 2
version.

You have remarked that I7 is good at separating default behavior from
specialized behavior. Note that the TADS 3 hooks also cleanly separate
default from specialized behavior.

The hooks work very simply: before returning the default plan for
opening an object, we first check if the object defines a custom plan
for its opening. Likewise with the plan for unlocking.

In the case of two-object actions (UnlockWith: unlock door with sonic
screwdriver), the "indirect object" (sonic screwdriver) can define some
specialized plan, just as the "direct object" can.

This latter case introduces the problem: what if both objects define
specialized plans? In this case, as I said upthread, you have to
resolve the conflict by hand. This means either overriding the main
plan object, to inform it which object's custom plan takes precedence,
or making the two objects' custom plans sufficiently aware of one
another.

(As I understand it, plan precedence is not a problem solved by I7
either.)

Nevertheless, perhaps this points to one (and perhaps the principle)
benefit of I7 generally, quite apart from RAP: that it is
relation-oriented, rather than object oriented. Or as you say...

> And there's three main objects involved in any
> plan: the relation/condition, the first object, the second object.
> Should all of these conditions be put on a method on the 'open' object?
> The 'door' object? The 'sonic screwdriver' object? The 'power failure'
> scene object?
>
> This is where OO breaks down, because this logic does not belong with
> any particular object of the three, so it can't be easily overridden
> simply by subclassing one object and replacing one method.

Again, sorry if I'm being dense, but the question remains: subtracting
the boilerplate I7 theory, how does this substantially improve planbase
design?

Let me try to help answer the question a little bit. I think there are
two ideas at work here:

"if trees," overt, or assembled from piecemeal:

In the TADS version, or in any conventional procedural version, you
have an overt tree of "if" statements, each branch of which returns
some plan. In the I7 version, as I understand it, you have a tree of
"if" statements, but the machine deduces the tree (really assembling
the tree) from individual statements, individual branches of what will
be internally the larger structure. The machine figures out the
relationships between the branches so you don't have to. (But don't you
feel like you've lost some view on the result?) Still, I like the
concept of assembling "if trees" from pieces. So yay I7 is cool.

"relation oriented" (RO) vs. OO:

This is a false distinction, at least as the distinction has been
discussed so far: OO is being given short shrift. OO is RO, really:
messaging is relation.

It is easy to devise an example where OO breaks down: the interrelation
of objects is so complex that a single object can't cover everything,
and messaging back and forth becomes messy. This does not mean that
relational logic would be better.

The initial problem is simply transformed into the problem of relation
(or rule) precedence.

Also, I don't think these easy-to-devise examples occur (practically
speaking) any more frequently than their equally-easy-to-devise
solutions. It's normally simple to figure out which object is the
conceptual master, and so which object should handle the process. When
it's necessary to modify, it's generally pretty clear where the
modification should go. The "problem" which RO programming pretends to
solve can be easily overstated in the first place.

na...@natecull.org

unread,
Jun 13, 2006, 8:10:08 PM6/13/06
to

steve....@gmail.com wrote:
> Thanks. This is what I was asking for.

Oh good.

> I agree that you want everything to be configurable -- that's precisely
> why I prefer procedural over rule-based programming. This motto "a
> world of hooks," which Graham borrowed from Plotkin, seems to me PR for
> the loss of control (and overview) which always accompanies rule-based
> systems. If you want "everything to be configurable," you probably want
> procedural programming. If you're satisfied with "providing hooks for
> certain operations," rule-based programming might be the best choice.

That's your right to have a contrary opinion, but don't expect everyone
to share it.

Procedural programming certainly gives you total control of the order
of of operations *within a single block of code* (such as a single
procedure or function), yes. However, it provides far less
configurability *between blocks of code*.

You may feel that you can accomplish everything you need to in IF
within single code blocks. I think you'll find otherwise when you've
played with a system for a while. Libraries, especially, will give you
trouble, as will any kind of code reuse. Your code will not be easily
modifiable, even by yourself, even within a single project.

> The hooks work very simply: before returning the default plan for
> opening an object, we first check if the object defines a custom plan
> for its opening. Likewise with the plan for unlocking.
>
> In the case of two-object actions (UnlockWith: unlock door with sonic
> screwdriver), the "indirect object" (sonic screwdriver) can define some
> specialized plan, just as the "direct object" can.

Okay, so here you're doing exactly what I was looking at in TADS2. This
is the standard, simple, OO approach to the problem, and it's the
approach that I consider to have failed to be flexible enough to be a
general solution.

> This latter case introduces the problem: what if both objects define
> specialized plans? In this case, as I said upthread, you have to
> resolve the conflict by hand. This means either overriding the main
> plan object, to inform it which object's custom plan takes precedence,
> or making the two objects' custom plans sufficiently aware of one
> another.


EXACTLY. You've just described the problem with the OO approach. If you
look at this long enough, you'll realise that a) this case comes up
very, very often in IF, b) attempting to make two objects aware of each
other violates OO encapsulation and leads to deep, hairy spaghetti
interconnections, and c) overriding the main plan object is a good
'emergency escape hatch' but basically ignores the OO inheritance
hierarchy completely and does not play well with any other conditions.


> (As I understand it, plan precedence is not a problem solved by I7
> either.)

If two rules in I7 have the same level of specificity, (>SHOOT BOND
WITH anything versus >SHOOT anyone WITH GUN), I believe the first one
listed applies - so you do have a manual override to finesse the
awkward cases. It's possible that corner cases exist which are
intractable, but the number of these conflicting rules is much smaller
than with only checking the plan, the direct or indirect object, and
doing so in a specified order. You can implement the TADS2/TADS3
behaviour as a *subset* of rule-based behaviour (any rule that doesn't
define a direct object, for instance, can be assumed to match all of
them, which is the same as a condition being checked 'before' checking
the direct object). And then you can catch many other more complicated
conditions.


> Nevertheless, perhaps this points to one (and perhaps the principle)
> benefit of I7 generally, quite apart from RAP: that it is
> relation-oriented, rather than object oriented. Or as you say...

You seem to be misunderstanding rather deeply here. Neither I7
relations nor Planner relations have anything to do with rules, per se.


> > And there's three main objects involved in any
> > plan: the relation/condition, the first object, the second object.
> > Should all of these conditions be put on a method on the 'open' object?
> > The 'door' object? The 'sonic screwdriver' object? The 'power failure'
> > scene object?
> >
> > This is where OO breaks down, because this logic does not belong with
> > any particular object of the three, so it can't be easily overridden
> > simply by subclassing one object and replacing one method.
>
> Again, sorry if I'm being dense, but the question remains: subtracting
> the boilerplate I7 theory, how does this substantially improve planbase
> design?

....

... in the way I just told you, several times over?

Look, I'm not pushing any particular barrow here except my own. I have
no idea what you mean by 'boilerplate I7 theory' but frankly it sounds
like a thinly veiled insult, and I'm not playing your Graham-hating
games. I'm not quoting anything. I''m stating what I've learned about
the system by playing with it. You might try doing the same. You'd
probably learn more than you would from talking here, since you don't
seem to be getting much understanding from what I'm saying.

>
> Let me try to help answer the question a little bit. I think there are
> two ideas at work here:
>
> "if trees," overt, or assembled from piecemeal:

Okay, yes, this is a good observation.


> In the TADS version, or in any conventional procedural version, you
> have an overt tree of "if" statements, each branch of which returns
> some plan.

Yes, but you also have two kinds of 'if trees' in OO languages like
TADS and I6: the 'if statement' in the procedures, *and* the object
class hierarchy of method inheritance. BOTH of these are ways of
creating 'generalised' versus 'specialised' behaviour, and they
interplay.

>In the I7 version, as I understand it, you have a tree of
> "if" statements, but the machine deduces the tree (really assembling
> the tree) from individual statements, individual branches of what will
> be internally the larger structure. The machine figures out the
> relationships between the branches so you don't have to.

The compiler constructs essentially a decision tree by ordering more
general rules before more specific rules, yes.

>(But don't you feel like you've lost some view on the result?)

A little, yes. Which is an ongoing debate, and is why there is the
option of dropping into procedural IF statements, which possibly
reveals a flaw in the design of the rules in that they're
insufficiently customisable.

But for the most part, it's fairly simple to tell which rule 'should
be' ordered before another: if it has more clauses, or if the clauses
refer to object kinds higher up in the OO hierarchy.

Admittedly, the I7 compiler currently doesn't order 'when' clauses
correctly, but I expect that to be fixed.

Ok, yes, and then there's procedural rules, and then there's being able
to abort the rule scanning with 'rule succeeds / rule fails' versus
letting multiple rules fire. These can complicate the flow of
interaction. And then there's knowing which top-level rulebooks are
consulted in which order, but that's a situation common to all IF
libraries, needing to know the basic phases of execution.

The nicer thing about rules is that usually they map *more closely* to
what you *intend* to say. Not always, but in many cases you want to
define a) general behaviour, b) special behaviour in some circumstances
(which, as I keep claiming, usually involves *more* complexity than
just checking noun/direct-object or second/indirect-object.


> This is a false distinction, at least as the distinction has been
> discussed so far: OO is being given short shrift. OO is RO, really:
> messaging is relation.

Er, what? Now you're using terminology that I don't think corresponds
to anything anyone else uses.

OO messaging is, um, messaging (and maps onto hierarchies of inherited
behaviour). Rules are rules. Relations are something else entirely.


> It is easy to devise an example where OO breaks down: the interrelation
> of objects is so complex that a single object can't cover everything,
> and messaging back and forth becomes messy. This does not mean that
> relational logic would be better.

Heck if I know what you mean by 'relational logic'. We're not talking
predicate calculus here.

> The initial problem is simply transformed into the problem of relation
> (or rule) precedence.

Precedence, yes. And as I keep saying, rules can model precedence
relationships which are much more complicated than simple trees.

OO handles trees well. Rules can do webs.

IF is more webby than it is tree-y.

> Also, I don't think these easy-to-devise examples occur (practically
> speaking) any more frequently than their equally-easy-to-devise
> solutions.

I disagree. The examples of where the simple OO approach fails are easy
to devise because they occur so often. The solutions are not easy to
devise.


>It's normally simple to figure out which object is the
> conceptual master, and so which object should handle the process.

>When
> it's necessary to modify, it's generally pretty clear where the
> modification should go.


No, it is not, and it is not. This is my point.

The interesting corner case of IF - NOT the generic behaviour, the
customisations, which is what makes a game unique and fun - is all
about situations where there is *no* conceptual master - or if there
is, it is NOT one of the two or three obvious objects interacting. It's
a higher-level 'if this and this and this' rule.

Kevin Forchione

unread,
Jun 13, 2006, 11:50:02 PM6/13/06
to
"Andrew Plotkin" <erky...@eblong.com> wrote in message
news:e6mo7p$r33$1...@reader2.panix.com...

> Here, Neil Cerutti <lead...@email.com> wrote:
>> On 2006-06-13, vaporware <jmc...@gmail.com> wrote:
>> > Kevin Forchione wrote:
>> >> The TADS 3 module could be rewritten to be rule based. Don't see why
>> >> not. As
>> >> I understand it the "rules" of I7 are nothing more than routines that
>> >> return
>> >> either true (if successful or failure) and false (if not applicable).
>> >> There's no reason why the TADS 3 RAP mechanism couldn't do the same,
>> >> if
>> >> rules are the bread and butter of your existence.
>> >
>> > Well, one nice thing about I7's rules is that the compiler
>> > automatically sorts them by specificity, so an "opening the
>> > cell door during Power Outage" rule will always have a chance
>> > to run before the plain old "opening a door" rule.
>>
>> In practice, I think you'll need to order your rules manually in
>> the code. The specificity of a rule can change through debugging,
>> and isn't necessarily obvious to the programmer.
>
> This has not been my experience. The specificity of a rule is part of
> the game design, like the class hierarchy. If I change it, it's on
> purpose.

Fortunately for the TADS version, such rules could be sorted during
pre-init.

--Kevin


steve....@gmail.com

unread,
Jun 14, 2006, 8:07:44 AM6/14/06
to
Nate Cull writes:

> Procedural programming certainly gives you total control of the order
> of of operations *within a single block of code* (such as a single
> procedure or function), yes. However, it provides far less
> configurability *between blocks of code*.

Program flow is the relationship between objects. OO doesn't get going
until you write code that references other code; but once it's going,
it's really interlaced in a good way.

> You may feel that you can accomplish everything you need to in IF
> within single code blocks.

In their interrelation, yes. By messaging and querying other objects
from within one object.

In your excitement, I think you have mischaracterized OO programming,
forgetting that it is also essentially relational.

> I think you'll find otherwise when you've
> played with a system for a while.

Just any old system, or do you have a particular system in mind? :)

> [Y]ou're doing exactly what I was looking at in TADS2. This


> is the standard, simple, OO approach to the problem,

That's right, and it seems to be working fine of course.

> and it's the
> approach that I consider to have failed to be flexible enough to be a
> general solution.

When you have two competing customizations, you have to resolve the
conflict by hand no matter what system you use. That this is necessary
is not a failure of the system, but a fact of the project.

> a) this case comes up
> very, very often in IF

It comes up often that more than one object or more than one piece of
data is involved in the logic, but it does not come up often that this
means there is some great disaster.

> b) attempting to make two objects aware of each
> other violates OO encapsulation and leads to deep, hairy spaghetti
> interconnections

Such programming as "if(self.location == b.location)..." does not
constitute a violation of OO encapsulation, or a hairy spaghetti. You
seem to be imagining an OO where all methods and properties are
private. (Odd indeed, to call this OO -- OOP always involves multiple
objects because their relation is the whole point of the model.)

> c) overriding the main plan object is a good
> 'emergency escape hatch' but basically ignores the OO inheritance
> hierarchy completely and does not play well with any other conditions.

It splits the decision code, but so does relation-based programming.
The fact that you need some logic which relates the objects does not
mean that OO is broken.

> You can implement the TADS2/TADS3
> behaviour as a *subset* of rule-based behaviour (any rule that doesn't
> define a direct object, for instance, can be assumed to match all of
> them, which is the same as a condition being checked 'before' checking
> the direct object).

I'm sorry, but I can't follow your logic. You might be saying something
substantial here, so perhaps you can explain.

> > > And there's three main objects involved in any

> > > plan: the relation/condition, the first object, the second object.[...]


> > > This is where OO breaks down, because this logic does not belong with
> > > any particular object of the three, so it can't be easily overridden
> > > simply by subclassing one object and replacing one method.

[...]


> Look, I'm not pushing any particular barrow here except my own.

Let's just say that this reminds me of the argument Plotkin makes when
arguing for a rule-based IF system, an argument seminal to I7, and
repeated by its designer in his description of the system.

> I have
> no idea what you mean by 'boilerplate I7 theory'

That OO is somehow broken because its objects' behavior is
interdependent. (Or, to put it crudely, that objects have to reference
one another.) Don't get me wrong, though -- I like Plotkin's argument
nevertheless, and I expect it's ground for further productive thought.

> but frankly it sounds
> like a thinly veiled insult

Not at all -- I just mean that this is what one might excitedly (and
somewhat inaccurately) say about rule-based systems in general (under
the aegis of "first principles," perhaps), and I'd rather hear more
about what this has to do with designing a planbase.

> [R]ules can model precedence


> relationships which are much more complicated than simple trees.
>
> OO handles trees well. Rules can do webs.

I think that this is your main point, in a nutshell. In anticipation of
what I hope will be your elaboration, let me try to unpack this
statement: that rule-based (relation-based) programming can handle
web-like logic, as opposed to tree-like logic.

I'll take a very simple example, but one which I think represents
web-like logic: moving around a game-object in a game. Let's say for
simplicity that there are only three objects involved when an object is
moved: the initial location, the destination, and the object being
moved.

Around these three objects, the web: basically we want, during the
move, to make sure that all three objects to agree that the move is
permissible. This isn't terribly webby, of course, but it's more
complicated than it might appear at first blush: at minimum we must
check if the initial location will allow the object to be moved (into
the destination); check if the destination will allow the object to be
moved into it (from the initial location); check if the object will
allow itself to be moved (from the initial location and to the
destination).

These three checks are all relational -- indeed they each involve at
least two and really all three objects. Now, if you're staring blankly
at the blank screen, trying to imagine a single code block to handle
this, I can imagine that relation-based programming is going to look
pretty appealing.

However, if you know how to program (and you do, so you probably know
where I'm heading), you'll break this into stages, each stage
representing one of the things you want to check. You'll decide where
each bit of code goes by figuring out which object is making the
decision at each stage. You'll "notify" each object involved in the
relation, from within a larger wrapper method (e.g., the moving
object's main "move" method). And it will be perfectly customizable.

I'm not saying that there's no rationale whatsoever for relation-based
programming, or that the complaint against OOP is completely unfounded:
it is possible to devise examples where OOP-style relation is not
perfectly sturdy. But in the vast number of cases, these webs you
imagine can be broken down into straightforward OOP-style relations
with minimal effort.

In any case, pretending that the concept of relation is foreign to OO
is just plain silly.

vaporware

unread,
Jun 14, 2006, 8:45:04 AM6/14/06
to
steve....@gmail.com wrote:
> Nate Cull writes:
[...]

> > [R]ules can model precedence
> > relationships which are much more complicated than simple trees.
> >
> > OO handles trees well. Rules can do webs.
[...]

But it's not always clear which object *should* make the decision at
each stage. Which object should be consulted first: the initial
location, the destination, or the item being moved?

And what if a decision depends on the state of two objects: nothing can
be moved between X and Y, but all other moves are permissible? You can
flip a coin to pick X or Y, and put the code there, but having to make
an arbitrary choice like that seems like a sign that the paradigm is
breaking down.

vw

Kyle Pierce

unread,
Jun 14, 2006, 9:26:47 AM6/14/06
to
na...@natecull.org wrote:
> No idea quite how we'd specify these rules, something Prologish perhaps
> though I don't quite grok Prolog. I probably need to learn but the
> examples seem very contrived and not terribly real-worldy. (There is a
> proto-IF system, though -
> http://www.ainewsletter.com/downloads/if_docs/ - which could be fun to
> play with and see if it's useful. Needs a good library and a much
> better example than Duck World.)
>

BTW, thanks for sharing your work on Planner. I got some good insights
into actually implementing an algorithm in I7 from studying your code.
I studied the TADS3 version before, and the I7 version is a good bit
shorter and more readable. But I have the impression it would be easier
still for me to do something like that in Prolog. This is partly
because I know Prolog better, but also, Prolog's rule engine is simple
and its behavior is pretty transparent, because it is based on a single
algorithm. Maybe at some point I7 will be that transparent to me, but I
sort of doubt it.

So, I am more tempted than ever to go back to working in Prolog. I
spent some time running the Amzi IF library and studying the source
files. That was nice of Amzi to make their IF library publicly
available, and I guess you can modify the files template.pro and
template_english.pro to make your own games. But to compile your own
version of the library you would have to buy their commercial Prolog
system. Probably anyone who is motivated enough to learn a language as
powerful as Prolog would want to be able to do that.

There are other good Prologs that are free. If you're interested in
pursuing anything with Prolog beyond the Amzi IF library, you might
check out SWI-Prolog.org. Theirs is one of the leading Prolog compilers
and it's free software. I've been using SWI-Prolog myself for many
years.

Kyle

steve....@gmail.com

unread,
Jun 14, 2006, 9:57:54 AM6/14/06
to
vaporware wrote:
> But it's not always clear which object *should* make the decision at
> each stage.

That is true. It's not always clear -- I'm not arguing that it is
always clear. However, the frequency of this, and the problematics when
it does happen, the problem's importance and the urgency of its
solution -- these things can be very easily exaggerated.

> Which object should be consulted first: the initial
> location, the destination, or the item being moved?

This is a separate question. Everything else being equal, you would
probably prefer to order the operations to reflect their natural order:
an object is removed from one location before it is placed in another.
When do you notify the object itself? Doesn't matter: fine either way.

> And what if a decision depends on the state of two objects: nothing can
> be moved between X and Y, but all other moves are permissible? You can

> flip a coin to pick X or Y, and put the code there[...]

No, you'd probably want to put the code in the first place it makes
sense. So, in your example, the code would go in the
remove-notification. Either way is fine, though, so if you want to put
it in the insert notification for some reason, go right ahead.

> but having to make
> an arbitrary choice like that seems like a sign that the paradigm is
> breaking down.

Why's that? The fact that there may be more than one correct way to do
something doesn't seem to directly imply that there's a problem.

Andrew Plotkin

unread,
Jun 14, 2006, 10:14:10 AM6/14/06
to
Here, steve....@gmail.com wrote:
> vaporware wrote:
> > But it's not always clear which object *should* make the decision at
> > each stage.
>
> That is true. It's not always clear -- I'm not arguing that it is
> always clear. However, the frequency of this, and the problematics when
> it does happen, the problem's importance and the urgency of its
> solution -- these things can be very easily exaggerated.

So can the ease and naturalness of breaking down a set of rules into
object behaviors.

Perhaps you should try implementing a complicated bit of game logic in
an OO manner and a rule-based manner, to compare them. Experience is
an excellent antidote to worries about exaggeration.

There are bugs in _So Far_ that I never bothered fixing, because it
was too much work to drop in the fixes in every object and action
where they were needed. (I'm thinking of the prohibitions on making
noise in certain areas.) These would be very simple I7 rules.

--Z

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

You don't become a tyranny by committing torture. If you plan for torture,
argue in favor of torture, set up legal justifications for torturing
someday, then the moral rot has *already* set in.

vaporware

unread,
Jun 14, 2006, 10:21:30 AM6/14/06
to
steve....@gmail.com wrote:
> vaporware wrote:
[...]

> > Which object should be consulted first: the initial
> > location, the destination, or the item being moved?
>
> This is a separate question. Everything else being equal, you would
> probably prefer to order the operations to reflect their natural order:
> an object is removed from one location before it is placed in another.
> When do you notify the object itself? Doesn't matter: fine either way.

But sometimes that will be wrong, and you may have general conditions
applying to the initial location that should be overridden in special
cases by a condition on the destination.

Point is, it's a question you're forced to tackle in a purely OO
system, and you have to structure your code unnaturally to deal with
it. There is no need, in a rule based system, to have a fixed schedule
of which objects are checked in which order. There's no need for the
library or extension author to pick a default order.

> > but having to make
> > an arbitrary choice like that seems like a sign that the paradigm is
> > breaking down.
>
> Why's that? The fact that there may be more than one correct way to do
> something doesn't seem to directly imply that there's a problem.

They both work, but they're both awkward. They don't reflect the
author's intent; a rule about moving things between two rooms doesn't
naturally belong to either room. Rule based programming lets you
separate the rule from its components.

vw

Kevin Forchione

unread,
Jun 14, 2006, 11:12:05 AM6/14/06
to
<na...@natecull.org> wrote in message
news:1150175907....@g10g2000cwb.googlegroups.com...

>
> Kevin Forchione wrote:
>> The TADS 3 module could be rewritten to be rule based. Don't see why not.
>> As
>> I understand it the "rules" of I7 are nothing more than routines that
>> return
>> either true (if successful or failure) and false (if not applicable).
>> There's no reason why the TADS 3 RAP mechanism couldn't do the same, if
>> rules are the bread and butter of your existence.
>
> Yes, and I think the I6 version could do this too. And quite possibly
> an OO approach to rules would give you more flexibility than the
> fixed-at-compile-time rule syntax in I7. (TADS3 quite possibly already
> does a large part of the things I'm after - fully dynamic VM, hackable
> parser, I'm not entirely sure why I haven't tried using it yet. Mostly
> fatigue from its perpetual beta-ness and a shock reaction to the size
> of the library. And an irrational fondness for the Z-machine, but I'm
> reconciling myself to abandoning that anyway.)

Yes, ironically when people talk about an alternate target language other
than I6, they're describing those elements that TADS 3 possesses.

--Kevin


Kevin Forchione

unread,
Jun 14, 2006, 11:17:03 AM6/14/06
to
"Stephen Granade" <stephen...@granades.com> wrote in message
news:m3lks1z...@sargent.dyndns.org...

> I agree with what Nate said downstream: certainly it could. There's
> nothing magical about rules that keeps you from adding them to any
> language, provided you're willing to do the heavy lifting. Reducing
> the concept to routines that return a boolean is skipping past the
> really hard parts, though, namely, how do you decide rule precedence?
> And how do you allow on-the-fly reordering of them? Given recent
> discussions on this newsgroup, that's where the tricky bits are, and
> it's a problem we don't yet have a great solution to.

That's one of the dynamics of systems development. I7 pioneers and approach,
and the other systems pick the best bits and leverage them. In a sense I7 is
doing proof-of-concept for this rules approach, and once these discussions
have sorted out most of the issues inherent then it will be up to I7 to
attempt to implement a solution, if it proves too difficult to implement
under it's current infrastructure then another system will no doubt
successfully implement one based on that analysis.

--Kevin


na...@natecull.org

unread,
Jun 14, 2006, 11:38:23 PM6/14/06
to

Kyle Pierce wrote:

> BTW, thanks for sharing your work on Planner. I got some good insights
> into actually implementing an algorithm in I7 from studying your code.

Yay. :)

> I studied the TADS3 version before, and the I7 version is a good bit
> shorter and more readable. But I have the impression it would be easier
> still for me to do something like that in Prolog. This is partly
> because I know Prolog better, but also, Prolog's rule engine is simple
> and its behavior is pretty transparent, because it is based on a single
> algorithm. Maybe at some point I7 will be that transparent to me, but I
> sort of doubt it.

Yes, Prolog is looking more appealing to me too. But I never learned
more than the basic textbook logic examples (' father(X,Y) :- male(X),
child(Y,X) ') and am still quite unsure how to even begin handling, eg,
I/O in it.

> There are other good Prologs that are free. If you're interested in
> pursuing anything with Prolog beyond the Amzi IF library, you might
> check out SWI-Prolog.org. Theirs is one of the leading Prolog compilers
> and it's free software. I've been using SWI-Prolog myself for many
> years.

Oh good. I've installed SWI-Prolog on my Dapper box, but I'm sort of
stymied as to how to get hacking. Can you recommend any good
introductions (preferably from a 'I know imperative programming, how
the heck do I do stuff?' angle?)

Prolog excites me on one level, but it also seems so... sterile. Can
everything in the world really be represented as Horn clauses?

Kyle Pierce

unread,
Jun 15, 2006, 9:07:13 AM6/15/06
to
na...@natecull.org wrote:

> > There are other good Prologs that are free. If you're interested in
> > pursuing anything with Prolog beyond the Amzi IF library, you might
> > check out SWI-Prolog.org. Theirs is one of the leading Prolog compilers
> > and it's free software. I've been using SWI-Prolog myself for many
> > years.
>
> Oh good. I've installed SWI-Prolog on my Dapper box, but I'm sort of
> stymied as to how to get hacking. Can you recommend any good
> introductions (preferably from a 'I know imperative programming, how
> the heck do I do stuff?' angle?)
>
> Prolog excites me on one level, but it also seems so... sterile. Can
> everything in the world really be represented as Horn clauses?

As far as representing things in the world, I think the problem you are
seeing is that, in contrast to Inform or TADS, in Prolog this remains
more of a do-it-yourself task (and not a technical limitation). The
Prolog code that comes with that Amzi IF download is the first I've
seen that makes an effort to handle basic IF functionality. Maybe it
could be done in a better way but right now that code is the best
starting point I know of.

Prolog is based on a lower-level, more-powerful rule engine that
doesn't have the additional layers of semantic wrapping built into I7.
Not only that, but for some reason the documentation for AI languages
typically features pretty lame and limited examples (in which words
like "foo" often show up a lot).

But if we want to work more directly with the rule engine itself, then
we have to go pretty far behind the scenes, where things are, yes, a
bit sterile. Look at the Z-machine, though -- until you add the
semantic wrapping, it all looks pretty sterile, doesn't it?

The thing I appreciate most about the IF community is the wealth of
rich descriptions that are grounded in good observations and intuitions
about the world. I am not a gamer by any stretch, but I am fascinated
by the potential for creating interesting "story puzzles" that are sort
of a take-off on IF as I understand it.

Also I would suggest clicking on the "Links" link on the left of the
SWI home page, and looking at some of the tutorials and even textbooks
that are available online. I hope to have some time soon to convert the
Amzi IF code to SWI-Prolog. Yes there is an ISO standard Prolog but as
you might expect there are some differences between compilers. I will
keep you posted if and when I have more to offer, and if you have
questions I will try to answer them.

Kyle

Kyle Pierce

unread,
Jun 15, 2006, 10:05:44 AM6/15/06
to
I meant to include this reference to a tutorial that is for SWI-Prolog
specifically:

http://www.cse.ucsc.edu/classes/cmps112/Spring03/languages/prolog/PrologIntro.pdf

Hope this helps,

Kyle

steve....@gmail.com

unread,
Jun 15, 2006, 10:45:37 AM6/15/06
to

Kyle Pierce wrote, Quoting Nate Cull:

> > Prolog excites me on one level, but it also seems so... sterile. Can
> > everything in the world really be represented as Horn clauses?
[...]

> But if we want to work more directly with the rule engine itself, then
> we have to go pretty far behind the scenes, where things are, yes, a
> bit sterile. Look at the Z-machine, though -- until you add the
> semantic wrapping, it all looks pretty sterile, doesn't it?

I'd like to add that there are ways to extend Prolog to enable it to
handle a broader logic, such as PTTP. I would also like to say how
impressed I am how far one can go with simple Horn clauses; not sterile
-- quite the contrary!

Kyle Pierce

unread,
Jun 15, 2006, 12:26:14 PM6/15/06
to
Something else I neglected to point out about Prolog, that is relevant
to IF developers who are interested in parsing: Prolog was originally
invented as a programming language in which to write natural language
applications, and thus Prolog is a very elegant language for expressing
grammars. Prolog even has a builtin syntax (the DCG or Definite Clause
Grammar) especially created for writing grammars. It is often said that
with Prolog one gets a builtin parser for free.

If you google "Prolog DCG" you can find all sort of references. There
are some examples of DCG usage in the Amzi IF source code:
specifically, the filenames that fit the pattern *_english.pro. I
included part of one here:

% These grammar rules define the vocabulary words or
% phrases for the different parts of speech. For example, the
% internal command token, 'take', is recognized from input
% strings beginning with "get" or "pick up".

% The verbs have the number of arguments to make it
% easier to distinguish between put with one argument
% and put with two arguments. The internal token
% for the one argument version is 'drop', and is 'put'
% for two.

% The first vocabulary entry for each of the words will
% be used when presenting the player with hints.
verb(drop,1) --> [drop].
verb(drop,1) --> [put].
verb(drop,1) --> [hang].
verb(examine,1) --> [examine].
verb(examine,1) --> [x].
verb(examine,1) --> [look,at].
verb(go_direction,1) --> [go].
verb(go_place,1) --> [go,to].
verb(go_place,1) --> [go].
verb(help,0) --> [help].
verb(hint,0) --> [hint].
verb(inventory,0) --> [inventory].
verb(inventory,0) --> [i].
verb(look,0) --> [look].
verb(options,0) --> [options].
verb(options,1) --> [options].
verb(put_at,2) --> [put].
verb(put_at,2) --> [hang].
verb(quit,0) --> [quit].
verb(score,0) --> [score].
verb(take,1) --> [take].
verb(take,1) --> [get].
verb(take,1) --> [take].
verb(take,1) --> [grab].
verb(take,1) --> [pick,up].
verb(take_off,1) --> [take,off].
verb(wear,1) --> [wear].
verb(wear,1) --> [put,on].

% The grammar rules can refer back to the game. This
% rule says anything is a verb if it appears in the game
% logic's action clause. This lets the game be played
% using internal tokens during development.
verb(V,_) --> [V], { a_verb(V) }. % a catch all

% As with the other tokens, the first entry is the one
% that will be used in hints and in short descriptions to
% the player. So the 'cloak' will be referred to as
% "velvet cloak" and the 'hook' as "brass hook".

% The adjectives for items can be simply enumerated
% here with the items, as with "velvet cloak", but if it
% is desired to handle more complex and arbitrary sequences
% of adjectives, then an additional 'adjectives' grammar
% rule is needed, as is used here.
object(cloak) --> [velvet, cloak].
object(cloak) --> [cloak].
object(hook) --> [brass, hook].
object(hook) --> adjectives(hook), [hook].
object(hook) --> adjectives(hook), [peg].
object(hat) --> [hat].

steve....@gmail.com

unread,
Jun 15, 2006, 6:17:45 PM6/15/06
to
Andrew Plotkin wrote, quoting me:

> > That is true. It's not always clear -- I'm not arguing that it is
> > always clear. However, the frequency of this, and the problematics when
> > it does happen, the problem's importance and the urgency of its
> > solution -- these things can be very easily exaggerated.
>
> So can the ease and naturalness of breaking down a set of rules into
> object behaviors.

That is also true, but packing the process in a black box is a
sacrifice, so the rule-based regime remains at a disadvantage, even if
it can do one or two things slightly better.

> Perhaps you should try implementing a complicated bit of game logic in
> an OO manner and a rule-based manner, to compare them.

BTDT, but this is beside the point. Quite apart from the real and
imagined gains of rule-based programming (including or ignoring the
sacrifice involved), I was asking *how* a planner written in I7
leverages this, and *why* it's important. These questions have not been
sufficiently answered. I'm probably better off asking a newsgroup which
specializes in logic programming (or AI), but I was hoping Nate could
answer the question.

(By the way.... Have you yet performed this experiment?)

> There are bugs in _So Far_ that I never bothered fixing, because it
> was too much work to drop in the fixes in every object and action
> where they were needed. (I'm thinking of the prohibitions on making
> noise in certain areas.) These would be very simple I7 rules.

You'd weigh this with/against the (in-)convenience of programming the
rest of the game in I7. The fact that I7 does this-or-that better means
very little.

na...@natecull.org

unread,
Jun 15, 2006, 6:54:57 PM6/15/06
to

steve....@gmail.com wrote:
> That is also true, but packing the process in a black box is a
> sacrifice, so the rule-based regime remains at a disadvantage, even if
> it can do one or two things slightly better.

The I7 rule engine is not a black box. I'm not sure why you keep saying
this. It has clearly defined precedence behaviour, of roughly the same
order as Prolog. It's a lot simpler and more predictable than Prolog
in many respects. (Prolog doesn't appear to sort its rules by order of
specificity, which I find frustrating; otoh, Prolog rules can trigger
their own subgoals which is much more complex behaviour than I7's rule
engines. I7 also doesn't have cuts or backtracking, which I find quite
hard to predict.)

One of my projects in learning Prolog will be to try to implement an
I7-like most-general-predicate first search, as well as a Planner-like
breadth-first search.

> BTDT, but this is beside the point. Quite apart from the real and
> imagined gains of rule-based programming (including or ignoring the
> sacrifice involved), I was asking *how* a planner written in I7
> leverages this, and *why* it's important. These questions have not been
> sufficiently answered. I'm probably better off asking a newsgroup which
> specializes in logic programming (or AI), but I was hoping Nate could
> answer the question.

I did answer the question, several times. I explained exactly using
rules helps me to overcome real problems I encountered using my former
TADS2 OO method. You ignored my answer and claimed I was seeing a
problem that wasn't there. That's your choice, but that you didn't want
to hear what I had to say is not the same as me not saying it.

steve....@gmail.com

unread,
Jun 15, 2006, 7:32:26 PM6/15/06
to
Nate Cull wrote:
> The I7 rule engine is not a black box. I'm not sure why you keep saying
> this. It has clearly defined precedence behaviour, of roughly the same
> order as Prolog.

Now you're being silly. Prolog is also a black box language, of course.
All rule-based languages are black-box languages, because the process
is written in a different language.

> It's a lot simpler and more predictable than Prolog
> in many respects.

This is also silly. Prolog has very few "respects" for comparison. In
fact, Prolog is the simplest language I can think of, off hand. The
logic is simpler, and unoccluded by a parse web.

> One of my projects in learning Prolog will be to try to implement an
> I7-like most-general-predicate first search, as well as a Planner-like
> breadth-first search.

Super.

> > I was asking *how* a planner written in I7
> > leverages this, and *why* it's important. These questions have not been

> > sufficiently answered.[...]


>
> I did answer the question, several times.

Thank you for your efforts, but as I said, these questions have not
been sufficiently answered. I hope we don't pretend that they have
been, as this would be obstructive. You have addressed the questions,
and I appreciate the effort, but most of this does not apply
specifically to the real work of writing planners and their databases.

The best I've gotten is that the I7 Planner is slightly better at
handling cases where both objects have custom plans -- and even this
minor claim is a bit stretched, since you have to program the tiebreak
no matter what language.

steve....@gmail.com

unread,
Jun 15, 2006, 7:52:57 PM6/15/06
to
vaporware wrote, quoting me:

> > This is a separate question. Everything else being equal, you would
> > probably prefer to order the operations to reflect their natural order:
> > an object is removed from one location before it is placed in another.
> > When do you notify the object itself? Doesn't matter: fine either way.
>
> But sometimes that will be wrong, and you may have general conditions
> applying to the initial location that should be overridden in special
> cases by a condition on the destination.

Well, you could very easily code that also, but your larger point is of
course correct: that if you continue to add this kind of problem on top
of this kind of problem, you'll run into the situation where a built-in
algorithm designed to handle such situations is preferable.

> Point is, it's a question you're forced to tackle in a purely OO
> system, and you have to structure your code unnaturally to deal with
> it.

Don't know what you mean by "it," but you might favor tackling the
problem in a purely OO system, rather than tackling it in a rule-based
system. There are advantages to both, and both are unnatural.

> There is no need, in a rule based system, to have a fixed schedule
> of which objects are checked in which order.

There's a (perceived) degree of freedom, but they are checked in an
order. One of my prejudices against rule-based systems is that you
don't get a bird's eye view of such things.

> There's no need for the
> library or extension author to pick a default order.

No, this is incorrect. If you want to make good overrides, you have to
know the order they come in.

> [A] rule about moving things between two rooms doesn't


> naturally belong to either room.

If you want to disallow movement from A to B, the code would most
logically go in A. If you think of the "move" as a construct itself,
yes you could say the code belongs in the "move" construct.

> Rule based programming lets you
> separate the rule from its components.

To the extent that such is useful, and to the extent that this
overcomes the costs, hooray for rule-based programming. I'd like to see
a much better rule-based system than I7, which I appreciate as a very
useful (though somewhat misguided) testing ground.

Andrew Plotkin

unread,
Jun 15, 2006, 11:56:42 PM6/15/06
to
Here, steve....@gmail.com wrote:
> Andrew Plotkin wrote, quoting me:
> > > That is true. It's not always clear -- I'm not arguing that it is
> > > always clear. However, the frequency of this, and the problematics when
> > > it does happen, the problem's importance and the urgency of its
> > > solution -- these things can be very easily exaggerated.
> >
> > So can the ease and naturalness of breaking down a set of rules into
> > object behaviors.
>
> That is also true, but packing the process in a black box is a
> sacrifice, so the rule-based regime remains at a disadvantage, even if
> it can do one or two things slightly better.

This is the great thing about getting into discussions with you,
Steve. I know it'll be two posts, max, before you simply declare your
position to be correct. Then we can all move on!

(Bonus points when you quote someone who disagrees with you as support
for your side!)



> > Perhaps you should try implementing a complicated bit of game logic in
> > an OO manner and a rule-based manner, to compare them.
>
> BTDT, but this is beside the point. Quite apart from the real and
> imagined gains of rule-based programming (including or ignoring the
> sacrifice involved), I was asking *how* a planner written in I7
> leverages this, and *why* it's important. These questions have not been
> sufficiently answered.

Easier specification of complex conditions and goals, because subcases
can be described in localized code. (The compiler collates them them
together when generating the code, in the appropriate logical
structure). Thus, greater scalability, because less time need be spent
organizing pieces of code that are unconnected from a design
standpoint. There you go. Don't worry, this won't be on the test.

(Also, bonus points to you for parallel structure. The gains may be
real or imagined; the sacrifice may be considered or ignored. Guess
that means the sacrifice is real!)

> (By the way.... Have you yet performed this experiment?)

Yes. Then I posted a 350-line article discussing how it came out. Enh,
you'd have to have been there.



> > There are bugs in _So Far_ that I never bothered fixing, because it
> > was too much work to drop in the fixes in every object and action
> > where they were needed. (I'm thinking of the prohibitions on making
> > noise in certain areas.) These would be very simple I7 rules.
>
> You'd weigh this with/against the (in-)convenience of programming the
> rest of the game in I7. The fact that I7 does this-or-that better means
> very little.

And now we can move on!

Bonus points for deciding that when Nate disagrees with you, he's just
being silly. I also see that pretending you're wrong would be
obstructive.

--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.

Andrew Plotkin

unread,
Jun 16, 2006, 12:14:56 AM6/16/06
to
Here, na...@natecull.org wrote:
>
> One of my projects in learning Prolog will be to try to implement an
> I7-like most-general-predicate first search, as well as a Planner-like
> breadth-first search.

For what it's worth, I have assumed all along that Prolog can do what
I want (the whole vaguely-specified and hand-wavy cloud of What I
Want.)

However, my only use of Prolog was a few weeks in CS 15-312, and it
made my head hurt. (I never did understand why the dichotomy between
red cuts and green cuts was a false one. Sorry -- I know my status as
an ivory-tower theoretician will never recover...)

This is why I've been trying to come up with a simpler model (i.e.,
not requiring the full generality of Prolog's engine). This may of
course turn out to be a fool's errand. But since I am (to date) still
hung up on defining my needs, I haven't worried about what kind of
logical deduction engine those needs will require.

Your desire to link planning rules with world-customization rules is
helpful. Well, helpful in that I've added it to What I Want, thus
complicating my life. :)

--Z

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

steve....@gmail.com

unread,
Jun 16, 2006, 12:49:25 AM6/16/06
to
Andrew Plotkin wrote, quoting me:
> > packing the process in a black box is a
> > sacrifice, so the rule-based regime remains at a disadvantage, even if
> > it can do one or two things slightly better.
>
> This is the great thing about getting into discussions with you,
> Steve. I know it'll be two posts, max, before you simply declare your
> position to be correct.

Of course I don't mean that rule-based programming is ultimately at a
disadvantage, only that it comes at a cost.

I simply point out that, if we're comparing two systems that do about
the same thing, the rule-based system is at a disadvantage (because
it's black-boxed), even if it achieves some slightly better results in
certain cases.

> (Also, bonus points to you for parallel structure. The gains may be
> real or imagined; the sacrifice may be considered or ignored. Guess
> that means the sacrifice is real!)

I don't know what you're talking about, but yes, the sacrifice is real.
Ask anyone who works in knowledge-base systems. You lose an overview of
the code.

> > (By the way.... Have you yet performed this experiment?)
>
> Yes. Then I posted a 350-line article discussing how it came out. Enh,
> you'd have to have been there.

Sorry, too much noise; didn't catch it. Looking forward to reading it.

> Bonus points for deciding that when Nate disagrees with you, he's just
> being silly. I also see that pretending you're wrong would be
> obstructive.

Now you are being silly. I hope that when we agree or disagree, we can
do so on substance. My person has nothing to do with the ideas under
discussion.

vaporware

unread,
Jun 16, 2006, 12:59:27 AM6/16/06
to