# HG changeset patch # User Oleksandr Gavenko # Date 1410989981 -10800 # Node ID 93cb48b73b39cbf7754c572a225add1989156ce1 # Parent a50828ac954d241aef22d6215d3b67a60eb48246 Enable config for expectimax. Fix weight function for expectimax. diff -r a50828ac954d -r 93cb48b73b39 2048.html --- a/2048.html Wed Sep 17 23:30:02 2014 +0300 +++ b/2048.html Thu Sep 18 00:39:41 2014 +0300 @@ -103,6 +103,9 @@ border: 1px solid green; padding: 2px; } + table.report-by-maxval > tr > td:nth-child(3) { + background-color: yellow; + } @@ -231,6 +234,28 @@
expectimax
+
+ recursion depth +
+
+ probability of 2 +
+
+ score weight +
+
+ max value weight +
+
+ max value at corner bonus +
+
+ max value at edge bonus +
+
+ free cell coefficient +
+
@@ -624,8 +649,10 @@ "ai-deep-max-score-corner": function() { return new ai.DeepMaxScoreCorner(ui.brdEngine); }, - "ai-expectimax": function() { - return new ai.expectimax(ui.brdEngine); + "ai-expectimax": function(aiDom) { + var cfg = {}; + ui.ai.parseCfg(aiDom, cfg); + return new ai.expectimax(ui.brdEngine, cfg); }, // "": function() { // return new ai.(ui.brdEngine); diff -r a50828ac954d -r 93cb48b73b39 ai.js --- a/ai.js Wed Sep 17 23:30:02 2014 +0300 +++ b/ai.js Thu Sep 18 00:39:41 2014 +0300 @@ -378,33 +378,31 @@ * @constructor */ ai.expectimax = function(brdEngine, cfg) { this.brdEngine = brdEngine; - this.cfg = cfg || {}; - this.cfg.balance = this.cfg.balance || .9; + this.cfg = ai.copyObj(ai.expectimax.bestCfg); + ai.copyObj(cfg, this.cfg); + if (this.cfg.balance <= 0) + this.cfg.balance = ai.expectimax.bestCfg.balance; + if ( this.cfg.balance > 1) + this.cfg.balance = 1; if (!this.cfg.depth || this.cfg.depth < 0 || 8 <= this.cfg.depth) - this.cfg.depth = 5; - this.cfg.cornerBonus = this.cfg.cornerBonus || 20000; - this.cfg.edgeBonus = this.cfg.edgeBonus || 100; - this.cfg.freeBonus = this.cfg.edgeBonus || 100; - this.cfg.weightPriority = this.cfg.weightPriority || 10; + this.cfg.depth = ai.expectimax.bestCfg.depth; } -ai.expectimax.prototype.lvl1Score = function(brd) { - var score = brd.score(); +ai.expectimax.bestCfg = {balance: .9, depth: 3, scoreCoef: 1, maxValCoef: 0, cornerBonus: 0, edgeBonus: 0, freeBonus: 0, weightPriority: 10}; +ai.expectimax.prototype.weight = function(brd) { + var score = 0; + if (this.cfg.scoreCoef > 0) + score += this.cfg.scoreCoef * brd.score(); var max = brd.max(); - if (brd.atCorner(max)) - score += this.cfg.cornerBonus; - else if (brd.atEdge(max)) - score += this.cfg.edgeBonus; - score += brd.free() * this.cfg.freeBonus; - return score; -} -ai.expectimax.prototype.lvlnScore = function(brd) { - var score = brd.score(); - // var max = brd.max(); - // if (brd.atCorner(max)) - // score += this.cfg.cornerBonus; - // else if (brd.atEdge(max)) - // score += this.cfg.edgeBonus; - // score += brd.free() * this.cfg.freeBonus; + if (this.cfg.maxValCoef > 0) + score += this.cfg.maxValCoef * max; + if (this.cfg.cornerBonus > 0) + if (brd.atCorner(max)) + score += this.cfg.cornerBonus; + if (this.cfg.edgeBonus > 0) + if (brd.atEdge(max)) + score += this.cfg.edgeBonus; + if (this.cfg.freeBonus > 0) + score += this.cfg.freeBonus * brd.free(); return score; } ai.expectimax.prototype.analyse = function(brd) { @@ -417,10 +415,13 @@ for (var i = 0; i < ai.dirs.length; i++) { var dir = ai.dirs[i]; if (origBrd[dir](nextBrd)) { - nextScore = this.lvl1Score(nextBrd); - var weight = this.weight(nextBrd, 0); - // console.log("dir: %o, prevScore: %o, nextScore: %o, maxWeight: %o, weight: %o", dir, prevScore, nextScore, maxWeight, weight); - if (maxWeight + this.cfg.weightPriority < weight || (maxWeight <= weight && prevScore < nextScore)) { + var weight = this.recWeight(nextBrd, 1); + var ok = (weight - maxWeight) > this.cfg.weightPriority; + if ( ! ok && maxWeight <= weight) { + nextScore = this.weight(nextBrd); + ok = prevScore < nextScore; + } + if (ok) { prevScore = nextScore; maxWeight = weight; bestDir = dir; @@ -430,9 +431,9 @@ this.cleanup(); return bestDir; } -ai.expectimax.prototype.weight = function(brd, depth) { - if (depth === this.cfg.depth) - return this.lvlnScore(brd); +ai.expectimax.prototype.recWeight = function(brd, depth) { + if (depth >= this.cfg.depth) + return this.weight(brd); if (this.cache[depth]) { var cache = this.cache[depth]; for (var i = cache.length-1; i >= 0; i--) { @@ -453,24 +454,26 @@ var n = 0, w = 0; for (var diri = 0; diri < ai.dirs.length; diri++) { if (randBoard[ai.dirs[diri]](nextBrd)) { - w += this.weight(nextBrd, depth+1); + w += this.recWeight(nextBrd, depth+1); n++; } } if (n > 0) w = w / n; weight += this.cfg.balance * w; - randBoard.set(i, j, 2); - var n = 0, w = 0; - for (var diri = 0; diri < ai.dirs.length; diri++) { - if (randBoard[ai.dirs[diri]](nextBrd)) { - w += this.weight(nextBrd, depth+1); - n++; + if (this.cfg.balance < 1) { + randBoard.set(i, j, 2); + var n = 0, w = 0; + for (var diri = 0; diri < ai.dirs.length; diri++) { + if (randBoard[ai.dirs[diri]](nextBrd)) { + w += this.recWeight(nextBrd, depth+1); + n++; + } } + if (n > 0) + w = w / n; + weight += this.cfg.balance * w; } - if (n > 0) - w = w / n; - weight += this.cfg.balance * w; free++; } }