Bubbling Beaker Awards (Award #19, Feb 23 2024)

This week’s prize, Bubbling Beaker Award® #18 is presented to @matt_weiner, who has not visited the forum for quite a while but seems to have had the mad scientist spirit in spades. His award-winning post (which doesn’t use I6) demonstrates a method for establishing mutually-exclusive sets of relations, in an example concerning attitudes between people ranging from loving to hating.

The interesting part of this approach is that it is another way of approximating trinary relations. It’s similar in setup and usage to how I7 handles the relationship between origin room, destination room and direction via the various mapping <direction> relations, and similar in function to I7’s special handling of the various mutually-exclusive “spatial” relations (containment, support, carrying, etc.). When any one type of relation is set between two people using the provided set the feeling... phrase, any other type of relation between the two people is cleared.

4 Likes

I’d be inclined to go with:

Attitude is a kind of value. Attitudes are indifference, hate, dislike, like, love.

A person has a relation of person to attitude called the disposition.

To decide what attitude is the feeling of a/an/-- (p - person) toward/towards a/an/-- (q - person):
  if q relates to an attitude by the disposition of p, decide on the attitude that q relates to by the disposition of p;
  else decide on indifference.

To set the feeling of a/an/-- (p - person) toward/towards a/an/-- (q - person) to a/an/-- (att - attitude):
  now the disposition of p relates q to att.

Lab is a room. Alice is a person. Bob is a person.

when play begins:
  set the feeling of alice toward bob to love;
  set the feeling of bob toward alice to like;
  set the feeling of player toward bob to dislike;
  repeat with p running through people begin;
    repeat with q running through people who are not p begin;
      say "[p] feels [feeling of p toward q] toward [q].";
    end repeat;
  end repeat;

But, then, I would say that, wouldn’t I.

1 Like

I’m ashamed to say that I’ve only just had a proper look at this award, and think it deserves a little more explanation. The fundamental problem to be solved is another facet of an issue that was the basis of a recent post discussion and Bubbling Beaker award #1- the constraints on the kinds of property Inform currently allows things to be ‘Understood’ by. (see Writing with Inform §17.15. Understanding things by their properties)

When understanding something by one of its properties, Inform permits that property to be one of a limited variety of kinds (although much less limited than suggested by the compiler error generated by trying to stray beyond this list):

either/or property (e.g. a thing can be broken or unbroken)
truth state (e.g. a secret door has a truth state called password-guessed)
enumerated kind of value (e.g. Colour is a kind of value. Some colours are red, green, blue. A thing has a colour called hue)
scene (e.g. A thing has a scene called prop-requirement)
command parser error (e.g. A thing has a command parser error called error-type.)

number (e.g. a treasure has a number called points-value)
time of day (e.g. an animal has a time of day called feeding-time)
real number (e.g. a thing has a real number called calculated-value)
unit (e.g. A weight is a kind of value. 10kg specifies a weight. A thing has a weight called encumbrance.)

text (e.g. A thing has a text called abbreviated-name)

figure name
sound name
external file

natural language
narrative viewpoint
grammatical tense
grammatical case
grammatical gender

are permitted kinds, but not

topic
snippet
unicode character
rulebook
rulebook outcome
action
action name
response
verb
table name
equation name
list of …
phrase …

object or subkind of object (e.g. thing)

In the Kinds Chart of the Index, this almost corresponds to the kinds which can appear in Understand tokens (e.g. “[colour]”) with the exceptions that:

(i) the Understand token “[text]” refers to a topic, not a text, and whereas topic properties cannot be understood as their objects, text properties can
(ii) subkinds of object can appear in Understand tokens such as “[person]” but properties holding subkinds of object cannot be understood as their objects

The challenge laid down was for an object to be understood by a property of one of its properties. The specific context was the wish to concisely define a list of material types (iron, wood etc.) in a table alongside properties of those material types- e.g.

A material is a kind of thing.
The materials are defined by the Table of Material-characteristics.

Table of Material-characteristics
material	material-adjective	destroying heat	heat-behaviour	corrosion resistance
iron	    “iron”	            10	            melter	        995
wood     	“wooden”          	3	            burner         	970
adamant 	“adamantine”	    999	            melter          1000

after which, there would be three objects of material kind called iron, wood and admanant and for example the material wood would have the material-adjective property “wooden” (a text property).

The idea was then to have:

A thing has a material called essence. Understand "thing/object" as a thing.
A staff is here. The essence of the staff is wood.
A rod is here. The essence of the rod is wood.
A sword is here. The essence of the sword is iron.

The author wanted the player to be able to type “take every wooden thing” in order to pick up just the nearby things made of wood, using the material-adjective property as laid out in the table- i.e. the material-adjective property of the essence property. e.g.

Understand the material-adjective property as describing a material. [so that "wooden" describes the wood object]
Understand the essence property as describing a thing. [so that, for example, the wood object in turn describes a thing holding a wood object in its essence property]

Now, here’s the snag. As noted above, a thing cannot in the ordinary way of things be understood by a property that itself holds a subkind of object (in this case an object of material kind). So the second Understand phrase won’t compile, being spat out with the following complaint:

You wrote ‘Understand the essence property as describing a thing’ : but the value of that property is itself a kind of object, so that it cannot be understand as describing or referring to something.

We could make materials an enumerated kind of value rather than a kind of thing (A material is a kind of value. The materials are defined by by the Table of Material-characteristics.), in which case the second Understand phrase will compile fine (as noted above, properties holding enumerated values are fine to be understood as their objects) but now the first won’t compile, since only objects can be understood by their properties- and now materials are no longer a kind of object, but a kind of value.

The award-winning solution is to make the essence property understood as its object not by the usual (disallowed)Understand the ... property as describing a ... method, but by the Understand "[something related by ...]" as a ... method. ( see Writing with Inform §17.16. Understanding things by their relations)

For this to work, it’s necessary to set up a simple ‘conditional’ relation between a thing and whatever object is in its essence property (see Writing with Inform §13.12. Relations which express conditions):

Constitution relates a thing (called the item) to a material (called the constituent) when the essence of the item is the constituent.

and now:

Understand "[something related by constitution]" as a thing.

(where [something related by constitution] now means ‘whatever object is held in a given thing’s essence property’)
and so overall this means the parser can now recognise a given thing by any word(s) by which it can recognise the object in that given thing’s essence property, which will include the name(s) of that object (e.g. ‘wood’) but also any properties describing it (e.g. “wooden”).

So, essentially the solution is a neat workaround for Inform’s refusal to allow an object/object kind property to describe its object.

Unfortunately this particularly neat trick doesn’t allow a similar workaround for the other varieties of property listed above that are presently disallowed from describing their objects, because at present Inform only allows relations between kinds of object to appear in Understand phrases.

3 Likes

It’s not too hard to extend the technique to any sayable value.

Lab is a room.

an action-nom is a kind of object.
an action-nom has an action name called the action-name.
an action-nom has a text called description.
The description of an action-nom is usually "[actionless action of the action-name of the item described]".
Understand the description property as describing an action-nom.

to say actionless action of/for (ac - action name):
  let t be "[ac]";
  replace the text " action$" in t with "";
  say t;

Jumping-obj is an action-nom with action-name jumping action.

describing is an action applying to one visible thing.
understand "describe [any action-nom]" as describing.
report describing: say the action-name of the noun; say " action".

Proxying relates one thing to one action-nom.
the verb to proxy means the proxying relation.
the jumprope proxies jumping-obj.
the jumprope is in the lab.
understand "[something related by proxying]" as a thing.

test me with "describe jumping / get jumping / i".
3 Likes

This week’s prize, Bubbling Beaker Award® #19 is presented to @drpeterbatesuk. Continuing his efforts to get better use out of the text matching functionality of topics, he shows how to fool the compiler into accepting the logical equivalent of a variable holding a topic, which makes it easy to change out the topic used in a particular comparison. (This technique is vaguely similar to his invention from award #1, but the details of the use case look significantly different to me, and the implementation is more readily understood by the budding mad scientist.)

This marks the good doctor’s fourth BBA. Congratulations! In recognition of this achievement, I’ve added a leaderboard to the top post.

2 Likes

But this is an exhibition, not a competition: please, no wagering.

3 Likes

If I have seen further, it is by standing on the shoulders of giants.

                                  Isaac Newton 1675

Wow, well I feel a bit of a fraud with this one- because if ever there was a case of standing on the shoulders of giants, this was it.

The unlikely background to this minor advance was a simple enquiry as to why the following:

if the player's command is "[Password]":
...

(where Password is a text variable)
doesn’t work.

This led to a whole cascade of stuff mostly outside the original thread-

  1. the incidentally-noted fact that a (supposedly) random choice from 4 alternative passwords turned out to be very much NOT random- caused by a glitch with the Glulxe random number generator that I had noted previously but shelved looking into in detail, which led to…
  2. a very long post with multiple distinguished contributors culminating in revision of the Glulxe and Git random number generators…
  3. and which itself led to my stumbling on a very sneaky means to smuggle raw I6 code into the final compiled output of I7 when using Version 10- the subject of Bubbling Beaker Award #7

all of which is a perfect illustration of how even the simplest of enquiries on this forum can lead to a whole heap of good stuff of interest and value to even the most experienced denizens and contributors.

A few words now- after that preamble- on this fortnight’s award.

First to recap some basics. I7 has a closely-patrolled typing system whereby if a phrase expects, for example, a text, Inform complains and refuses to proceed if you try to feed it instead with something different, say a number. I7 however compiles to I6, a much more primitive language, which has only a rudimentary typing system and one that is not enforced. Fundamentally, to I6, entities of any of I7’s types are just integer numbers, which is how they are represented in I6.

So a text is represented by an integer number. A phrase is represented by an integer number. A snippet is represented by an integer number. And, relevant to the present issue, a topic is represented by an integer number.

How these various numbers are interpreted by I6 varies from type to type.

An I7 text is represented by a number which is a memory address where data is stored describing exactly what flavour of text this is and from that, both where and how to retrieve and assemble the sequence of characters which ultimately make up the text.

An I7 snippet is represented by an integer number which simply encodes the starting position and length of a sequence of words in the player’s command.

A topic is represented by an integer number which is the memory address of a routine. Specifically, for a topic this routine will be something called a General Parsing Routine which, on a basic level, tries to match certain dictionary words against the contents of a given snippet.

In I7, the boundaries between types (or kinds, as I7 likes to term them) are largely defended- with few exceptions you usually can’t try to turn something of one type into another (a process known as casting) without Inform complaining. But because I7 allows you to link an I7 entity such as a text to an I6 equivalent value- which will always be an integer number- and vice versa, it is possible via I6 to persuade I7 to cast between types (or kinds). To do this we simply find the integer number in I6 which represents the I7 entity of kind J we are casting from, then reverse the process to find what I7 entity of kind K that I6 integer number would be.

Long ago @Zed wrote a simple line of code which neatly performs this magic for any I7 entity and kind, which I shamelessly stole:

To decide which K is (v - a value) as a/an/-- (name of kind of value K): (- {v} -).

It’s easier to see how this works if we write a similar ‘To… phrase’ with a kind and a value explicitly stated:

To decide which number is the player's command as a number: (- (+ the player's command +) -).

