New extension: Scope Caching

I’ve had this lying around for a while, ever since Zarf explained how to do it. But I came up with a situation where I actually had to use it, so I thought it was time to write some documentation and flesh it out a little.

eyeballsun.org/i/Scope%20Caching.i7x

Please have a look at it. I would happily take advice on improving the lame example.

But about that example

I’m not 100% sure why this happens, but if I don’t use Scope Caching, this gets stuck in an infinite loop:

[code]Indoors is a room.

The front door is a door. It is west of Indoors and east of Outdoors.

There is a container called a pile of balls in Indoors. “There is a pile of rubber balls here.” In the pile is a ball.

Understand “rubber” as a pile when the ball is not visible.
Understand “rubber” as a ball when the ball is visible.

The outdoor view is scenery. The description is “It’s bright outside.”;

After deciding the scope of the player in Indoors when the front door is open:
place the outdoor view in scope.

Test me with “open door/rules/get rubber”[/code]

I sort of get the idea, but the situation seems weird. What happens during “place the outdoor view in scope” that causes the infinite loop, exactly?

Also, if you think this should be a two-star example rather than a one-star example, let me know.

I found what in PlaceInScope is causing the infinite loop. The first line is “wn = match_from;”

The parse_name routine of the ball does a visibility test, which means a scope test; that invokes PlaceInScope; PlaceInScope resets wn, the global word-count index. Thus the parse_name routine never makes progress through the input buffer.

(It’s not an infinite recursion, as I originally thought. Just a loop whose counter keeps being reset.)

I have no idea what that line is doing there, or what case it supports. If I comment it out, this example works.

I’ve updated the extension to include optimizations for Epistemology by Eric Eve and Remembering by Aaron Reed. Let me know if there are any problems or oversights with the interactions between them.

The same link applies to the extension, but for your convenience, I’ll spoiler it right here:

[spoiler][code]Version 1/110913 of Scope Caching by Mike Ciul begins here.

“Gives things the ‘marked visible’ property, to check the visibility of something without repeating the entire scope loop each time.”

Use authorial modesty.

Volume 1 - Scope Caching

Chapter 1 - Iterating over Scope

[Thanks to Andrew Plotkin for this code to make the scope checking not incredibly repetitive]

To iterate scope with (func - phrase thing -> nothing): (- LoopOverScope({func}–>1); -).

To iterate scope for (actor - thing) with (func - phrase thing -> nothing): (- LoopOverScope({func}–>1, {actor}); -).

Chapter 2 - The Marked Visible Property

A thing can be marked visible or marked invisible.

To mark the/-- visibility of (target - a thing) (this is scope caching):
now target is marked visible;

To cache the/-- scope for (viewer - a person):
Now everything is marked invisible;
Iterate scope for viewer with scope caching.

Chapter 3 - When to Perform Scope Caching

After reading a command (this is the cache player’s scope rule):
Cache the scope for the player.

The cache player’s scope rule is listed first in the after reading a command rules.

Volume 2 - Interactions with Other Extensions

Book 2 - Sight (in place of Book 1 - Sight in Epistemology by Eric Eve)

A thing can be either seen or unseen. A thing is usually unseen.

[ With the speed advantages of scope caching, we can now do more accurate accounting of what has actually been seen. ]

After reading a command (this is the mark cached items as seen rule):
Now every marked visible thing is seen.

The mark cached items as seen rule is listed after the cache player’s scope rule in the after reading a command rulebook.

The cache player’s scope rule is listed last in the carry out looking rules.
The mark cached items as seen rule is listed last in the carry out looking rules.

The cache player’s scope rule is listed last in the carry out opening rules.
The mark cached items as seen rule is listed last in the carry out opening rules.

Book 3 - Remembering (for Glulx only)

Section - Rules (in place of Section - Rules in Remembering by Aaron Reed)

After reading a command (this is the update remembered positions of cached things rule):
repeat with item running through marked visible things that are enclosed by the location:
if remembered location of item is not holder of item:
now the remembered location of item is the holder of item.

