Can a rulebook be list based?

There’s a trivial “yes” answer here, one can compile

Dpointer is a kind of value. The dpointers are d1, d2, d3, d4.

Exampling is a (list of dpointers) based rulebook producing a text.

But I haven’t found a way to qualify rules for it that I7 will accept.

Exampling { d1, d2, d3 }: rule succeeds with result "!".

gets

>--> In 'Exampling {d1, d2, d3}' [...] you use a list which might or might not
    match a definition requiring a list of dpointers. But there's no efficient
    way to tell during play whether the list actually contains that, without
    laboriously checking every entry. Because in general this would be a bad
    idea, this usage is not allowed.

And

Exampling a (list of dpointers) called L when the number of entries in L is 1:
    rule succeeds with result ".".

gets

>--> You wrote 'Exampling a (list of dpointers) called L when the number of
    entries in L is 1' [...] but the description of the thing(s) to
    which the rule applies ('a (list of dpointers) called L') did not make
    sense. This is a list of dpointers based rulebook, so that should have
    described a list of dpointers.

The definition dodge didn’t work either.

Definition: a list of dpointers (called L) is one-count-ish if the number of entries in L is 1.

Exampling a one-count-ish list of dpointers:
    rule succeeds with result "!".

gets the same no efficient way to tell during play whether the list actually contains that as the first.

(Same results without the parens around list of dpointers; I added them to rule that out.)

One can do this:

Bogus is a kind of object. Bogus has a list of numbers called bogus list.
Example2ing is a bogus based rulebook producing a text.

Example2ing a bogus (called B) when the number of entries in the bogus list of B is 1 (this is the gnarly rule):
    rule succeeds with result "-".

Example2ing a bogus (called B) when the number of entries in the bogus list of B >= 5 and entry 1 in the bogus list of B is 3 and entry 5 in the bogus list of B is 7:
    rule succeeds with result "you sunk my battleship".

… but is there a way I’m missing to specify rules for a directly list-based rulebook in a way that I7 will accept?

Does it work with lists of numbers?

I don’t think so. I ran into this some time ago. I was trying to create a rulebook which takes multiple arguments and figured I could “cheat” using lists. It seems like it would be possible since action rules can have two arguments (three if you count the actor) but those actually work using global variables. You could do the same (which is sort of like what you did with the bogus object) but you don’t need the rulebook to be based on anything. Something like this might be a little klunkier than you wanted, but:

Lab is a room. 

Dpointer is a kind of value. The dpointers are d1, d2, d3, d4.

Current dpointer is a list of dpointers that varies.

Exampling is a rulebook producing some text.

Exampling when the number of entries in current dpointer is less than three (this is the not enough rule):
	rule succeeds with result "Not enough coordinates, mate.".
	
Exampling when current dpointer is {d1, d2, d3} (this is the you win rule):
	rule succeeds with result "You sank my battleship!".

Instead of waiting:
	now current dpointer is {d1};
	let output be the text produced by the exampling rules;
	say "[output][line break]".
		
Instead of jumping:
	now current dpointer is {d1, d2, d3};
	let output be the text produced by the exampling rules;
	say "[output][line break]".
	
test me with "z / jump".

You could also use phrases which can take multiple arguments. It really just depends on how many special situations you need to account for.

2 Likes

I have a specific case of needing to make lots of different decisions based on specific combinations of different numbers of eight different things in a way that doesn’t lend itself to any algorithmic approach other than lots o’ conditionals. If something like Exampling { d1, d2, d3 } were possible, it would be a nice way to express it (the lists can always be assumed to be ordered given how they’re generated).

(The bogus object workaround thus becomes an uglier and more cumbersome way to express it than lots o’ conditionals in a phrase, but once it seemed impossible to do it directly, I wondered if the workaround would… y’know, work around.)

One nice thing to come of this list-fiddling, though – I realized that this is possible:

To decide what K is (L - a list of values of kind K) -> (N - a number):
    decide on entry N in L.

