ROT13 code is very slow (encode hints in tester transcript?)

I wanted to have a ROT13 encoder in place in order to display hint information for myself in a tester’s transcript. For instance, a player would be able to say “HINT” and that would show a location-specific hint in a test build. But I don’t want to ruin that for the first time player–though I want to be sure the hints would be reasonable if he could see them. So I could have them set a flag that obfuscates the hint, then read their transcript.

But ROT13 seems very slow with indexed text, at least in the couple ways I tried to implement it. I’ve tried two ways and each takes a few seconds within the IDE or a built zblorb. Is there a quicker way than my source? I read in the docs that we don’t track the ASCII number of values, so I can’t do any math tricks to replace the perl-ish cheap and dirty tr/[a-z]/[m-za-o]/y.

Now, I think a better solution is ultimately to just send the player’s latest command and the game’s hint to a text file, but I’m curious about if there’s a way to speed any ROT13 up.

Thanks again!

[code]“rot13” by Andrew

room 1 is a room.

every turn:
test-reg-expr;

to test-reg-expr:
let xyz be indexed text;
now xyz is “Yay”;
say “[xyz].”;
say “[the rot13 of xyz].”;
now xyz is “The quick brown fox jumped over the lazy dog”;
say “[xyz].”;
say “[the rot13 of xyz].”;
now xyz is “Another test, this one to see if things really slow down”;
say “[xyz].”;
say “[the rot13 of xyz].”;

table of rot13
from to
“a” “n”
“b” “o”
“c” “p”
“d” “q”
“e” “r”
“f” “s”
“g” “t”
“h” “u”
“i” “v”
“j” “w”
“k” “x”
“l” “y”
“m” “z”

to decide what indexed text is the rot13 of (aa - indexed text):
let twiddled-yet be a truth state;
let A be AA;
repeat with B running from 1 to the number of characters in A:
now twiddled-yet is false;
repeat through the table of rot13:
if twiddled-yet is false:
if character number B in A in lower case is “[from entry]”:
replace character number B in A with “[to entry]”;
now twiddled-yet is true;
otherwise if character number B in A in lower case is “[to entry]”:
replace character number B in A with “[from entry]”;
now twiddled-yet is true;
decide on “[A]”;

to decide what indexed text is the encodation of (aa - indexed text):
let twiddled-yet be a truth state;
let A be AA;
let D be a number;
repeat with B running from 1 to the number of characters in A:
now twiddled-yet is false;
repeat with C running from 1 to the number of entries in Q:
if character number B in A in lower case is “[entry C of Q]” and twiddled-yet is false:
now D is rotationkey + C;
if D > number of entries in Q:
now D is D - number of entries in Q;
replace character number B in A with entry D of Q;
now twiddled-yet is true;
decide on “[A]”;

rotationkey is a number that varies. rotationkey is usually 13. [this allows for not just ROT13]

Q is a list of text which varies. Q is { “a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”, “i”, “j”, “k”, “l”, “m”, “n”, “o”, “p”, “q”, “r”, “s”, “t”, “u”, “v”, “w”, “x”, “y”, “z” };[/code]

If these hints are going to be fixed, why not just do the ROT13 calculations yourself and include both strings in the game file, printing out the appropriate one when required?

-Kevin

Hm, that’s a good idea. I suppose it’s possible to convert them beforehand, or maybe even assign a number to each hint–but that is a lot of grunt work. After I posted this, I thought–why can’t I just pull every 5th character or something to obfuscate this from the player/tester? That’d be almost certainly garbled enough for the tester, but since I have the master sheet of hints, I can derive what I need.

Also I fiddled with my workaround about putting the hint text to an external file, and it works well, so I guess my main question is how I could speed up ROT13. This is more intellectual curiosity than anything, though I figured having a topic like this might be worth it for someone else who wants to try encoding.

What reference are you looking at? I don’t find it.

Glulx indexed text will always stored character sequences as Unicode (in arrays of four-byte values, no UTF involved, not that you care for rot13 purposes). As long as you don’t involve fancy foreign output options, Z-code indexed text will be ASCII for ASCII values – again, that’s all you care about for rot13 purposes.

Your functions use a double nested loop, and the inner loop is just a long, inefficient way to add or subtract 13. (Not to mention the twiddle flag, which saves a few bytes of table table at a cost of making your code clever. Never write clever code.) You’d need an I6 function to do the conversion quickly, but it’s worth it.

Really, I would replace the entire function with I6 code to mangle the indexed text array in-place.

Thanks. I was sort of fearing someone’d say that, but on the other hand, I6 obviously has some powerful low-level stuff that might be easier than I7. Roger Firth’s website seems as good a place as any to start.

Also, I appreciate your pointing out what not to do with coding. I can slip into the bad coding practices and felt I was headed that way.

Section 19.6 says “(iv) Inform does not allow characters to be referred to by character code (whereas Perl allows “\036” for an octal character code, “\x7e” for a hexadecimal one, “\cD” for a control character). This is because we do not want the user to know whether text is internally stored as ZSCII or Unicode.”

But this is part of the regular expressions chapter. I assumed it expanded to referring to characters that way in general, but I guess I was wrong. I think I’ve seen use of ascii code in Mark Tilford’s automapping. I should look there for how he did it.

It is referring to characters in general; I’m just ignoring it. (And, as I said, Unicode and Z-encoding are the same for simple letters. Usually. If you’re not doing anything clever.

Not necessarily. It’s possible to use another programming language (such as C++) do to the conversions. Also, some text editors include a ROT13 function and can convert an entire text file in next to no time.

Hope this helps.

Thanks–actually the solution I came up with was to have a command that toggled printing the first two letters and the character count of the hint to the screen, and print out the following to a file:

“> (player’s command): (the same hint in full)”

This hides the clue from the tester if he doesn’t want it, and it gives the tester something he can attach and send to the programmer. Full hints in-game can be toggled as well, of course…

Obviously this code must be pulled before the game is released (I have a testing section I can mark as not for release,) but I think it does what I want without (too many) gimmicks.

If anyone has a better solution I’d be quite interested. A double blind is obviously very handy for tester/programmer communications. The less spoiled before a game is polished, the better–a tester only gets one chance to see things the first time and act as a true player.

Here’s an optimized version using I6 code.

[code]To decide which indexed text is rot13 of (T - indexed text): (- (IT_ROT13({-pointer-to-new:indexed text}, {-pointer-to:T})) -).

Include (-
[ IT_ROT13 dest src len i c;
len = BlkValueExtent(src);
BlkValueSetExtent(dest, len);
for (i=0: i<len: i++) {
c = BlkValueRead(src, i);
switch © {
‘a’ to ‘m’, ‘A’ to ‘M’: c = c + 13;
‘n’ to ‘z’, ‘N’ to ‘Z’: c = c - 13;
}
BlkValueWrite(dest, i, c);
}
return dest;
]; -).[/code]

Wow! Thanks for posting this. I was curious how to do this, but I figured there was so much else to look at.

This is the sort of thing that makes I6 a lot less intimidating to me.