Tables and Kinds

Here is an example game:

[code]“Test” by Victor Gijsbers

Church is a room. A fruit is a kind of thing. An apple is a kind of fruit. In church is one apple.

Table of Fruit Prices
fruit price
apple 5

Instead of examining a fruit:
let m be 0;
repeat through the Table of Fruit Prices:
if the noun is a fruit entry:
now m is the price entry;
say “That costs [m] dollars. You must be in Manhattan.”.[/code]
The intent of the code is probably obvious: I want to have a table with kinds and numbers, and I want to be able to look up, for any object, what number belongs to its kinds. (In this example game, this could also be done with “A fruit has a number called the price. The price of an apple is usually 5.”. But since I want to set the prices at random at the beginning of the game, this is not a possibility for me.)

This code compiles but doesn’t work, and I’m thinking that the underlying problem is probably that I do not know a way to refer to the kind of something. Is there a way to check whether X is a thing of kind Y? Or does anyone know another way to get the effect I intend?

However, the reason Inform 7 gives me when the game throws an error (after “examine apple”) is the mysterious:

Mysterious because I don’t see how the entry at (1,1) could be non-existent. I am repeating through a table which has no blank entries, so there should never be a non-existent entry. Is my table being emptied for some reason, or is this a bug in Inform?

I found a workaround. I don’t think it’s too arduous. Basically, you give each type of fruit an id number, and refer to them that way in a price list.

[code]“Test” by Victor Gijsbers

Church is a room. A fruit is a kind of thing. An apple is a kind of fruit. A banana is a kind of fruit. In church is one apple and three bananas.

A fruit has a number called id.
id of apple is 1.
id of banana is 2.

Table of Prices
produce numero price
apple 1 10
banana 2 20

Instead of examining a fruit:
choose a row with numero of id of noun in Table of Prices;
say “That costs [price entry] dollars. You must be in Manhattan.”

test me with “x apple / x banana”. [/code]

The first thing I tried to do with your original code was convert the fruit’s name into text, then match it against a table of text items. But this never worked. It drove me mad trying to work out why not and I gave up!

Look at these 2 examples. In the first one, I store the apple’s name as text in textmatch. I then add a letter ‘g’ to the front of the text (to prove Inform still isn’t being thrown in any way by the fact we’re talking about something which is a kind we have defined…) and try to match it to the word ‘gapple’ in the table. It doesn’t match, so it doesn’t say “That costs mucho dolllars.”

In the 2nd example, I simply set textmatch to “gapple” when it goes to look for a match. It succeeds.

In both cases, I print the contenst of ‘textmatch’ with hyphens around it to show there are no weird gaps or trailing or leading characters at either end of the word that could screw up the match. So I cannot work out why my example 1 doesn’t work.

Example 1:

[code]“Test” by Victor Gijsbers

Church is a room. A fruit is a kind of thing. An apple is a kind of fruit. In church is one apple. torch is in church.

textmatch is a text variable.

Table of Prices
texty price
“gapple” 5
“Sam” 10
“gtorch” 7

Before examining:
now textmatch is “g[printed name of noun]”;
say “–[textmatch]–”;
if textmatch is a texty listed in Table of Prices:
say “That costs mucho dollars. You must be in Manhattan.”[/code]

Example 2:

[code]“Test” by Victor Gijsbers

Church is a room. A fruit is a kind of thing. An apple is a kind of fruit. In church is one apple. torch is in church.

textmatch is a text variable.

Table of Prices
texty price
“gapple” 5
“Sam” 10
“gtorch” 7

Before examining:
now textmatch is “g[printed name of noun]”;
now textmatch is “gapple”;
say “–[textmatch]–”;
if textmatch is a texty listed in Table of Prices:
say “That costs mucho dollars. You must be in Manhattan.”[/code]

This is a bug, and I’m sure it’s because “apple” is a kind name as well as an object name. If you replace “apple” with “thing” or “person” in the table, you get the same result – it compiles, but the entry is blank.

Filed: inform7.com/mantis/view.php?id=690

You can work around this by filling in the table entry at runtime, being careful to refer to the correct apple.


One apple is in the Kitchen.

A iigs is an apple.

Table of Fruit Prices
fruit	price
--	1
iigs	2

When play begins:
	let T be a random apple in the Kitchen;
	now the fruit in row 1 of the Table of Fruit Prices is T.

Instead of jumping:
	repeat through the Table of Fruit Prices:
		let F be the fruit entry;
		let G be the price entry;
		say "### [F] [G].";

