Join N level deep on score value without random simulation AIs and add
authorOleksandr Gavenko <gavenkoa@gmail.com>
Mon, 22 Sep 2014 22:35:41 +0300
changeset 110 e3a91b336976
parent 109 6d5a9d8b00be
child 111 7b9d1bb9c471
Join N level deep on score value without random simulation AIs and add parameter customisation.
2048.html
ai.js
--- a/2048.html	Mon Sep 22 01:44:48 2014 +0300
+++ b/2048.html	Mon Sep 22 22:35:41 2014 +0300
@@ -235,13 +235,28 @@
         </div>
         <div class="clearfix"></div>
       </div>
-      <div class="ai" id="ai-deep-max-score">
+      <div class="ai" id="ai-static-deep-merges">
         <button class="ai">enable</button>
-        <h5>deep merges without simulation make max score</h5>
-      </div>
-      <div class="ai" id="ai-deep-max-score-corner">
-        <button class="ai">enable</button>
-        <h5>deep merges without simulation make max score + bonus if max value at corner/edge</h5>
+        <h5>deep merges without random simulation</h5>
+        <div class="option">
+          <input type="text" name="scoreCoef" class="positive" pattern="[0-9]*[.]?[0-9]*" value="1"/> score weight
+        </div>
+        <div class="option">
+          <input type="text" name="maxValCoef" class="positive" pattern="[0-9]*[.]?[0-9]*" value="0"/> max value weight
+        </div>
+        <div class="option">
+          <input type="text" name="cornerBonus" class="positive" pattern="[0-9]*[.]?[0-9]*" value="100"/> max value at corner bonus
+        </div>
+        <div class="option">
+          <input type="text" name="edgeBonus" class="positive" pattern="[0-9]*[.]?[0-9]*" value="0"/> max value at edge bonus
+        </div>
+        <div class="option">
+          <input type="text" name="freeBonus" class="positive" pattern="[0-9]*[.]?[0-9]*" value="10"/> free cell coefficient
+        </div>
+        <div class="option">
+          <input type="text" name="weightThreshold" class="positive" pattern="[0-9]*[.]?[0-9]*" value="10"/> score threshold
+        </div>
+        <div class="clearfix"></div>
       </div>
       <div class="ai" id="ai-expectimax">
         <button class="ai">enable</button>
@@ -732,11 +747,9 @@
         var cfg = ui.ai.parseCfg(aiDom);
         return new ai.OneStepAhead(ui.brdEngine, cfg);
       },
