Backporting code from I7 for speed: DWORDS, globals, byte shifting?

Hi,

I have some code that works in i6, here, but it’s ugly. The original code is in i7. It assigns every letter to a DWORD, then looks through the player’s command and adds that value to a number to create a hash. It’s pretty straightforward, but I wanted to see if I could speed things up with i6, because i7 using regexes or picking through the player’s command slow.

i7 code:

Table of Hashcodes
Letter(indexed text)	Code
"a"	2187818
"b"	18418905
"c"	19005585
"d"	21029089
"e"	127806109
"f"	26514896
"g"	32599702
"h"	37282299
"i"	44992846
"j"	48960525
"k"	52933178
"l"	53813839
"m"	64075153
"n"	68907508
"o"	74352577
"p"	81465959
"q"	84405617
"r"	85323803
"s"	96273966
"t"	103110018
"u"	105105807
"v"	107164820
"w"	107934773
"x"	112768081
"y"	122359252
"z"	122969618

to decide what indexed text is the filtered name of (t - a value of kind K):
	let s be t in lower case;
	replace the regular expression "<^abcdefghijklmnopqrstuvwxyz>" in s with "";	[ a-z would include accented characters]
	decide on s;

to decide what number is the hash of (t - a value of kind K):
	let s be the filtered name of t;
	let hash be 0;
	repeat with c running from 1 to the number of characters in s:
		increase hash by the Code corresponding to a Letter of character number c in s in the Table of Hashcodes;
	decide on hash;

i6 code:

include (-

Array hashvals --> (2187818) (18418905) (19005585) (21029089) (127806109) (26514896) (32599702) (37282299) (44992846) (48960525) (52933178) (53813839) (64075153) (68907508) (74352577) (81465959) (84405617) (85323803) (96273966) (103110018) (105105807) (107164820) (107934773) (112768081) (122359252) (122969618);

[
	i6hash firstword retval temp ix theidx;

	retval = 0;
	
	for (ix=0 : ix<buffer-->0 : ix++)
	{
		temp = buffer->(WORDSIZE+ix);
		if ((temp == 32) && (firstword == true))
		    return retval;
		if ((temp > 64) && (temp < 91)) { theidx = temp - 65; }
		else if ((temp > 96) && (temp < 123)) { theidx = temp - 97; }
		else continue;
		retval = retval + hashvals->(4*theidx+3);
		retval = retval + 256 * hashvals->(4*theidx+2);
		retval = retval + 65536 * hashvals->(4*theidx+1);
		retval = retval + 16777216 * hashvals->(4*theidx);
	}

	return retval;

];

-)

firstword is sent as a parameter, and it says, do we take the hash of the first word instead of the whole command?

Now, I’ve tested this code, and it basically works. But there are some things I’d like to tune up with my i6 code!

First, I’m wondering if there is a way to define an array of DWORDS instead of what my array is – an array of bytes, which necessitates the 256, 65536, etc. stuff.

Second, if that’s not possible, is there a way to do byte/bit shifting without 256, etc.? I tried <<8 but got a compiler error.

Third, I am relying on the global variable “buffer” being the player’s command. This seems to work, but it makes me uneasy. Is there a simple-stupid reason I shouldn’t worry?

Thanks to any and all who can help!

I gotta admit, I’m a bit confused by your terminology here… I’m assuming that by “DWORD” you mean a 32-bit number? I’m also assuming that this code targets Glulx because otherwise the compiler wouldn’t allow you to use numbers as large as in your example.

The size of an entry in an I6 --> array depends on what VM you’re compiling for: 16 bits on the Z-Machine, 32 bits on Glulx. So, on Glulx, the last four lines in your loop could just be:

retval = retval + hashvals-->theidx;
1 Like

In I6 arrays (whether defining or accessing), -> is for bytes, --> is for words.

1 Like

It is inelegant, but it is correct. buffer is always used for the player’s input.

There’s a buffer2 which is used for secondary inputs (like “player consents”), but the “reading a command” activity doesn’t run on those.

This looks like it’s really an I7 question at heart.

Here’s something that will let you define the hash table in I7 but get the speed you want from I6:

Hash Commands
To decide which number is the/-- hash value of player's command:
	(- I6Hash() -).

After reading a command:
	say "('[player's command]' hashes to: [hash value of player's command])[line break]".

To store (M - number) at position (N - number) of I6 hash table:
	(- hashvals-->{N} = {M}; -).

When play begins (this is the load I6 hash table rule):
	let N be 1;
	repeat through the Table of Hashcodes:
		store code entry at position N of I6 hash table;
		increment N.

[make sure rows are in the correct order!]
Table of Hashcodes
Letter(indexed text)	Code
"a"	2187818
"b"	18418905
"c"	19005585
"d"	21029089
"e"	127806109
"f"	26514896
"g"	32599702
"h"	37282299
"i"	44992846
"j"	48960525
"k"	52933178
"l"	53813839
"m"	64075153
"n"	68907508
"o"	74352577
"p"	81465959
"q"	84405617
"r"	85323803
"s"	96273966
"t"	103110018
"u"	105105807
"v"	107164820
"w"	107934773
"x"	112768081
"y"	122359252
"z"	122969618

Include (-

Array hashvals table 26;	! will be loaded from I7 table, so array size must match row count

[ I6Hash firstword buf      retval temp first_space_flag ix chrs loc theidx;

	if (buf == 0) buf = buffer;	! default to normal command input buffer
	retval = 0;
	#Ifdef TARGET_ZCODE; chrs=buf->1; #ifnot; chrs=buf-->0; #endif;
	loc = buf+WORDSIZE;
	
	for (ix=0 : ix<chrs : ix++)
	{
		temp = loc->ix;
		if (temp == ' ' && firstword == true) break;
		if ((temp >= 'A') && (temp <= 'Z')) { temp = temp+('a'-'A'); }
		if ((temp >= 'a') && (temp <= 'z')) { theidx = temp-'a'; }
		else continue;
		retval = retval + hashvals-->(theidx+1);
	}

	return retval;
];

-).
3 Likes