Note that I had to select the apple by description. If I write “now the fruit in row 1 of the Table of Fruit Prices is the apple”, I7 thinks I’m talking about the kind again.

Ah, that’s neat. I’m gonna add that to my text file of neat stuff.

Thanks for the help, guys.

Right, but I want Inform to put kinds in that table, not individual objects (but I don’t think this is possible). I don’t want to set the price of an apple, but the prices for all apples; and I want to set it randomly at the start of the game; and I don’t want to go through all the kinds of fruit by hand. It’s that triple set of conditions that I’m having trouble satisfying. If I didn’t want to do it randomly, I could use “The price of an apple is always 5.”. If I didn’t mind adding all the kinds of fruit by hand, I could write a loop and test for each kind of fruit individually (“repeat with item running through fruit; if item is an apple: now the price of item is randomly-determined-number-1; if item is a banana: …”).

Maybe I can work something out with printed names, as severhand suggested… I’ll let you know. Or maybe I just need to rethink the design from the ground up.

(If you wonder what I need these three conditions for: not the toy example of fruit prices, but roguelike item identification. So on the one hand I have things like “scroll of teleportation”, “scroll of ghoulification”, on the other hand I have things like “scroll labelled MORT EILYSH”, “scroll labelled NAAR OD ERAE”. These kinds need to be paired randomly at the beginning of the game, and reading an instance of a kind of unidentified scrolls then needs to result in it being switched for whatever kind of identified scroll it was paired with. Having separate objects for the identified and the unidentified scrolls seemed like a good idea at the time, because it meant I wouldn’t have to worry about the “scroll labelled MORT EILYSH” listening to “drop scroll of teleportation”.

I would love to be able to repeat through kinds, as in “repeat with X running through kinds of scroll: repeat with Y running through things of kind X: …”.)

Severedhand, I think your problem with printed names is caused by the bug, reported by zarf in december: http://inform7.com/mantis/view.php?id=459.

You can circumvent it by explicitly declaring a printed name:

[code]“Test” by Victor Gijsbers

Test chamber is a room.

An apple is a thing in test chamber. The printed name of the apple is “apple”.

Check taking:
if printed name of the noun is “apple”:
say “That certainly is an apple.”.
[/code]

Is it possible to hack this using the printed plural name property? I was trying to think of something that exposes the most specific kind of an item, and I can’t find any way of doing it directly (maybe someone knows this, I think it may be in the forum somewhere), but “printed plural name” seems like it does, as long as you don’t do other stuff to mess with the printed plural name – or don’t do it until you’ve done your startup stuff. So here’s a fruit code:

[code]Fruit is a kind of thing. apple is a kind of fruit. pear is a kind of fruit. A fruit is usually edible. A fruit has a number called a price. The price of a fruit is usually 0.

Grocery is a room. There are three apples in grocery. There are two pears in grocery.

Instead of examining a fruit:
say “This [noun] costs [price of the noun] dollars.”

Duplication relates a thing (called X) to a thing (called Y) when the printed plural name of X is the printed plural name of Y. The verb to duplicate (he duplicates, it is duplicated, they duplicate, it is duplicating) implies the duplication relation.
Definition: A fruit is price-set if its price is not 0.

To decide whether (X - a fruit) is price-kind-set:
repeat with item running through fruits that duplicate X:
if the price of item is not 0, decide yes;
decide no.

When play begins:
repeat with item running through fruits:
if item is price-kind-set:
let old item be a random price-set fruit that duplicates item;
now the price of item is the price of old item;
otherwise:
now the price of item is a random number from 2 to 5. [/code]

This seems to be working right now. I’m pretty groggy, so it’s probably very inelegant if it’s not bugfree. (Highlights of my attempts to get this to compile: thinking there was something going on with the syntax “a random price-set fruit that duplicates item” when I had omitted “let” from the beginning of the line; trying to use A as a variable; writing “plural name” property and thinking that there was some deep magic in trying to access that property, instead of realizing that I’d got the name wrong; and sundry other stupid bugs.)

UPDATE: In fact, my grogginess led me to complicate that unnecessarily – you don’t need the business about “price-kind-set.” This seems to work:

[code]Duplication relates a thing (called X) to a thing (called Y) when the printed plural name of X is the printed plural name of Y. The verb to duplicate (he duplicates, it is duplicated, they duplicate, it is duplicating) implies the duplication relation.
Definition: A fruit is price-set if its price is not 0.

When play begins:
repeat with item running through fruits:
if item duplicates a price-set fruit:
let old item be a random price-set fruit that duplicates item;
now the price of item is the price of old item;
otherwise:
now the price of item is a random number from 2 to 5.[/code]