Saying something as straightforward as L -> 3 feels really good.

(I imagine it might be possible to have an unfortunate conflict with I7’s existing -> if one were using a phrase variable. But if you’re doing that, you don’t need me telling you anything. :grinning: )

1 Like

Literate programming style? Wot be datt? :wink:

1 Like

As I suspect you’re aware, any number of alternate succint notations also work, e.g.:

L # 3
L @ 3
L >> 3

etc.

there’s no efficient way to tell during play whether the list actually contains that, without laboriously checking every entry

I don’t understand this complaint, since in Inform 7 a list can only have entries of one given kind. So a list of dpointers is a list of dpointers- it can’t contain anything else, no need to laboriously check every entry… Particularly when it’s a constant list :wink:. Furthermore, the number of entries can I think be calculated without counting through each entry in the list…

EDIT: perhaps the concern is the need to check that the elements in the list do match the specific elements given in the rule declaration, which would be necessary to check that these match the rule declaration if these need to be fixed constant values rather than simply being variables passed as arguments to the rule, and which might be a laborious task in deciding which of various similar rules with long lists in their declarations to invoke …? But seems unlikely that anyone would write multiple declarations each containing hundreds of different constant elements in a list…

That is a strange error message.

Here’s an example of cajoling the compiler into accepting something that is approximately as easy to type as you wanted it to be. The burden would be on you to make sure that that the ordering of list elements is appropriate; I couldn’t figure out a way to convince the compiler to allow sorting parameter_object as a list of colors.

EDIT: OK, I got sorting working. So long as the same unordered list membership is present at both the “submission” (i.e. follow... ) end and the “setup” (i.e. Color checking...) end, it should work. No promises on performance, though.

"Exampling Lists"

Place is a room.

Color is a kind of value. The colors are red, orange, yellow, green, blue and purple.

The color checking rules are a list of colors based rulebook producing text.

Include (- Global color_sort_list; -) after "Definitions.i6t".

To decide whether submitted colors are (L - list of colors): [allows approximation of normal rule syntax]
    (- ( color_sort_list = {L}, LIST_OF_TY_Sort(color_sort_list, 1), LIST_OF_TY_Sort(parameter_value, 1), BlkValueCompare(parameter_value, color_sort_list) == 0) -).

Color checking when submitted colors are {red, orange, yellow}:
    rule succeeds with result "Warm in a row."

Color checking when submitted colors are {purple, green, blue}: [notice unsorted list]
    rule succeeds with result "Cool in a row."

Color checking when submitted colors are {red, orange, yellow, green, blue, purple}:
    rule succeeds with result "Full spectrum."

To say with break (T - text): [simplifies formatting for saying a text produced from a constant list of colors]
    say T;
    say paragraph break.

After waving hands:
    say with break text produced by the color checking rules for {red, orange, yellow}.

After jumping:
    say with break text produced by the color checking rules for {purple, blue, green}. [notice unsorted list]

After waiting:
    say with break text produced by the color checking rules for {red, orange, yellow, green, blue, purple}.

Test me with "wave / jump / wait".

Submitting a list of colors that varies should be OK, too.

Color checking when submitted colors are mycolorlist:
    ...
2 Likes

That’s pretty slick, @otistdog.

I’d be lying if said I hadn’t thought about writing a pre-processor that facilitated writing codier code that would be compiled to Inform 7 (what this tech stack really needs is more layers.)

2 Likes

Let’s take it as given that this is a terrible idea. tl;dr, this works in the way one might expect:

H is a hash variable.

Last when play begins:
    now H is new hash;
    H => "Q" = "Z";
    say H => "Q";
    H => "Q" = "A";
    say H => "Q";

The ridiculous gory details to make a game output “ZA”.:

Previous massively overcomplicated version
Use MAX_STATIC_DATA of 99999999.

hash-source is a list of lists of texts that varies. hash-source is initially {{""},{""},{""},{""},{""},{""},{""},{""}};