The update remembered positions of cached things rule is listed after the cache player’s scope rule in the after reading a command rules.

First report remembering (this is the Remembering specific report remembering rule):
if remembered location of noun is nothing, continue the action;
say the message corresponding to a rule name of Remembering specific report remembering rule in Table of Remembering Messages;
stop the action.

Volume 3 - Testing commands - not for release

Checking the scope cache is an action out of world. Understand “scopestat” as checking the scope cache.

Report checking the scope cache:
say “The following items are marked visible: [line break]”;
repeat with item running through marked visible things:
say " [the item][line break]";

Checking the scope cache for is an action out of world applying to one visible thing. Understand “scopestat [any thing]” as checking the scope cache for.

Carry out checking the scope cache for something:
Cache the scope for the noun;

Report checking the scope cache for something:
say “The following items are marked visible for [the noun]: [line break]”;
repeat with item running through marked visible things:
say " [the item][line break]";

Scope Caching ends here.

---- DOCUMENTATION ----

Optimizes Epistemology by Eric Eve and Remembering by Aaron Reed. I6 code by Andrew Plotkin. Andrew also explained how to pass a phrase as an argument to another phrase for looping.

Section: The Marked Visible Property

Scope Caching creates a property for things called “marked visible.” This is equivalent to the “visible” adjective, except it is calculated only at specific times and then stored, trading storage space for speed.

These conditions:

the player can see the ball

the ball is visible

Will normally mean the same as:

the ball is marked visible

Section: The Cache Scope Phrase

If circumstances change during a turn and we need to check scope again, or if we want to check scope for something other than the player, we need to refresh the cache. We can do this with the “cache scope” phrase:

Before Bob trying doing something:
	cache scope for Bob

This will, of course, leave the “marked visible” property set for Bob, so if we need to check the player’s scope again, we need to run the phrase an additional time.

Section: The Cache Scope After Reading a Command Rule

This is the rule which normally sets the “marked visible” property each turn:

After reading a command (this is the cache scope after reading a command rule):
	Cache the scope for the player.

It’s listed first in the “after reading a command” rulebook, so other “after reading a command” rules should be able to make use of the “marked visible” property.

Section: Testing Commands

We can use the “scopestat” command to find out what items are currently marked visible. The command by itself will list the items marked visible for the player, while “scopestat [any thing]” will list the items visible for another person.

Example: * Which Rubber - Uses Scope Caching to prevent an infinite loop. Without it, the “After deciding the scope of the player” rule repeats forever.

*: "Which Rubber"

Include Scope Caching by Mike Ciul.

Indoors is a room.

The front door is a door. It is west of Indoors and east of Outdoors.

Bob is a man in Outdoors.

There is a container called a pile of balls in Indoors. "There is a pile of rubber balls here." In the pile is a ball.

Understand "rubber" as a pile when the ball is not marked visible.
Understand "rubber" as a ball when the ball is marked visible.

The outdoor view is scenery. The description is "It's bright outside.";

After deciding the scope of the player in Indoors when the front door is open:
	place the outdoor view in scope.

Test me with "rules/open door/get rubber/scopestat/scopestat bob"

[/code][/spoiler]

I had one point I wasn’t sure about, in the section of rules for Remembering:

After reading a command (this is the update remembered positions of cached things rule): repeat with item running through marked visible things that are enclosed by the location: if remembered location of item is not holder of item: now the remembered location of item is the holder of item.

The “enclosed by the location” clause is preserved from the original, where I assume it was used to minimize visibility tests. My question regards objects that are not enclosed by the location, but have been added to scope by a rule. Added objects might be the contents of a room you can look into, or abstract things that don’t really exist anywhere.

Should they also be remembered?

Should they only be remembered if their holder is a thing or a room?

Should they only be remembered if they’re not off-stage?

It’s possible that some authors might create a room or a container just to hold abstract things that are added to scope - should we warn authors about it in the documentation?