Mr Socks is a pink and green knitted cat

So, I wanted to be able to write Mr Socks is a pink and green knitted cat.

Looking at various examples, colour usually seems to be modelled as a property. That seems to work well enough for things with a single colour. However Mr Socks is stripy, so this won’t work…

Modelling the colours as a list does work, but I couldn’t make it read well:

Mr Socks is a knitted cat. The colour is {pink, green}.

Yuck! Also it’s tedious for those objects which are non-stripey (how gauche!) and have to be described with a single-valued list.
Worse, I couldn’t find a simple way to “understand” the colours. e.g. refer to “pink” or “the green cat” automatically. Understand’ing a property seems to work only for single values, not a list of them.

For now, I’ve come up with this, which is verbose, but seems to do what I want:

[code]A hue is a kind of thing. [not a value, because we want a printed name]

A thing can be pink.
Pinkness is a hue. The printed name is “pink”.
Understand the pink property as describing a thing.

A thing can be green.
Greenness is a hue. The printed name is “green”.
Understand the green property as describing a thing.

To decide what list of hues is the colour of (T - a thing):
Let L be a list of hues;
if T is pink, add pinkness to L;
if T is green, add greenness to L;
decide on L.

A cat is a kind of animal.
A cat can be knitted.

Mr Socks is a pink and green knitted cat.
He is in a room called the Kitchen.
When play begins: say “Mr Socks is [the colour of Mr Socks].”[/code]

Is that a reasonable approach? I’d like to define these colours in a table, but it doesn’t seem to be possible to put a property in a table.
I’m assuming it’s possible to make that more compact (certainly by dropping into Inform6 as a last resort), but that’s a secondary concern.

Is the intent just to make your source code read better? This is not only verbose, it’s inefficient to parse.

Are you going to have several multicolored objects?

Thanks, let me try to clarify:

  1. The requirement does arise from the character:
    Mr Socks is stripy, and therefore likes stripy things and dislikes monochrome things.
    I can think of a few nice descriptions and potentially some puzzles based on that.

  2. But this is also effectively structured play: I’m only just learning Inform 7, so I’m excited to
    learn more about what works better, both for the source code and for the engine itself.

So yes, the current implementation is largely an idle curiosity (and yes, part of me just wanted
to be able to write that sentence), but it does arise from a problem that I’ve played with several ways,
none of which seem entirely satisfactory.

Have you checked out the Recipe Book 9:7 “Painting and Labeling Devices” - It’s about changing properties of things but may give some example code along the lines of what you are doing.
inform7.com/learn/man/RB_9_7.html

Oh, thanks! One of those examples suggests a label which is part of a thing. That suggests modelling the stripe in the same way, so…

[code]Colour is a kind of value. The colours are uncoloured, pink and green.
A stripe is a kind of thing. A stripe is part of every animal.
Every thing has a colour.

Mr Socks is a pink animal. The stripe is green.[/code]

It’s not quite as nicely phrased, and it does mean that every animal is modelled as having a stripe… that’s fine, as we can ignore it if the stripe is in fact uncoloured. Not sure if this has legs, but definitely worth a play :wink:

And… with a bit more thought and play, I think this is better:

[code]Colour is a kind of value. The colours are pink and green.
Colouring relates one animal to various colours.
The verb to be coloured means the colouring relation.
The verb to be resplendent in means the colouring relation.

Mr Socks is an animal. He is resplendent in pink and green.[/code]

Hurrah!

osf’

1 Like

If you turn the colours from a kind of value to a kind of thing, you can even have them be understood:

[code] Lab is a room.

Colour is a kind of thing. Pink and green are colours.
Colouring relates one animal to various colours.
The verb to be coloured means the colouring relation.
The verb to be resplendent in means the colouring relation.

Mr Socks is an animal in Lab. He is resplendent in pink and green.

Understand "[something related by colouring]" as an animal.[/code]

They have to be a kind of thing because, as the compiler informed me the first time I tried it, understanding by relations doesn’t work with kinds of value. But this creates them offstage where they can’t do any harm.