A hash is a kind of object. A hash has a list of texts called the hkeys.
A hash-val is a kind of object. A hash-val has a list of texts called the hvalues.

There are 10 hashes. There are 10 hash-vals.

Unused hashes are a list of hashes that varies.
Unused hash-vals are a list of hash-vals that varies.

Hashage relates one hash to one hash-vals.

Error-hash is a hash.

To enhashenate is a verb implying the hashage relation.

To decide what hash is the new hash:
if unused hashes is empty, decide on error-hash;
let new-h be entry 1 in unused hashes;
remove entry 1 from unused hashes;
now the hkeys of new-h is entry 1 in hash-source;
remove entry 1 from hash-source;
let hvals be entry 1 in unused hash-vals;
remove entry 1 from unused hash-vals;
now the hvalues of hvals is entry 1 in hash-source;
remove entry 1 from hash-source;
now new-h enhashenates hvals;
decide on new-h.

To (h - a hash) => (v - a text) = (T - a text):
let h-index be 0;
let local-keys be the hkeys of h;
let hlen be the number of entries in local-keys;
repeat with i running from 1 to hlen begin;
if entry i in local-keys is v begin;
now h-index is i;
break;
end if;
end repeat;
let local-hvals be the hash-val that h relates to by the hashage relation;
if h-index is 0 begin;
now h-index is hlen plus 1;
extend the hkeys of h to h-index entries;
extend the hvalues of local-hvals to h-index entries;
end if;
now entry h-index in the hkeys of h is v;
now entry h-index in the hvalues of local-hvals is T.

To decide what text is the (h - a hash) => (v - a text):
let local-hvals be the hash-val that h relates to by the hashage relation;
let h-index be 0;
repeat with i running from 1 to the number of entries in the hkeys of h begin;
if entry i in the hkeys of h is v begin;
now h-index is i;
break;
end if;
end repeat;
if h-index is 0, decide on “__error”;
let local-hvals be the hash-val that h relates to by the hashage relation;
decide on entry h-index in the hvalues of local-hvals;

first when play begins:
now Unused hash-vals is the list of hash-vals;
now Unused hashes is the list of hashes;

Edited: wow, over-complicated that one. Let’s try that with the complication right-sized:

A hash is a kind of object.
A hash has a list of texts called the hkeys.
A hash has a list of texts called the hvalues.

An object can be error-object. An object is seldom error-object.
Error-hash is a hash.
Definition: An object is non-object-erroneous if it is not error-object.

Unused hashes is a list of hashes variable.

There are 10 hashes.

To decide what hash is the/a/-- new hash:
    if unused hashes is empty, decide on error-hash;
    let h be entry 1 of unused hashes;
    remove entry 1 from unused hashes;
    decide on h;

To (h - a hash) => (v - a text) = (T - a text):
    let h-index be 0;
    let hlen be the number of entries in the hkeys of h;
    repeat with i running from 1 to hlen begin;
      if v is (entry i of hkeys of h) begin;
        now h-index is i;
        break;
      end if;
    end repeat;
    if h-index is 0 begin;
      now h-index is hlen plus 1;
      extend the hkeys of h to h-index entries;
      extend the hvalues of h to h-index entries;
    end if;
    now entry h-index in the hkeys of h is v;
now entry h-index in the hvalues of h is T.

To decide what text is the (h - a hash) => (v - a text):
  let h-index be 0;
  repeat with i running from 1 to the number of entries in the hkeys of h begin;
    if entry i in the hkeys of h is v begin;
      now h-index is i;
      break;
    end if;
  end repeat;
  if h-index is 0, decide on "__error";
  decide on entry h-index in the hvalues of h;

When play begins:
    now unused hashes is the list of non-object-erroneous hashes;
    let H be new hash;
    H => "Q" = "Z";
    say H => "Q";
    H => "Q" = "A";
    say H => "Q";
1 Like