Creating lists of things subject to a condition

Hi,

I’m repeatedly running up against a syntax problem within my code, which I’m sure is just a failure to understand how Inform wants me to word the phrase, but is proving very frustrating.

I’m trying to iterate through a list of objects that satisfy certain conditions, namely where a property of a kind satisfies particular conditions. I know that I can create a “list of open doors”, for example, but when I try and create a more nuanced iterator I keep running into problems where Inform doesn’t understand what I’m trying to say.

As an example of what I mean, I’ve written the below. I’m looking for a way to gather all the paintings of a certain colour together as a list that can be iterated over, or used in other rules. I’ve tried multiple ways of saying “list of paintings that have impression equal to red”, but I simply cannot get it to work.

Colour is a kind of value. The colours are red, yellow, green and purple.

A painting is a kind of thing. Every painting has a colour called the impression. The description of a painting is usually "This painting just seems to be a big splodge of [the impression] paint on the canvas."

The gallery is a room. "The clean white walls of the gallery seem the perfect foil for contemplating the art with surgical critical precision."

The still life is a painting. The impression of the still life is yellow. The still life is in the gallery.
The landscape is a painting. The impression of the landscape is green. The landscape is in the gallery.
The portrait is a painting. The impression of the portrait is red. The portrait is in the gallery.
The battle scene is a painting. The impression of the battle scene is red. The battle scene is in the gallery.

Every turn:
	Repeat with p running through the list of paintings that have impression equal to red:
		say "[P] is a red painting."

Any ideas on how to solve this would be much appreciated - as I said, I keep trying to use a formulation like this throughout my code and it’s creating a whole heap of ugly work arounds!

Thanks!

1 Like

One way of doing that is to use the kind of value directly as a property:

Colour is a kind of value. The colours are red, yellow, green and purple.

A painting is a kind of thing. Every painting has a colour. The description of a painting is usually "This painting just seems to be a big splodge of [colour] paint on the canvas."

The gallery is a room. "The clean white walls of the gallery seem the perfect foil for contemplating the art with surgical critical precision."

The still life is a yellow painting. The still life is in the gallery.
The landscape is a green painting. The landscape is in the gallery.

[You can declare a "<colour> painting" directly or in a separate sentence:]
The portrait is a painting. The portrait is red. The portrait is in the gallery.
The battle scene is a red painting. The battle scene is in the gallery.

Every turn:
	Repeat with p running through red paintings:
		say "[The p] is a red painting."

See 4.9. Using new kinds of value in properties.

2 Likes

Thanks, that’s helpful in some cases and is a definite improvement on my original scenario. It doesn’t quite cover what I’m trying to do though (my fault for the simplified example). I want to do something like the following - i.e. I don’t know what precise value I’m trying to filter my list for when I’m writing the code.

Every turn:
	Repeat with c running through colours:
		Repeat with p running through the list of paintings with impression of c:
			say "[The p] is a [c] painting."

With my code from above, the following works:

Every turn:
	Repeat with c running through colours:
		Repeat with p running through paintings which are c:
			say "[The p] is a [c] painting."

It feels as though you ought to be able to say:

Repeat with p running through paintings of which the impression is c:

but Inform does not support this form of adjectival phrase, so I think it has to be broken out into a separate condition if you want to filter on a named property:

Every turn:
	Repeat with c running through colours:
		Repeat with p running through paintings:
			if the impression of p is c:
				say "[The p] is a [c] painting."
1 Like

We can make it, on a case-by-case basis – but I wouldn’t exactly call it a good idea:

To repeat with (loopvar - nonexisting Painting variable) running through paintings that have an/-- impression of/-- (c - Colour) begin -- end loop:
	(- objectloop({loopvar} ofclass (+ painting +) && {loopvar}.(+ the property impression +) == {c}) {-block} -).

Every turn:
	Repeat with p running through paintings that have an impression of red:
		say "[P] is a red painting."

(Again, please don’t do this – or at least don’t say I didn’t warn you if it goes wrong in all kinds of hard-to-diagnose ways.)

2 Likes

What I’m really trying to do is get a list of objects based on named properties that I could pass to, say, the complex listing extension to print out, or to iterate over in order to test some other condition. I’ve been constructing this on a case by case basis by iterating through loops as suggested, but this feels messy and cumbersome. I guess, though, that this is what I’m left with! Thanks for the input all.

You can define such an adjective if you use a global variable.

The global-colour is a colour variable.

Definition: a painting is globally-coloured if the impression of it is global-colour.

Every turn:
	let global-colour be red;
	repeat with p running through globally-coloured paintings:
		say "... [p].";
	say "Or, [the list of globally-coloured paintings].";
2 Likes

Then I think you’d have to either define an adjective based on a named property to reflect the condition you want to filter on, as in zarf’s example, or build the list ‘by hand’ through a loop as you have been doing, -if it’s truly important that the properties are specifically named.

Inform is really willing you here to either use implicitly-named properties to create or filter your list (so that they can be used as adjectives as in St John Limbo’s example) or define your own adjectives (as in zarf’s example)

I worked out a generalized version with an only slightly awkward syntax. Would you like to see it?

After some more thought I came up with the following:

To decide whether (O - object) has (P - property) set to (V - value):
	(- (GProperty(OBJECT_TY, {O}, {P}) == {V}) -).

To decide what list of Ks is (full list - list of values of kind K) filtered by (P - property) being (V - value):
	let the filtered list be a list of Ks;
	repeat with item running through the full list:
		if the item has P set to V, add the item to the filtered list;
	decide on the filtered list.