which clearly means ‘decide on whichever number is the I7 number equivalent to the I6 representation of the player’s command’. (the I6 representation of the I7 snippet variable ‘the player’s command’ being an integer encoding, specifically 100 + the number of words in the command).

Now we can, for example, find the memory address (an integer number) where the metadata for an I7 text is stored by SomeText as a number or the integer number which encodes the player’s command (a snippet) by the player's command as a number. Casting by this method is often not very useful, because the I6 representation of one I7 kind as a number makes no sense as a representation of a different I7 kind. For example, casting a snippet to a text by this method won’t work, because the number encoding a snippet is not a memory address for text metadata, which is the meaning of an I6 number representing an I7 text- and this is why I7 normally steps in to prevent us trying to do something so foolish- in the jargon, I7 ‘enforces type safety’.So we need to be careful how we use this newfound power by ensuring we are only making casts that make sense.

I7 is a little ambivalent about topics, in that it is quite choosy about what it will allow us to declare as a topic. For example, an object can have a property that is a topic:

A thing has a topic called adjective. The adjective of the knife is "sharp/keen/steel"

Now we can write things like:

After reading a command:
	if the player's command includes the the adjective of the knife:
	...

and this works fine for assertions that set up the state of the world, but if we want to change the adjective property of the knife:

now the adjective of the knife is "blunt/steel";

