Getting rid of "a random X" for only one object

On Uservoice there’s been the suggestion to change the phrasing “a random hat worn by the player” when the author knows there can be only one: instead, “the hat worn by the player” is more readable, and could make more efficient code (why loop through all hats if you don’t need to?).

I put together some code to try this out:

Include (-
[ FirstSatisfying filter x;
	for(x=IK2_First: x: x=x.IK2_Link){
		if(filter(x)) return x;
	}
	rfalse;
];
-).

To decide which K is the* (D - description of values of kind K):
	(- FirstSatisfying({D}); -).

This allows you to refer “the* hat worn by the player”, with the asterisk. It also stops as soon as it finds one object fitting the criterion, even if there could potentially be more. (Unfortunately couldn’t make it work without the asterisk, since “the” has special meaning in Inform.)

Is there anything to be gained or lost by using this method? My code currently applies the test to all “things” it comes across, rather than only things of a certain kind—but the compiler won’t let me pass {K} to the function. Is there a way around this limitation? And, any recommendations for better syntax? The asterisk is ugly and confusing for readers, but this needs something short and readable.

(In other words: I could make this more efficient if there were {-substitutions} that turned “thing” into “IK2_First” and “IK2_Link”.)

A description function has “first-satisfying” built in. You don’t have to write the loop yourself.

To decide which K is the* (D - description of values of kind K):
	(- ({D}(-2)) -).

Of course, you need to document that if nothing satisfies the description, this returns “nothing”.

Since you’d still have to check if the hat worn is not nothing, you don’t really need what you tried:

if the player wears a hat (called H): now H is…People seem to forget you can write that.

Yes, that is often a good idiom.

Useful, thanks! (This is mostly intended for places where you know there is one and only one thing matching the description.)

Could “specific” just be a synonym for “random” (despite that being a real world paradox? - essentially it would do the same thing: pick a random hat or the only one.)

Before greeting someone: if the player wears a hat: now a specific hat worn by the player is carried by the player; [a specific hat chosen at random; a randomly chosen one of many specific hats worn by the player; it's not such a paradox, is it?] say "First doffing your hat.[command clarification break]";

Regarding syntax, what about “the only”?

if the player wears a hat, now the only hat worn by the player is carried by the player;

I like “the only”, but it breaks the Standard Rules (which have “only if victorious” as a column name in the table of ending options). This shouldn’t actually be a problem, since parsing is still unambiguous (“the only (if victorious entry)” doesn’t work), but the compiler doesn’t like it.

Checking a thesaurus…lone, one-off, single, solitary, or sole? “Sui generis” might be a bit much. :slight_smile:

What about “unique”?

let the chosen head-covering be the sui generis hat worn by the player;

I like “the”, with asterisks. As in: “let O be the hat worn by the player.”

or

let the chosen head-covering be the ronly hat worn by the player;

a.k.a. “I was going to say ‘random’ but I changed my mind.”

I like the idea of vanilla “a/the hat worn by the player” choosing a random one if the description has multiple matches, the single matching one if there’s only one match, and nothing if there are no matches.

That’s the same as “a random X”, though. You’re not defining new behavior.

The version I posted earlier (with {D}(-2)) is deterministic in the multiple case, and very slightly faster in the singleton case. This is not, to be honest, a improvement that’s really worth bothering with.

You might want this version, which validates that there’s exactly one D:

Include (-
[ SoleSatisfying desc obj obj2;
	obj = desc(-2);
	if (obj == nothing) {
		print "BUG: description covers zero things.^";
		return nothing;
	}
	obj2 = desc(-2, obj);
	if (obj2 ~= nothing) {
		print "BUG: description covers more than one thing.^";
		return nothing;
	}
	return obj;
];
-).

To decide which K is *the* (D - description of values of kind K):
	(- SoleSatisfying({D}) -).