How to show variable name for something with defined printed name?

Hello, I have a problem where I’d like to run tests on various rooms, but the problem is, they’re named identically.

Putting aside whether this is a good idea in game design, how would we print out r1/r2/r3 below instead of “Dead End?”

r1 is a room. printed name of r1 is "Dead End".
r2 is a room. printed name of r2 is "Dead End".
r3 is a room. printed name of r3 is "Dead End".

section testing - not for release

when play begins:
  repeat with Q running through rooms:
    say "Testing diagnostics for [Q]: (stuff)[line break]";

Thanks!

Good question. The source code name of a room (or other object) is not compiled into the game as text; only the printed name is. So you’d have to do something like this:

R1 is a room. 
Rule for printing the name of R1 while not debug-listing:
	say "Dead End".

Debug-listing is an action out of world applying to nothing.

Carry out debug-listing:
	repeat with R running through rooms:
		say "[R]...";

(The debug-listing action can’t be invoked by the player, since it has no grammar.)

There’s a simpler hacky solution, though. It turns out that the source-code name is compiled in as part of the object’s name synonyms – unless the object is privately-named. A room’s name synonyms aren’t normally checked (because rooms are out of scope by default) but you can peek at them:

To say internal name of (O - object): (- print (address) ({O}).&name-->0; -)

This only prints the first word of the name, and, again, only for publicly-named rooms and objects. So with that definition, this works:

When play begins:
	repeat with R running through rooms:
		say "[internal name of R]...";
4 Likes

Thanks!

I forgot to mention the rooms were privately-named, but it’s good to see some of the I6 nuts and bolts here, because it’s something I’m always interested in, but I put it off.

The explanation pointed me towards other ways to identify the rooms specific to my code, which is a good enough workaround.

I suppose if nothing else I could arbitrarily number the rooms and say

a room has a number called room-index.
say "[X] ([room-index of X]) needs (diagnostics).";

, which again might not be great code, but it gives the information that I need.

Some ideas that might or might not be useful in your specific case:

  • Say what room they’re adjacent to (if other rooms are uniquely named):
say "Testing diagnostics for [Q] (near [a random room adjacent to Q]): (stuff)[line break]";
  • Say what they contain:
say "Testing diagnostics for [Q] (that contains [the random thing in Q]): (stuff)[line break]";
  • or something else that’s unique to those rooms
1 Like

This would be a nice alternative:

A room has a text called debug-name.
The debug-name of a room is usually "[printed name of the item described]".

This lets you define a debug-name for any room, but if you don’t, it defaults to the printed name.

1 Like

You can also assign numbers automatically:

When play begins:
    let K be zero;
    repeat with R running through rooms:
        now the room-index of R is K;
        increment K.

Or you could use the rooms’ internal object numbers, which will be more useful on Z-machine than on Glulx but are guaranteed to be unique:

To decide which number is the internal index of (O - an object): (- {O} -).

Or you could come up with an extremely basic hash function to make the internal index more readable, and hope for no collisions:

To decide which text is the hash of (N - a number):
    let the alphabet be "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
    let R be the remainder after dividing N by the length of the alphabet;
    decide on character number R in the alphabet.

Then:

Rule for printing the name of a room (called the place) when using debug mode:
    say "[printed name of the place] ([hash of the internal index of the place])".

This should disambiguate most rooms; mathematically, the odds of getting two rooms that have the same printed name and the same hash are low (unless you’ve got a whole maze filled with identical rooms).

A better hash function might be something like “take each four-bit unit from the number, add them all together, and discard any overflow”, but that gets into bit manipulation in I6 which is tedious and annoying. So I don’t want to implement that unless there’s actually a demand for it. If that would be useful to people, though, I’ll do it.

2 Likes

…I say things like this, and then the problem sticks in my mind and I can’t get rid of it until I solve it. So here’s a better hash function in I6.

[ ExtractNybble n amt mask shift ;
	mask = $0f; ! 00001111 in binary
	shift = 4 * amt;
	mask = LeftShift(mask, shift);
	n = BitwiseAnd(n, mask);
	n = RightShift(n, shift);
	return n;
];

[ Hash n res i ;
	res = 0; ! Just in case
	for( i=0 : i<WORDSIZE*2 : i++ ){
		res = res + ExtractNybble(n, i);
	}
	return ExtractNybble(res, 0);
];

Plus some syntactic sugar for things that I6 doesn’t have operators for:

[ LeftShift n amt ;
	#Ifdef TARGET_GLULX;
	@shiftl n amt n;
	#Ifnot;
	@log_shift n amt -> n;
	#Endif;
	return n;
];

[ RightShift n amt ;
	#Ifdef TARGET_GLULX;
	@ushiftr n amt n;
	#Ifnot;
	amt = -amt;
	@log_shift n amt -> n;
	#Endif;
	return n;
];

[ BitwiseAnd x y ;
	#Ifdef TARGET_GLULX;
	@bitand x y x;
	#Ifnot;
	@and x y -> x;
	#Endif;
	return x;
];

This will turn any value into a number between 0 and 15 inclusive. So:

To decide which number is the disambiguator of (O - an object): (- Hash({O}) -).

Rule for printing the name of a room (called the place) when using debug mode: say "[printed name of the place] ([disambiguator of the place])".
2 Likes

I’m really glad my question spurred all these ideas. They’ll be useful beyond my current problem.

I also thought of deriving a room’s rough coordinates, as long as the map is relatively reciprocal e.g. going north and south leads you back to the same room. This is uncompiled pseudocode, but I hope it gives the general idea.


after printing the name of a room (called rm) while testanalyzing: say "([xcoord of rm], [ycoord of rm])";

when play begins:
    a room has a number called xcoord. a room has a number called ycoord.
    map-coords Home Base;

definition: a room (called rm) is uncoord:
    if rm is Home Base, no;
    if xcoord of rm is 0 and ycoord of rm is 0, yes;
    no;

to map-coords (rm - a room):
    if the room north of rm is uncoord:
        now xcoord of the room north of rm is xcoord of rm;
        now ycoord of the room north of rm is ycoord of rm + 1;
        map-coord room north of rm;
    if the room south of rm is uncoord:
        now xcoord of the room south of rm is xcoord of rm;
        now ycoord of the room south of rm is ycoord of rm - 1;
        map-coord room south of rm;
    if the room west of rm is uncoord:
        now xcoord of the room west of rm is xcoord of rm - 1;
        now ycoord of the room west of rm is ycoord of rm;
        map-coord room west of rm;
    if the room south of rm is uncoord:
        now xcoord of the room east of rm is xcoord of rm + 1;
        now ycoord of the room east of rm is ycoord of rm;
        map-coord room east of rm;

I suppose another way to do this if directions weren't reciprocal would be to generate a hash that describes the shortest path from home base to the room, maybe where the number was in base 5, e.g. 4321 in base 5 would mean go north east south west.This has its own problems, especially with overflow in a big map, but it seems to work well enough. Maybe you could use a string.
1 Like