Unfortunately this won’t allow “x pink and green cat” (assuming that you are understanding “cat” as a cat), because the parser wants to understand that as applying to two things: “x (pink) and (green cat).” It will tell you you can’t do that to multiple objects. This might be something that can be worked around with some sort of thing that replaces the word “and” in such constructions. Or it might not. I tried a bit with regular expressions and realized that I now had two problems. So it might not be worth it (I also understand that understanding by relations can be computationally slow).

1 Like

(I know this post is old, but a similar question has come up recently, and I know I once tried to figure out how to do something similar but couldn’t manage it then.)

Inform 7 does not have a built-in way to easily recognize a group of related words as being descriptive of a particular object via checking a list.

It’s possible to write something like:

Understand "[something related by reversed coloration]" as a toy animal.

That will work to an extent, but a command like >EXAMINE PINK AND GREEN ANIMAL will tend toward being interpreted as referring to at least two different things (i.e. as a multiple object list containing something matching “PINK” and something matching “GREEN ANIMAL”).

Inform 6 provides the tools to write a general parsing routine (GPR), which is a piece of code that tries to understand a string of words in the command input. I7 allows use of custom-written GPRs (see WWI 27.23 Inform 6 Understand tokens), though this is of limited use to the typical I7 author who wishes to avoid I6.

In this case, however, it is really the best option available. Here’s an implementation for 6M62:

Return of Mr. Socks
"Return of Mr. Socks"

Place is a room.

