Make fast board cache.
--- a/ai.js Thu Sep 25 01:10:01 2014 +0300
+++ b/ai.js Thu Sep 25 02:05:48 2014 +0300
@@ -22,6 +22,28 @@
return to;
}
+ai.brdCache = function() {
+ this.cache = [];
+}
+ai.brdCache.prototype.get = function(brd) {
+ var compr = brd.compress();
+ var subCache = this.cache[compr[0]];
+ if (subCache) {
+ return subCache[compr[1]];
+ }
+ return undefined;
+}
+ai.brdCache.prototype.put = function(brd, val) {
+ var compr = brd.compress();
+ var subCache = this.cache[compr[0]];
+ if (subCache) {
+ subCache[compr[1]] = val;
+ } else {
+ this.cache[compr[0]] = [];
+ this.cache[compr[0]][compr[1]] = val;
+ }
+}
+
// Each strategy is a function that except current board position as 2d array and context from
// previous call to share state/precomputed values between calls.
@@ -343,6 +365,7 @@
return score;
}
ai.expectimax.prototype.analyse = function(brd) {
+ this.brdCache = new ai.brdCache();
var origBrd = new this.brdEngine(brd);
var nextBrd = new this.brdEngine();
var maxW = -1;
@@ -368,15 +391,9 @@
ai.expectimax.prototype.evalFn = function(brd, depth) {
if (depth >= this.depthLimit)
return this.weight(brd);
- if (this.cache[depth]) {
- var cache = this.cache[depth];
- for (var i = cache.length-1; i >= 0; i--) {
- if (brd.equals(cache[i].brd))
- return cache[i].weight;
- }
- } else {
- this.cache[depth] = [];
- }
+ var wCached = this.brdCache.get(brd);
+ if (wCached)
+ return wCached;
var wMin = +Infinity;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
@@ -402,11 +419,10 @@
}
}
}
- this.cache[depth].push({brd: brd, weight: wMin});
+ this.brdCache.put(brd, wMin);
return wMin;
}
/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
ai.expectimax.prototype.cleanup = function() {
- this.cache = [];
}
--- a/board.js Thu Sep 25 01:10:01 2014 +0300
+++ b/board.js Thu Sep 25 02:05:48 2014 +0300
@@ -119,6 +119,26 @@
}
/** Compare boards. */
BoardArr2d.prototype.equals = BoardArr2d.prototype.equals_unrolled;
+BoardArr2d.prototype.compress = function() {
+ var brd = this.brd;
+ var h1 = brd[0][0];
+ h1 = (h1 << 4) | brd[0][1];
+ h1 = (h1 << 4) | brd[0][2];
+ h1 = (h1 << 4) | brd[0][3];
+ h1 = (h1 << 4) | brd[1][0];
+ h1 = (h1 << 4) | brd[1][1];
+ h1 = (h1 << 4) | brd[1][2];
+ h1 = (h1 << 4) | brd[1][3];
+ var h2 = brd[2][0];
+ h2 = (h2 << 4) | brd[2][1];
+ h2 = (h2 << 4) | brd[2][2];
+ h2 = (h2 << 4) | brd[2][3];
+ h2 = (h2 << 4) | brd[3][0];
+ h2 = (h2 << 4) | brd[3][1];
+ h2 = (h2 << 4) | brd[3][2];
+ h2 = (h2 << 4) | brd[3][3];
+ return [h1, h2];
+}
/* Return and optionally fill 2d board. */
BoardArr2d.prototype.exportTo = function(brd) {
@@ -812,6 +832,26 @@
&& self.db == brd.db && self.dc == brd.dc
&& self.bb == brd.bb && self.bc == brd.bc && self.cb == brd.cb && self.cc == brd.cc;
};
+BoardObj.prototype.compress = function() {
+ var brd = this.brd;
+ var h1 = brd.aa;
+ h1 = (h1 << 4) | brd.ab;
+ h1 = (h1 << 4) | brd.ac;
+ h1 = (h1 << 4) | brd.ad;
+ h1 = (h1 << 4) | brd.ba;
+ h1 = (h1 << 4) | brd.bb;
+ h1 = (h1 << 4) | brd.bc;
+ h1 = (h1 << 4) | brd.bd;
+ var h2 = brd.ca;
+ h2 = (h2 << 4) | brd.cb;
+ h2 = (h2 << 4) | brd.cc;
+ h2 = (h2 << 4) | brd.cd;
+ h2 = (h2 << 4) | brd.da;
+ h2 = (h2 << 4) | brd.db;
+ h2 = (h2 << 4) | brd.dc;
+ h2 = (h2 << 4) | brd.dd;
+ return [h1, h2];
+}
BoardObj.prototype.copy = function(brd) {
var self = this.brd;
if ( ! brd) {