在 Javascript 中实现 Zobrist 散列

Posted

技术标签:

【中文标题】在 Javascript 中实现 Zobrist 散列【英文标题】:Implementing Zobrist hashing in Javascript 【发布时间】:2014-09-08 21:53:12 【问题描述】:

我需要在 javascript 中为国际象棋引擎实现 Zobrist 散列,我想知道实现这一点的最佳方法是什么。现在,我不是计算机科学家,也从来没有正式的算法和数据结构类,所以如果我在这方面有点偏离,我很抱歉......

据我了解,我需要一个 64 位散列函数来将位置编码为低于该位置的位置会引发太多冲突。现在在 javascript 中,我只能访问 32 位数字。还有一个问题是我如何实现哈希表以及它是如何由节点中的 V8 引擎“在幕后”实现的。

我可以将它作为长度为 TABLESIZE 的 javascript 数组,然后执行以下操作:

var table = new Array();

table[hashCodeLo % TABLESIZE] = 
    hashCodeLo: hashCodeLo,
    hashCodeHi: hashCodeHi,
    someProperty: someValue
;

其中 hashCodeLo 和 hashCodeHi 表示代码的高 32 位和低 32 位,TABLESIZE

var table = ;

table[hashCode] = 
    someProperty: someValue

这里的 hashCode 只是我的 64 位 hashCode 的字符串表示。由于我不确定“字典模式”如何在幕后工作,我不确定哪个更好。另外我不知道我是否通过使用“1983981918391”之类的键而不是更紧凑的表示形式来使用更多内存:

hashCode = String.fromCharCode(FIRST_16BITS, SECOND_16BITS, THIRD_16BITS, FOURTH_16BITS)

我什至不确定这是否符合我的预期......

由于这是引擎的关键部分,因此我希望尽可能多地发挥性能,因此不胜感激。

【问题讨论】:

你在哪个环境下运行 v8 怎么样? 【参考方案1】:

据我了解,我需要一个 64 位散列函数来将位置编码为低于该位置会引发太多冲突。

至少不适用于transposition table - 它几乎不会有 264 的大小。

如果您要实现此功能来对位置本身进行编码(并通过比较 64 位哈希来检测一些冲突),那么是的,如果这是文献推荐的,您可以使用 64 位(尽管您可能想尝试52 位也是如此)。

现在在 javascript 中我只能访问 32 位数字。

没有。 JavaScript 中的数字是 64 位浮点数,您最多可以在其中精确存储 52 位整数。只有位运算符仅限于 32 位整数(如有必要,数字将被强制转换为整数)。

但是,数组本身的长度限制为 232;但即使这样也应该绰绰有余。

还有一个问题是我如何实现哈希表以及它是如何由节点中的 V8 引擎“在幕后”实现的。

只需将其实现为数组。尝试用 null 值填充它以进行初始化,并查看非稀疏数组是否表现更好。如果您关心性能,请测试一下

hashCodeLo 和 hashCodeHi 分别表示代码的高低 32 位,TABLESIZE

我会使用 Uint32Array 而不是对象数组。根据somePropertysomeValue 是什么,您可能只想将对象的索引存储在普通数组或标量本身(可能使用DataView)中。代码可能如下所示:

var zobrist = new Uint32Array(13 * 2 * 64 * 2) // pieces * colors * fields * 64/32
for (var i=0; i<zobrist.length; i++)
    zobrist[i] = Math.random() * 4294967296;

var table = new Uint32Array(3 * tablesize);

function hash(hi, lo, piece, color, field) 
    hi ^= zobrist[piece * 128 + color * 64 + field];
    lo ^= zobrist[piece * 128 + color * 64 + field + 1];

    var i = lo % tablesize;
    if (table[i] == hi && table[i+1] == lo) 
        // collision
     else 
        table[i] = hi; table[i+1] = lo;
        // do what you want with table[i+2]
    

【讨论】:

>没有。你是怎么得出这个结论的?有超过 264 个可能的国际象棋位置,您几乎不会尝试存储(甚至枚举)它们。 这似乎是我读过的国际象棋文献中的共识。我知道有超过 2^64 个可能的国际象棋位置,但我再次需要 64 位的密钥来检测合理数量的碰撞。将完整位置存储在转置表中似乎很浪费,而且我还没有看到任何引擎可以做到这一点。通过将其减少到 64 位,我假设您在哈希表大小和未检测到的冲突数之间取得了不错的折衷。我没有对此进行数学计算,我只是按照其他人所做的... 啊,我现在看到您将使用散列来编码实际位置,而不仅仅是转置表索引。我认为 2^64 的哈希表大小会有点大……

以上是关于在 Javascript 中实现 Zobrist 散列的主要内容,如果未能解决你的问题,请参考以下文章

如何在 javascript 中实现 Random.nextDouble()?

如何在 JavaScript 中实现锁

在javascript中实现一个规则算法[关闭]

如何在 Wordpress 中实现 javascript

如何在javascript中实现区域/代码折叠

JavaScript 在JavaScript中实现Singleton模式的3种方法