we run into a problem, because in ‘now phrases’ the compiler prefers to think that “blunt/steel” is a text, rather than a topic, and we get the cryptic compiler error:

Problem. In the sentence ‘now the adjective of the knife is “blunt/steel”’, it looks as if you intend ‘the adjective of the knife is “blunt/steel”’ to be a condition, but though they look the same, because both are written in double quotes, text values can’t in fact be used as topics, so it’s impossible to store this piece of text in that location.

What we need is a means to nudge the compiler into treating “blunt/steel” as a topic rather than as a text, and @zarf provided the surprisingly simple means to do so:

To decide which topic is the topic (T - a topic): decide on T.

and now we can write:

now the adjective of the knife is the topic "blunt/steel";

and the compiler will happily accept “blunt/steel” as a topic rather than a text.

So now we can assert (during setup) and assign/reassign (during play) the contents of a topic property.

However, if instead of declaring a topic property we try to declare a topic variable Inform once again complains:

Blasphemy is a topic that varies.

Problem. You wrote ‘Blasphemy is a topic that varies’: but ‘topics that vary’ are not allowed, that is, a variable is not allowed to have ‘topic’ as its kind of value. (This would cause too much ambiguity with text variables, whose values look exactly the same.)

The workaround that is the basis of this Bubbling Beaker Award recognises that, as we’ve seen already, to I6 a topic is simply an integer number representing the memory address to be called in order to invoke a General Parsing Routine. And I7 is perfectly happy to hold integer numbers in a variable.