I had thought that “price-set fruit that duplicates item” was making the compiler burp, when it was the missing “let” at the beginning of the line; by the time I’d fixed that I’d created a lot of extra complication. :blush:

Matt, that’s pretty neat. I hacked something ugly together, but your idea of using a relation may make it a lot neater. (Though only kind-variables would make it truly neat.)

I think you can do what you want with a little I6:[spoiler][code]Chapter “Object Types” (for Glulx only)
[Glulx only because the code uses @linearsearch and depends on the instruction layout of Prop_* routines.]

Include (-
! This is the hackiest bit.
[ convertPropRoutineToClass routine result;
@linearsearch OC__Cl 4 routine 1 (-1) 0 0 result;
return (result+5)–>0;
];
-) after “Definitions.i6t”.

An object type is a kind of value.
To decide what object type is the (K - a description of a value of kind K) type: (- convertPropRoutineToClass({K}) -).
To decide what object type is the type of (O - an object): (- ({O}.2) -).
To repeat with (I - a nonexisting object type variable) running through object types begin – end: (- for({I}=K0_kind–>6:{I}:{I}={I}–>6) -).
To decide whether (O - an object) is of type (T - an object type): (- ({O} ofclass {T}) -).
To decide whether (O - an object) is of type (K - a description of a value of kind K):
decide on whether or not O is of type the K type.
To say (T - an object type): (- print (I7_Kind_Name){T}; -).

Chapter “Demo”

There is a room.
When play begins:
say “Thing: [the thing type].”;
say “Player: [the type of the player].”;
showme whether or not the player is of type thing;
showme whether or not the player is of type person;
showme whether or not the player is of type device;
repeat with type running through object types:
say “A type: [the type].”
[/code][/spoiler]
Understand, of course, that this is just a hack.

I took a shot at an implementation of nethack magic items. It involved a level of dynamism that I don’t think played to Inform’s strengths.

[spoiler][code]
“rogue” by “Zed Lopez”.

Include Dynamic Objects by Jesse McGrew.

A thing can be either actual or prototypical. A thing is usually actual.

After cloning a new object from a thing:
now new object is actual.

A magic-effect-value is a kind of value. Some magic-effect-values are defined by the Table of Magic Effects.

Table of Magic Effects
magic-effect-value
scroll-teleportation
scroll-identify
scroll-confuse-monster
scroll-punishment
scroll-amnesia
wand-wishing
wand-striking
no-effect

Having-knowledge-of relates one person to various magic-effect-values. The verb to have-knowledge-of (it has-knowledge-of, they have-knowledge-of, it had-knowledge-of, it was-known, it is having-knowledge-of) implies the having-knowledge-of relation.

A magic-item is a kind of thing. A magic-item is usually prototypical. A magic-item has a magic-effect-value called magic-effect. A magic-item has a truth state called true-name. A magic-item is usually improper-named.

Having-magic-effect relates a magic-item (called item) to a magic-effect-value (called effect) when effect is the magic-effect of item. The verb to have-magic-effect (it has-magic-effect, they have-magic-effect, it had-magic-effect, it was magic-effect-had-by, it is having-magic-effect) implies the having-magic-effect relation.

Definition: a magic-item (called item) is plain rather than obfuscated if the true-name of item is true.

A scroll is a kind of magic-item. Some scrolls are defined by the Table of Magic Scrolls.

Table of Magic Scrolls
scroll magic-effect true-name
scroll of teleportation scroll-teleportation true
scroll of identify scroll-identify true
scroll of confuse monster scroll-confuse-monster true
scroll of punishment scroll-punishment true
scroll of amnesia scroll-amnesia true
scroll of DAUM SKNAHT no-effect false
scroll of FOO no-effect false
scroll of PLUGH no-effect false
scroll of XYZZY no-effect false
scroll of BTON no-effect false

Reading is an action applying to one thing.
Understand the command “read” as something new.
Understand “read [something]” as reading.
Check reading something when noun is not a scroll:
say “You can’t read that” instead.

To magic-effect-identify (effect - a magic-effect-value):
let realitem be a random prototypical plain magic-item which has-magic-effect effect;
now player has-knowledge-of effect;
repeat with item running through every actual on-stage obfuscated magic-item which has-magic-effect effect begin;
let itemholder be holder of item;
let newobject be a new object cloned from realitem;
remove item from play;
now newobject is in itemholder;
end repeat;