A color is a kind of object. [It's easier to use object than a new kind of value.]
A color can be privately-named or publicly-named. A color is always publicly-named.

Some colors are defined by the Table of Dyes

Table of Dyes
black
brown
red
orange
yellow
green
blue
purple
pink
gray
white

A toy animal is a kind of thing. A toy animal has a list of colors called pattern.

Carry out examining a toy animal:
	say "[The noun] is colored [list of colors staining the noun].";
	now examine text printed is true.

Coloration relates various colors to various toy animals. The verb to stain means the coloration relation. The verb to be dyed means the reversed coloration relation.

Understand "toy" or "animal" as a toy animal.

Understand "[color range]" as a toy animal.

Definition: a toy animal (called T) is single-colored:
	let L be the list of colors that relate to T by the coloration relation;
	if the number of entries in L is one, decide yes;
	decide no.

Before printing the name of a single-colored toy animal while asking which do you mean:
	say "plain ".

Mr Socks the Cat is a toy animal. He is dyed pink and green. Understand "cat" as Mr Socks.
Ms Claws the Tiger is a toy animal. She is dyed orange and black. Understand "tiger" as Ms Claws. 
Mr Hops the Frog is a toy animal. He is dyed green. Understand "frog" as Mr Hops. 
Mme L'Oink the Pig is a toy animal. She is dyed pink. Understand "pig" or "piggy" as Mme L'Oink.
Swirly the Snake is a toy animal. It is dyed red, orange, yellow and white. Understand "snake" as Swirly.
Snowy the Bear is a toy animal. It is dyed white. Understand "bear" as Snowy.

Every toy animal is in Place.

A color can be used-this-cycle.

Include (-

[ ParseColorList     sv_wn last_wn wd curr_col colors_matched all_colors_matched words_matched plain_flag;
	sv_wn = wn; all_colors_matched = true; plain_flag = false;
	ResetColorUse();
	do {
		last_wn = wn;
		wd = WordFrom(wn, parse);
		if (wd) {
			curr_col = ColorFromCurrentWord();
			if (curr_col) {
				if ( (RlnGetF( (+ coloration relation +) , RR_HANDLER))(false, RELS_TEST, curr_col, self) ) {
					wn++;
					if (~~(GetEitherOrProperty(curr_col, (+ used-this-cycle +)))) {
						SetEitherOrProperty(curr_col, (+ used-this-cycle +));
						colors_matched++;
					}
				} else {
					all_colors_matched = false;
				}
			}
			if (wd == 'and' && colors_matched) wn++;
			if (wd == 'plain') { plain_flag = true; wn++; }
		}
	} until (wn == last_wn);
	if ( plain_flag && (~~( (+ single-colored +)(self))) ) return GPR_FAIL;
	words_matched = wn - sv_wn;
	if (words_matched && all_colors_matched) return self;
	return GPR_FAIL;
];

[ ColorFromCurrentWord     color;
	objectloop (color ofclass (+ color +)) {
		if (Refers(color, wn)) return color;
	}
	rfalse;
];

[ ResetColorUse     color;
	objectloop (color ofclass (+ color +)) {
		SetEitherOrProperty(color, (+ used-this-cycle +), true);	! true means clear property
	}
];

-).

The understand token color range translates into I6 as "ParseColorList".

It may require substitution of certain routine names for 10.1.2.

5 Likes

I have reworked this for Ver 10.1.2, and refined it slightly in the process so that after commands of the form ‘<verb><colour(s)> and <non-colour-word>’ (e.g. ‘take yellow and cat’) the token backs out gracefully and exits with a match only on <colour(s)>, leaving the parser to interpret the ‘and’ in a conventional way as a prelude to a second object.

Without this tweak the token exits with a match that includes the ‘and’ and therefore after the above command, which leaves the parser trying to parse an unexpected ‘cat’ when the command appears to have completed with ‘take yellow’, leads to ‘I only understood you as far as wanting to take Swirly the Snake.’

I have also stripped out a few parts that seemed to me redundant, perhaps relics of earlier versions.

As it stands, the token chooses to interpret ‘<matching colour(s) for one object> and <colour not matching same object>’ e.g. ‘Take yellow and green’ as a failed match- take something both yellow and green, leading to ‘you can’t see any such thing’- rather than an attempt to take two objects of distinct mutually exclusive colours- take something yellow and take something green.

This was quite a job to convert because of

  • the need to strip GetEitherOrProperty() and GetEitherOrProperty() calls back to object.property syntax (to be converted by the compiler to the Ver 10 equivalent function calls)
  • the fact that some (+ … +) named I7 substitutions don’t work as they should in Ver 10
  • the fact that the call syntax is not supported in Ver 10 I6 inclusions
  • the need to fix the Ver 10 bug relating to failure to retokenise after ‘Which do you mean…?’ questions

In revenge, I have anglicised the spelling :grinning:

Return of Mr Socks - The Unwanted Sequel
"The Return of Mr Socks - The Unwanted Sequel" by OTD

[updated to Version 10 and tweaked a bit by PB]

Chapter - Geography

Place is a room.

Chapter - Colours

A colour is a kind of object. [It's easier to parse an object than a new kind of value.]
A colour can be privately-named or publicly-named. A colour is always publicly-named. [so that, as a kind of object not a thing, they are compiled with a name property]

Some colours are defined by the Table of Dyes

Table of Dyes
black
brown
red
orange
yellow
green
blue
purple
pink
grey
white

Chapter - Toy animals and their colours

Section - setting up the colouration of toy animals

A toy animal is a kind of thing. A toy animal has a list of colours called pattern.

Carry out examining a toy animal:
	say "[The noun] is coloured [list of colours staining the noun].";
	now examine text printed is true.

Colouration relates various colours to various toy animals. The verb to stain means the colouration relation. The verb to be dyed means the reversed colouration relation.

Understand "toy" or "animal" as a toy animal. Understand "one" as a thing.

Understand "[colour range]" as a toy animal.

Definition: a toy animal (called T) is single-coloured:
	let L be the list of colours that relate to T by the colouration relation;
	if the number of entries in L is one, decide yes;
	decide no.

To decide whether (T - a toy animal) is plain (this is plain-determining): [need this redundant phrase because (+ <adjective> +)  doesn't work in V10]
	if T is single-coloured, decide yes;
	decide no.

Before printing the name of a single-coloured toy animal while asking which do you mean :
	say "plain [list of colours staining the item described] ". [ now we get 'plain white Snowy the Bear' rather than 'plain Snowy the Bear']
	
Section - Some toy animals

Mr Socks the Cat is a toy animal. He is dyed pink and green. 
Ms Claws the Tiger is a toy animal. She is dyed orange and black.
Mr Hops the Frog is a toy animal. He is dyed green. 
Mme L'Oink the Pig is a toy animal. She is dyed pink. Understand "piggy" as Mme L'Oink.
Swirly the Snake is a toy animal. It is dyed red, orange, yellow and white.
Snowy the Bear is a toy animal. It is dyed white.
Dippy the Dinosaur is a toy animal. He is dyed pink, green and black.

Every toy animal is in Place.

Chapter - Washing and bleaching

Washing is an action applying to one thing. Understand "wash [things]" as washing.

Carry out washing: now the noun is dyed pink.

Report washing: say "[The noun] is looking a bit pinkish!".

Bleaching is an action applying to one thing. Understand "bleach [things]" as bleaching.

Carry out bleaching: now nothing stains the noun; now the noun is dyed white.

Report bleaching: say "[The noun] is brilliant white!".



Chapter - Colour parsing token

Include (-

[ ParseColourList     sv_wn last_wn wd curr_col colours_matched all_colours_matched words_matched plain_flag;
	sv_wn = wn; all_colours_matched = true; plain_flag = false;
	do {
		last_wn = wn;                                                          ! mark start of parsing for this cycle
		wd = WordFrom(wn, parse);                                  ! get current word to parse
		if (wd) {                                                                   ! if it's a dictionary word
			curr_col = ColourFromCurrentWord();          ! try to match current word as a colour
			if (curr_col) {                                                   ! and if so....
				if ( (RlnGetF( (+ colouration relation +) , RR_HANDLER))(false, RELS_TEST, curr_col, self) ) {   ! if relates to object of interest
					wn++;                                              ! move to next word
					colours_matched = true;
				} else {
					all_colours_matched = false;            ! flag that we've tried to parse a colour that didn't match this object
				}
			}  ! end of if current word is a colour
			if ( (wd == 'and') && (colours_matched) ) {            ! if we've already matched at least one colour, move past 'and'
				wn++;
				curr_col = ColourFromCurrentWord();             ! try to match word after 'and' as a colour
				if (~~(curr_col)) wn=last_wn;                           !  If that's not a colour, abandon matching after word before 'and'
			}                                                                                          ! so the parser treats what comes after 'and' as a separate object
			if (wd == 'plain') {
				plain_flag = true;
				wn++;
			} ! and move past 'plain' as a descriptor, setting flag
		}
	} until (wn == last_wn);  ! i.e. wn not incremented, so word not matched on this cycle-> stop parsing here
	if ( plain_flag && (~~( ((+ plain-determining +)-->1)(self))) ) return GPR_FAIL;  ! only accept 'plain' descriptor for single-coloured things
	words_matched = wn - sv_wn;
	if (words_matched && all_colours_matched) return self;  ! match this object only if we matched at least one word & all colours matched
	return GPR_FAIL;
];

[ ColourFromCurrentWord     colour;
	objectloop (colour ofclass (+ colour +)) {
		if (Refers(colour, wn)) return colour;
	}
	rfalse;
];

-).

The understand token colour range translates into I6 as "ParseColourList".

Chapter - Bug fixes

Section - Failure to retokenise after Which do you mean

After reading a command:
	retokenise;
	[say "The player's command is: [player's command][line break]";]
	
To retokenise: (- VM_Tokenise(buffer, parse); num_words = WordCount(); players_command = 100 + num_words; -).

Chapter - Testing

Test me with "take every green toy/drop all/x green/plain/take yellow and cat/drop all/take yellow and green/take yellow and brown/x red orange and yellow/x red orange and yellow and white/take red orange and yellow and white and frog/drop all/take bear and pink and green animal/Dippy/drop all/take every green toy except the green and black one/take one pink and one yellow/wash tiger/x tiger/bleach every black toy/x tiger".
4 Likes