Blasphemy is a number that varies.

So now all we have to do is, whenever we want to assign a topic to Blasphemy, make sure to cast it to a number:

When play begins:
	now Blasphemy is the topic "by/-- Baal/Baal's/Astarte/Astarte's/Ilumquh/Ilumquh's and/-- all/-- his/her/-- devils/--" as a number.

and in reverse, when we want to use Blasphemy as a topic, cast it back from a number to a topic:

if the player's command includes Blasphemy as a topic:
...

and we can also assign to a topic property:

A person has a topic called source of damnation.
After reading a command:
	if the player's command includes Blasphemy as a topic:
		say "You are damned!";
		now the source of damnation of the player is Blasphemy as a topic;

or create and manipulate dynamic lists of pseudo-topics-as-numbers:

The Scroll of Blasphemies is a list of numbers that varies.
After reading a command:
	if the player's command includes Blasphemy as a topic:
		say "You are damned!";
		add Blasphemy to The Scroll of Blasphemies;

etc.

4 Likes

This is absolutely another “on shoulders of giants thing”. Ron Newcomb, October, 2010:

Though I never paid much attention to the “that might be going a bit overboard” part.

2 Likes

As a bonus for this week’s Bubbling Beaker Award™, here’s a reworking of the problem central to BBA #14, but instead using type casting.

To recap, the problem was to represent an I7 grammar token in an included segment of I6 code- the difficulty being that I7 provides no native means to translate an I7 grammar token to a corresponding general parsing routine (GPR) of known name in I6.

The opposite is provided for, whereby a GPR we have written to be a grammar token in I6 can be represented by a name we invent for it in I7- by The Understand token <I7-name> translates into I6 as <I6-name>.

The syntax of this looks as though the following might work:

Color is a kind of value. Some colors are red, green and blue.
Painting it with is an action applying to one thing and one color.
Understand "paint [something] with [color]" as painting it with.

The Understand token color translates into I6 as "color_token".

but it doesn’t- the translation has to go the other way:

Include (-
[ color_token;
    ... clever I6 code here...
];
-).

The Understand token color-token translates into I6 as "color_token".
Understand "paint [something] with [color-token]" as painting it with.

So we need a different way of representing the I7 [color] token (representing the name of any color, typed in a command) in I6. The (+ color +) or (+ [color] +) notation can’t be used either here.

BBA #14 approached the issue by extracting the compiled address of the I7 [color] token from the grammar table of a verb making use of it.

But a simpler approach is to use the trick of casting a topic to a number, remembering that a topic is essentially a general parsing routine- the only difference is that a topic expects to be called with the word number (in the player’s command) to start from given as a parameter, whereas a standard general parsing routine assumes without any parameter that matching should start from the parser’s I6 global variable wn, which tracks where the parser is up to in parsing the command.

So, after

default-color-token is a number that varies.

To set color token:
	now default-color-token is the topic "[color]" as a number.