Every turn:
	Repeat with p running through the list of paintings filtered by the property impression being red:
		say "[P] is a red painting.";
	say "[paragraph break]Or...: [the list of paintings filtered by the property impression being red]";

Sure, let’s see yours as well :smiley:

2 Likes

Virtually identical to mine for the functional parts, and I like your syntax better! (I did guard against the possibility that an inapplicable property would be used. Also, mine checks whether the value is appropriate for the property.)

To decide whether the value held by (P - L valued property) of (X - value of kind K) is (V - value of kind L):
    (- (GProperty(OBJECT_TY, {X}, {P}) == {V}) -).

To decide which list of Ks is those (desc - description of values of kind K) that have/has a/an/-- (P - L valued property) of (V - value of kind L):
    let collection be a list of Ks;
    repeat with X running through desc: [EDIT: corrected error spotted by drpeterbatesuk]
	    if X provides P and the value held by P of X is V:
		    add X to collection;
    decide on collection.

Every turn:
    let C be a random colour;
    say "Looking for [C] paintings...";
    Repeat with P running through those paintings that have an impression of C:
	    say "[P] is a [C] painting."
2 Likes

Should this be

repeat with X running through desc:

FWIW, my suggestion for syntaxes… :wink:

To decide whether the/-- (P - L valued property) property of (X - value of kind K) is (V - value of kind L):
	(- (GProperty(OBJECT_TY, {X}, {P}) == {V}) -).
		
To decide which list of Ks is those (desc - description of values of kind K) having a/an/-- (P - L valued property) of (V - value of kind L):
	let collection be a list of Ks;
	repeat with X running through desc:
		if X provides P and the P property of X is V:
			add X to collection;
	decide on collection.
	
To decide which list of Ks is those (desc - description of values of kind K) that/which/who have a/an/-- (P - L valued property) of (V - value of kind L):
	decide on those desc having P of V.
1 Like

Missed this post somehow!

The answer is yes.

1 Like

This is incredibly useful. I’ve just started playing with Inform 7 after having coded in C/C++/Ruby for a couple decades, and its differences from those languages are both fascinating and occasionally maddening.

If you don’t mind my asking, is there any way to store properties and their values in lists? I’m trying to create a general “preference” system which allows characters to like or dislike things that have properties with certain values; this code solves the issue of checking the property values, but I can’t find a way to store them (i.e. A preference has a property called the preferred property. A preference has a value called the preferred value.) since neither property nor value can be used in this manner.

property is too generic to be used here. The concrete kind would be something like text valued propertyor color valued property.

Theoretically you could use a concrete kind with something like A preference has a text valued property called the preferred property. If you actually try that you’ll find that it complains about not being able to pick a default value. If you manually assign a default with The preferred property is the description property. you’ll find that the compiler complains that the description property is object kind, not text valued property. Weird, but it explains the inability to find an appropriate default.

So you could probably work around that by declaring the preferred property as an object and continue down that rabbit hole. My gut says you could do it, but it might involve dipping into some i6 to make it happen. The fact of the matter is that a lot of documented Inform reflection functionality is either mostly unimplemented (eg. the provisioning relation) or buggy (eg. K valued property). The “object provides the property property” phrase works fine, but have caution with anything fancier.

That said, Inform provides a rich set of options for implementing what you want to do more idiomatically. I’d need to know a little more about your use case to suggest the best one. Do you want to say “I don’t like it”, “I don’t like the color”, or "I don’t like the blue color”? If they like the color but hate the shape, do they like it overall? Do you want the ability to change an object’s property and have the liked status change accordingly?

Yeah, I’m pretty sure I’m contorting i7 to do stuff that it wasn’t really designed for. I have a system called “witnessing” which basically broadcasts room actions to other characters in the room, so they can react appropriately. The idea is that NPCs could witness an action, and then do something (set a mood, perform an action, say something, etc.) depending on aspects of that action. For example, if an individual sees someone else picking up a red bowl, and that individual really likes the color red, they might comment on what a nice shade of red it is.

But I’m realizing that the system doesn’t have to be so generic; I’m still thinking as though NPCs can be created/destroyed at runtime (a la a game like The Sims, or Dwarf Fortress), which wouldn’t really be the case here. So it’s probably better to manually set hooks for the preferences of individual characters, instead of trying to abstract it all out so much.

I can’t read Graham’s mind, but I doubt those parts would be documented if they weren’t designed to be used. I think it’s more likely that they’re underdeveloped because they’re underused, and they’re underused because there’s usually a more idiomatic way to express the same functionality. For example, you could say

A character has a description of thing called preference. A character has a text called reaction.

Jill is a character. Her preference is something red. Her response is "Jill says, 'I like the shade of red.'".

which captures most of the essence of your preferred property/value scheme, but a bit more flexible.

Traditional OO design teaches you for each concern to ask which object it most naturally belongs to, so it’s easy when starting Inform to think the same way. Inform gives you more options to think about. The most natural place for something to belong might be between objects (like in a relation or table) or as part of some kind of computation (like in a phrase, rulebook, activity, or action). For a while you’ll need to practice evaluating those other options every time you feel like reaching for a property. Even a stateful value associated with an object sometimes is better represented as a relation between an object and a value; it just depends on what you plan to do with it.

In this case, if reacting is the only place the characters’ preferences are needed, then the reaction would be the natural place for that information to belong. (This is especially true because Inform already has built in behavior for that.) So you could write

After doing something with something red in the presence of Jill: say "Jill says, 'I like the shade of red.'".

But if character preferences were needed in multiple places, it might be better to model them using a phrase like this:

To decide if (character - a character) likes (thing - a thing): decide no.

To decide if (character - Jill) likes (thing - a red thing): decide yes.
1 Like