-      "ai-deep-max-score": function() {
-        return new ai.DeepMaxScore(ui.brdEngine);
-      },
-      "ai-deep-max-score-corner": function() {
-        return new ai.DeepMaxScoreCorner(ui.brdEngine);
+      "ai-static-deep-merges": function(aiDom) {
+        var cfg = ui.ai.parseCfg(aiDom);
+        return new ai.StaticDeepMerges(ui.brdEngine, cfg);
       },
       "ai-expectimax": function(aiDom) {
         var cfg = ui.ai.parseCfg(aiDom);
--- a/ai.js	Mon Sep 22 01:44:48 2014 +0300
+++ b/ai.js	Mon Sep 22 22:35:41 2014 +0300
@@ -159,7 +159,7 @@
  * @property {number} maxValCoef   multiplicator for max value
  * @property {number} cornerBonus  bonus for max value at board corner
  * @property {number} edgeBonus    bonus for max value at board edge
- * @property {number} freeBonus    bonus foe each free cell
+ * @property {number} freeBonus    bonus for each free cell
  */
 
 /** 1 step deep with * AI.
@@ -213,151 +213,85 @@
 // N level deep on score value without random simulation.
 ////////////////////////////////////////////////////////////////
 
-/** N level deep on score value without random simulation.
+/**
+ * Defines coefficient for linear resulted weight function.
+ * @name ai.StaticDeepMerges.cfg
+ * @namespace
+ * @property {number} scoreCoef    multiplicator for score
+ * @property {number} maxValCoef   multiplicator for max value
+ * @property {number} cornerBonus  bonus for max value at board corner
+ * @property {number} edgeBonus    bonus for max value at board edge
+ * @property {number} freeBonus    bonus for each free cell
+ */
+
+/** Deep merges AI without random simulation.
  * @param {Board} brdEngine  board engine from board.js
+ * @param {Object} cfg  configuration settings
  * @constructor */
-ai.DeepMaxScore = function(brdEngine) {
+ai.StaticDeepMerges = function(brdEngine, cfg) {
     this.brdEngine = brdEngine;
+    this.cfg = ai.copyObj(ai.OneStepAhead.bestCfg);
+    ai.copyObj(cfg, this.cfg);
 }
-ai.DeepMaxScore.prototype.analyse = function(brd) {
+ai.StaticDeepMerges.bestCfg = {scoreCoef: 1, maxValCoef: 0, cornerBonus: 0, edgeBonus: 0, freeBonus: 0, weightThreshold: 10};
+ai.StaticDeepMerges.prototype.weight = function(brd) {
+    var weight = 0;
+    if (this.cfg.scoreCoef > 0)
+        weight += this.cfg.scoreCoef * brd.score();
+    var max = brd.max();
+    if (this.cfg.maxValCoef > 0)
+        weight += this.cfg.maxValCoef * max;
+    if (this.cfg.cornerBonus > 0 && brd.atCorner(max))
+        weight += this.cfg.cornerBonus;
+    if (this.cfg.edgeBonus > 0 && brd.atEdge(max))
+        weight += this.cfg.edgeBonus;
+    if (this.cfg.freeBonus > 0)
+        weight += this.cfg.freeBonus * brd.free();
+    return weight;
+}
+ai.StaticDeepMerges.prototype.analyse = function(brd) {
     var origBrd = new this.brdEngine(brd);
     var nextBrd = new this.brdEngine();
     var prevScore = -1, nextScore = -1;
-    var maxScore = -1;
+    var maxWeight = -1;
     var bestDir;
     for (var i = 0; i < ai.dirs.length; i++) {
         var dir = ai.dirs[i];
         if (origBrd[dir](nextBrd)) {
-            nextScore = nextBrd.score();
-            var score = this.evalFn(nextBrd);
-            // console.log("dir: %o, prevScore: %o, nextScore: %o, maxScore: %o, score: %o", dir, prevScore, nextScore, maxScore, score);
-            if (maxScore < score || (maxScore === score && prevScore < nextScore)) {
+            var weight = this.evalFn(nextBrd);
+            var ok = (weight - maxWeight) > this.cfg.weightPriority;
+            if ( ! ok && maxWeight <= weight) {
+                nextScore = this.weight(nextBrd);
+                ok = prevScore < nextScore;
+            }
+            if (ok) {
                 prevScore = nextScore;
-                maxScore = score;
+                maxWeight = weight;
                 bestDir = dir;
             }
         }
     }
     return bestDir;
 }
-ai.DeepMaxScore.prototype.evalFn = function(brd, seenBrds) {
-    if (seenBrds) {
-        for (var i = 0; i < seenBrds.length; i++)
-            if (brd.equals(seenBrds[i]))
-                return 0;
-    } else {
-        seenBrds = [];
-    }
-    seenBrds.push(brd);
+ai.StaticDeepMerges.prototype.evalFn = function(brd) {
     var currScore = brd.score();
-    var maxScore = currScore;
+    var maxWeight = currScore;
     var nextBrd = new this.brdEngine();
     for (var i = 0; i < ai.dirs.length; i++) {
         if (brd[ai.dirs[i]](nextBrd)) {
             var score = nextBrd.score();
             if (score > currScore)
-                maxScore = Math.max(maxScore, this.evalFn(nextBrd, seenBrds));
+                maxWeight = Math.max(maxWeight, this.evalFn(nextBrd));
         }
     }
-    return maxScore;
+    return maxWeight;
 }
 /* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
-ai.DeepMaxScore.prototype.cleanup = function() { }
+ai.StaticDeepMerges.prototype.cleanup = function() { }
 
 
 
 ////////////////////////////////////////////////////////////////
-// N level deep on score value + max value prefer corner,
-// without random simulation.
-////////////////////////////////////////////////////////////////
-
-/**
- * Defines coefficient for linear resulted weight function.
- * @name ai.DeepMaxScoreCorner.cfg
- * @namespace
- * @property {number} scoreCoef    multiplicator for score
- * @property {number} maxValCoef   multiplicator for max value
- * @property {number} cornerBonus  bonus for max value at board corner
- * @property {number} edgeBonus    bonus for max value at board edge
- * @property {number} freeBonus    bonus foe each free cell
- */
-
-/** N level deep AI without random simulation.
- * @param {Board} brdEngine  board engine from board.js
- * @param {Object} cfg  configuration settings
- * @constructor */
-ai.DeepMaxScoreCorner = function(brdEngine, cfg) {
-    this.brdEngine = brdEngine;
-    this.cfg = cfg || {};
-    this.cfg.cornerBonus = this.cfg.cornerBonus || 20000;
-    this.cfg.edgeBonus = this.cfg.edgeBonus || 100;
-    this.cfg.freeBonus = this.cfg.edgeBonus || 100;
-}
-ai.DeepMaxScoreCorner.prototype.scoreCorner = 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;
-    return score;
-}
-ai.DeepMaxScoreCorner.prototype.scoreEdge = function(brd) {
-    var score = brd.score();
-    var max = brd.max();
-    if (brd.atEdge(max))
-        score += this.cfg.edgeBonus;
-    score += brd.free() * this.cfg.freeBonus;
-    return score;
-}
-ai.DeepMaxScoreCorner.prototype.analyse = function(brd) {
-    var origBrd = new this.brdEngine(brd);
-    var nextBrd = new this.brdEngine();
-    var prevScore = -1, nextScore = -1;
-    var maxScore = -1;
-    var bestDir;
-    for (var i = 0; i < ai.dirs.length; i++) {
-        var dir = ai.dirs[i];
-        if (origBrd[dir](nextBrd)) {
-            nextScore = this.scoreCorner(nextBrd);
-            var score = this.evalFn(nextBrd);
-            // console.log("dir: %o, prevScore: %o, nextScore: %o, maxScore: %o, score: %o", dir, prevScore, nextScore, maxScore, score);
-            if (maxScore < score || (maxScore === score && prevScore < nextScore)) {
-                prevScore = nextScore;
-                maxScore = score;
-                bestDir = dir;
-            }
-        }
-    }
-    return bestDir;
-}
-ai.DeepMaxScoreCorner.prototype.evalFn = function(brd, seenBrds) {
-    if (seenBrds) {
-        for (var i = 0; i < seenBrds.length; i++)
-            if (brd.equals(seenBrds[i]))
-                return 0;
-    } else {
-        seenBrds = [];
-    }
-    seenBrds.push(brd);
-    var currScore = this.scoreEdge(brd);
-    var maxScore = currScore;
-    var nextBrd = new this.brdEngine();
-    for (var i = 0; i < ai.dirs.length; i++) {
-        if (brd[ai.dirs[i]](nextBrd)) {
-            var score = this.scoreEdge(nextBrd);
-            if (score > currScore)
-                maxScore = Math.max(maxScore, this.evalFn(nextBrd, seenBrds));
-        }
-    }
-    return maxScore;
-}
-/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
-ai.DeepMaxScoreCorner.prototype.cleanup = function() { }
-
-
-////////////////////////////////////////////////////////////////
 // N level deep with random simulation.
 ////////////////////////////////////////////////////////////////
 
@@ -369,7 +303,7 @@
  * @property {number} maxValCoef   multiplicator for max value
  * @property {number} cornerBonus  bonus for max value at board corner
  * @property {number} edgeBonus    bonus for max value at board edge
- * @property {number} freeBonus    bonus foe each free cell
+ * @property {number} freeBonus    bonus for each free cell
  */
 
 /** N level deep with random simulation.