ORD(X) in Inform 7/6?

Updating my entry in ParserComp brought up an interesting coding question–well, for me, anyway. Save states were broken, but the thing is, you don’t really NEED save states. There are technically 24 or so switches you can flip to check progress.

So I thought it would be nice to give the player something to write down to try for later, in case the game was updated, if they try to quit or save or whatever. It seems like it might be useful for future comps where maybe I might send an update.

I came up with this code, which works, but it seems convoluted. It takes a number in text and converts it to a number variable, which I can then process with bits, etc. (Yes, I recognize z-machine has overflow over 32768. I’ll deal with that in my own private code. The basic idea is, the “number” has 4 digits for the 1st 12 flags and 4 for the next, making the maximum value 81918191.)

"Add 1 to a string-number" by Andrew

room 1 is a room.

table of ORD
numchar (indexed text)	num
"0"	0
"1"	1
"2"	2
"3"	3
"4"	4
"5"	5
"6"	6
"7"	7
"8"	8
"9"	9

after reading a command:
	if the player's command matches the regular expression "^<0-9>+$":
		say "[1 + num-val of word number 1 in the player's command].";
		reject the player's command;

to decide which number is num-val of (x - indexed text):
	let this-num be 0;
	let char-index be 1;
	let this-char be indexed text;
	while char-index <= number of characters in x:
		now this-char is character number char-index in x;
		let my-num be the num corresponding to a numchar of this-char in table of ORD;
		now this-num is this-num * 10;
		increase this-num by my-num;
		increment char-index; [this-index gives abject failure]
	decide on this-num;

Now this would be trivial with an ord(x) function from Python/C, etc. (or, more precisely, digit = ord(x) - 48.) But that’s probably too much too ask. Still, I’m wondering: is there a better “ord” function Inform can use? Can some Inform 6 be used? Or is what I have the best a programmer can do, practically speaking?

Note I’d also like to keep the game as Z-code and am willing to jump through some hoops to keep it that way. My holy grail is to be able to convert a string to a number without that table of ORD.

1 Like

How about the following?

To decide which number is digit-val of (x - text):
    (- (DigitToValue(BlkValueRead({x}, 0))) -).

to decide which number is num-val of (x - text):
    let this-num be 0;
    let char-index be 1;
    let this-char be text;
    while char-index <= number of characters in x:
	    now this-char is character number char-index in x;
	    let my-num be the digit-val of this-char;
	    now this-num is this-num * 10;
	    increase this-num by my-num;
	    increment char-index; [this-index gives abject failure]
    decide on this-num;

EDIT: Removed some debugging output from the above that I forgot to take out before posting.

2 Likes

Thanks! This is really slick & what I’d hoped for. It also alerted me to Utilities.i6t when I did a grep for DigitToValue. That may very well pay off in the future.

(As for leaving code in, I left a comment to myself in too! And sometimes I can learn stuff from debug code others left in.)

(Also, note this works great in 6L+, but for the ancient 6G, you need x - indexed text.)

I6 does have the idea of “characters”, pretty much exactly like chars in C (except by default using ZSCII instead of ASCII). The real difficulty is that I6 strings aren’t straight arrays of chars like in C (they’re compressed for efficiency), and I7 texts are another layer of complexity on top of this.

The main thing you can do with an I6 string or I7 text is print it, and there’s a way to print it into a C-style array in memory, at which point you can examine the characters individually. I would need to check the documentation, but it shouldn’t be too hard to whip something up that gives you “the value of character number N in T” as an int.

Here, I think this should do it.

Include Text Capture by Eric Eve.

To decide what number is the/-- value of character/char number/-- (N - a number) in the captured text: (- (captured_text --> (+N+) ) -).

Then capture your string using Text Capture’s API and get “the value of character number 2 in the captured text” as a number, to handle however you like. On Z-machine it’ll be ZSCII codes; on Glulx it’ll be Unicode codepoints.

Unfortunately it’s been long enough since I used Text Capture that I can’t figure out what version is compatible with my I7 so I haven’t been able to test this. If someone else can, it would be appreciated.

1 Like

I think this works:

Text number is a snippet that varies.

To decide what number is the numerical value of (T - a text):
	replace text number with T;
	if text number matches "[number]":
		decide on the number understood.
4 Likes

This is neat!

Unlikely to be important in most instances, but as written this code leaves the player’s command corrupted (the first word will be replaced by T)

The following modification avoids this by restoring the player’s command to its pristine state:

To decide what number is the numerical value of (T - a text):
	let n be a number;
	let txt be the substituted form of "[the player's command]";
	change the text of the player's command to T;
	if the player's command matches "[number]":
		let n be the number understood;
	change the text of the player's command to txt;
	decide on n.

EDIT: as written, this also returns 0 for a non-numeric text. An alternative would be to add

otherwise:
    let n be -9999; [or some other special value to flag a non-numeric text]

EDIT_2:

Or use a phrase to decide whether a text is numeric:

To decide whether (T - a text) is numeric:
	let n be a number;
	let txt be the substituted form of "[the player's command]";
	change the text of the player's command to T;
	if the player's command matches "[number]":
		change the text of the player's command to txt;
		decide yes;
	change the text of the player's command to txt;
	decide no.
2 Likes

Yes, that is certainly a consideration.

It seems strange to me that there is no easy way of checking whether a text matches a topic. There really should be. (But I guess what I’m really saying is that it should be easier to perform parsing operations on something which is not the player’s command.)

And this second one, it should be noted, leaves the result in “the number understood”. Which is a useful behavior—you can check if something is numeric and then get the result without any further parsing if it is—but also notably clobbers a global variable.

Hmm. Good points. I suppose one could also save and restore the number understood, in similar fashion to the player’s command.