‘default-colour-token’ is the address of an I6 routine which, if called from I6 with <start-word-number> as a parameter, will itself do nothing other than set wn to be <start-word-number>, then call ParseToken(GPR_TT, <color-token>) (where <color-token> is the compiled address of the I7 [color] token) and finally return whatever the [color] GPR returns, Effectively, our topic, represented by default-color-token, is a simple wrapper function to the [color] token.

So our I6 routine for a second color token, which was

[ second_color_token x firstnum;
	firstnum = parsed_number; ! saves the first parsed number locally
	x = ParseToken(GPR_TT, default_color_token); ! <- global assigned when play begins with the address of the [color] token GPR routine
	if (x == GPR_FAIL or GPR_REPARSE) return x;
	second_color = parsed_number; ! saves the second parsed number into a global
	parsed_number = firstnum; ! returns the first number to its usual global spot
	return GPR_PREPOSITION;
];

now becomes

[ second_color_token x firstnum;
	firstnum = parsed_number; ! saves the first parsed number locally
	x =  (+ default-color-token +)(wn); ! <- I7 representation of address of topic calling [color] token GPR routine, called with wn as parameter since we do want to parse starting from where we're up to
	if (x == GPR_FAIL or GPR_REPARSE) return x;
	second_color = parsed_number; ! saves the second parsed number into a global
	parsed_number = firstnum; ! returns the first number to its usual global spot
	return GPR_PREPOSITION;
];

This is the whole example, reworked as above:

Testing Color Token
"Testing_Color_token" by PB

[NB: can be made to compile in version 6M62, but crashes interpreter with an out-of-range memory access error, because relations as properties are not implemented correctly in 6M62; works as written here in 10.1.0 (in Borogove app); works as written in 10.1.2.]

[This is a more general solution than BadParser's, achieved by creating an integer variable to hold the I6 address of a topic calling Inform's [color] token, and using the former to parse a [color] token within a custom Understand token for parsing a second color value in a command.]

Lab is a room. 

Section 1 - Zed Lopez's Bubbling Beaker Award Winner #5

color is a kind of value.

the colors are brown, red, orange, yellow, green, blue, indigo, violet.

a color has a relation of a color to a color called the mixmaster.

to (c1 - color) mixed with (c2 - color) is (c3 - color):
  now the mixmaster of c1 relates c2 to c3;
  now the mixmaster of c2 relates c1 to c3;

to decide what color is (c1 - color) mixed with (c2 - color):
  if c2 relates to a color by the mixmaster of c1, decide on the color that c2 relates to by the mixmaster of c1;

when play begins (this is the set up colors still on the TODO list rule):
	red mixed with blue is violet;
	red mixed with yellow is orange;
	yellow mixed with blue is green;
	

Section 2 - Bad Parser's Bubbling Beaker Award Winner #6 Modified for Use with a cast topic variable

default-color-token is a number that varies.

First when play begins: set color token.

To set color token:
	now default-color-token is the topic "[color]" as a number.

Include (-
Global second_color;
[ second_color_token x firstnum;
	firstnum = parsed_number; ! saves the first parsed number locally
	x =  (+ default-color-token +)(wn); ! <- I7 representation of address of topic calling [color] token GPR routine, called with wn as parameter
	print "{default_colour_token returned ", x, "}^";
	if (x == GPR_FAIL or GPR_REPARSE) return x;
	second_color = parsed_number; ! saves the second parsed number into a global
	parsed_number = firstnum; ! returns the first number to its usual global spot
	return GPR_PREPOSITION;
];
-).

The second color understood is a color that varies.
The second color understood variable translates into I6 as "second_color". [represented as a number in i6]

The Understand token second-color translates into I6 as "second_color_token".


Section 3 - Mixing It Up

Mixing it with is an action applying to one color.

Understand "mix [color] with [second-color]" as mixing it with.

Report mixing it with:
	say "Mixing [color understood] with [second color understood] (in this implementation at least) yields: [color understood mixed with second color understood].".
	
test me with "mix red with blue / mix blue with red / mix blue with yellow / mix violet with yellow / mix blue with blue / mix blue with vermilion".

Section - Casting

To decide which K is (v - a value) as a/an/-- (name of kind of value K): (- {v} -).
To decide which topic is the topic (T - a topic): decide on T.
4 Likes

Bravo, Doc!