To magic-effect-amnesia:
repeat with effect running through magic-effect-values begin;
if player has-knowledge-of effect begin;
let obfuscateditem be a random prototypical obfuscated magic-item which has-magic-effect effect;
now player does not have-knowledge-of effect;
repeat with item running through every actual plain on-stage magic-item which has-magic-effect effect begin;
let itemholder be holder of item;
let newobject be a new object cloned from obfuscateditem;
remove item from play;
now newobject is in itemholder;
end repeat;
end if;
end repeat;

Carry out reading something (called thescroll):
Let effect be magic-effect of thescroll;
Remove thescroll from play;
if player does not have-knowledge-of effect:
magic-effect-identify effect;
if magic-effect of thescroll is:
– scroll-teleportation: say "There’s nowhere to teleport to. ";
– scroll-confuse-monster: say "There are no monsters to confuse. ";
– scroll-punishment: say "You are being punished. ";
– scroll-identify:
repeat with eachitem running through visible obfuscated magic-items:
let effect be the magic-effect of eachitem;
magic-effect-identify effect;
say "You feel knowledgeable. ";
– scroll-amnesia:
magic-effect-amnesia;
say “Thinking of Maud, you forget all else.”.

Report reading something:
say “The scroll crumbles to dust.”

When play begins:
Let l be a list of magic-effect-values;
repeat with eachscroll running through every plain scroll begin;
add magic-effect of eachscroll to l;
end repeat;
sort l in random order;
let i be 1;
repeat with eachscroll running through every obfuscated scroll begin;
now magic-effect of eachscroll is entry i of l;
increase i by 1;
end repeat;
repeat with item running through prototypical obfuscated magic-items begin;
Let newitem be a new object cloned from item;
now newitem is in the Dungeons of Doom;
end repeat;
magic-effect-identify scroll-identify;

The Dungeons of Doom is a room.
[/code][/spoiler]

Here’s a transcript.

[spoiler]Dungeons of Doom
You can see scroll of identify, scroll of BTON, scroll of PLUGH, scroll of FOO
and scroll of DAUM SKNAHT here.

get all
scroll of identify: Taken.
scroll of BTON: Taken.
scroll of PLUGH: Taken.
scroll of FOO: Taken.
scroll of DAUM SKNAHT: Taken.

drop teleportation
You can’t see any such thing.

read identify
You feel knowledgeable.
The scroll crumbles to dust.

i
You are carrying:
scroll of confuse monster
scroll of amnesia
scroll of punishment
scroll of teleportation

l
Dungeons of Doom

drop foo
You can’t see any such thing.

read amnesia
Thinking of Maud, you forget all else.

The scroll crumbles to dust.

l
Dungeons of Doom

i
You are carrying:
scroll of FOO
scroll of BTON
scroll of DAUM SKNAHT

drop foo
Dropped.

[/spoiler]

I implemented the scroll of identify as something like a super-blessed Nethack scroll, identifying everything in the location, and amnesia as forgetting all the identifications (though I don’t recall that you ever really forget identifications in Nethack, or, I presume, Rogue.)

There are still difficulties to surmount – the wand of wishing would need to admit even unidentified things to scope.

Oh, you do. Never read an unidentified 200zm scroll (unless you’re going to die the next turn and your only hope of escape is lucking onto a taming scroll, in which case, don’t find yourself in that position).

Zed, that is fantastic. I had my identification working, but I was using some of the ugliest code known to man (or any other species). I am certainly going to replace it with an adaptation of your code.

[Edit: sorry, I read “zarf” instead of “zed”.]

Being mistaken for zarf on intfiction.org is probably the best thing that’ll happen all day. :smiley:

I don’t have much faith that the implementation above wouldn’t have its memory usage spiral out of control if you’re creating bunches of items. An obvious small optimization occurred to me – before cloning a new object, check to see if there’s an appropriate existing one lying around off-stage and recycle it.

And if you add properties to the items, for instance, adding blessed/cursed/neutral or letting the player name them, you’d have to transfer all the traits appropriately when you exchange plain for obfuscated or vice versa.

Hm, you just uncovered a huge bug in my game (both with my previous code, and with your code that I have been adapting). You can stop a scroll from burning by identifying it. Heh.

I think the only interesting property that a scroll can have right now is that it can be burning, but I have think about this more carefully. Thanks.

I have some clunky code that needs looking at, but right now, before cloning, I have a look at a separate room called Limbo to see if there’s an item of the appropriate type there. If so, it picks it up, wipes it clean of various properties and relations, pretends like it’s a new item, and voila. Limbo is better than off-stage, since it absolutely ensures I can’t pick a prototype, or mess with something that’s off-stage for other reasons but might make a return, and provides me with easy testing feedback as to the numbers of “extra” items lying around at any given time.