repiV, Perl is one of the things I've always wanted to do and never gotten around to. Perl may be evil, but it's a very seductive kind of evil.
Thanks for posting the snippet, I think it shows the power of Perl very well.
Jor , I have not yet written anything that translates hash values into nicknames. This is basically a database problem: scan all .ini files in the data tree for nicknames, hash them, and build a table indexed by hash. But I do have written something that is necessary for this: some compilable reference code for the hash function that FL uses.
The algorithm resembles a bit-reversed and byte-swapped (Big Endian) version of the standard CRC16, tweaked to yield more than 16 bits. The hash has effectively 28 bits instead of 30 because 2 bits are lost because of a programming error. This gives a theoretical collision threshold of 16384; IOW, it is unlikely that you can hash more than 16000 things without getting a collision. The actual threshold is probably lower because of the poly and the nature of the things to be hashed (lower-case letters instead of random byte values).
Here's the guts of the algorithm:
<pre><font size=1 face=Courier>
/* standard CRC16 polynomial */
#define FLHASH_POLYNOMIAL 0xA001ul
.
#define LOGICAL_BITS 30
#define PHYSICAL_BITS 32
#define SHIFTED_POLY (FLHASH_POLYNOMIAL << (LOGICAL_BITS - 16))
.
void InitFLHashContext (FLHashContext *ctx) {
DWORD i, bit;
for (i = 0; i < 256; i++) {
DWORD x = i;
for (bit = 0; bit < 8; bit++)
x = x & 1 ? (x >> 1) ^ SHIFTED_POLY : x >> 1;
ctx->lookup??(i??) = x; }
}
.
DWORD FLHash (FLHashContext const *ctx, char const *text, size_t length) {
DWORD hash = 0;
size_t i;
for (i = 0; i < length; i++)
hash = (hash >>
^ ctx->lookup[(BYTE)hash ^ (BYTE)tolower(text??(i??));
return (BSwap32(hash) >> (PHYSICAL_BITS - LOGICAL_BITS)) / 0x80000000ul;
}
</font></pre>
Note: I had to use the trigraphs ??( and ??) instead of square brackets, because the forum script tries to interpret things in square brackets.
The archive
FLHashReferenceCode.rar contains source code (FLHash.c, FLHash.h) that can be incorporated into C/C++ projects as is. You can also compile this into a stand-alone console program by defining the symbol STANDALONE_TEST. A Win32 console exe is included, with PGP signature.
The program is simple because its main purpose is to serve as a reference implementation. You can supply one or more nicknames on the command line and the program will print the hashes for them. Example:
<pre><font size=1 face=Courier>D:\dev\out\FL\FLHash> FLHash shield01_mark01_lf ge_fighter_power01
"shield01_mark01_lf", 3088051465, -1206915831, 0xb80fed09
"ge_fighter_power01", 2779996489, -1514970807, 0xa5b36149 </font></pre>
The program also contains a selftest, where the hash function is run against known hash/text pairs from InitialWorld.ini.
Have fun!
Edited by - Sherlog on 11-06-2003 23:58:33