AI: Survive as long as possible.
authorOleksandr Gavenko <gavenkoa@gmail.com>
Sun, 19 Oct 2014 01:13:42 +0300
changeset 155 1f8df90bd338
parent 154 c6d9b84d9391
child 156 e6a4bc888b72
AI: Survive as long as possible.
2048.html
ai.js
--- a/2048.html	Sun Oct 19 01:04:19 2014 +0300
+++ b/2048.html	Sun Oct 19 01:13:42 2014 +0300
@@ -281,6 +281,16 @@
           <input type="text" name="freeBonus" class="positive" pattern="[0-9]*[.]?[0-9]*" value="10"/> free cell coefficient
         </div>
       </div>
+      <div class="ai wide control" id="ai-survive">
+        <button class="ai">enable</button>
+        <h5>survive</h5>
+        <div class="option">
+          <input type="text" name="maxDepth" class="positive" pattern="[0-9]*" value="5"/> depth
+        </div>
+        <div class="option">
+          <input type="text" name="freeCells" class="positive" pattern="[1-9][0-9]?" value="8"/> free cells
+        </div>
+      </div>
     </div>
   </div>
 
@@ -785,6 +795,10 @@
         var cfg = ui.ai.parseCfg(aiDom);
         return new ai.expectimax(ui.brdEngine, cfg);
       },
+      "ai-survive": function(aiDom) {
+        var cfg = ui.ai.parseCfg(aiDom);
+        return new ai.survive(ui.brdEngine, cfg);
+      },
       // "": function() {
       //   return new ai.(ui.brdEngine);
       // },
--- a/ai.js	Sun Oct 19 01:04:19 2014 +0300
+++ b/ai.js	Sun Oct 19 01:13:42 2014 +0300
@@ -435,3 +435,99 @@
 ai.expectimax.prototype.cleanup = function() {
 }
 
+
+
+////////////////////////////////////////////////////////////////
+// Survive as long as possible.
+////////////////////////////////////////////////////////////////
+
+/**
+ * Defines coefficient for linear resulted weight function.
+ * @name ai.survive.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
+ */
+
+/** N level deep with random simulation.
+ * @param {Board} brdEngine  board engine from board.js
+ * @param {ai.survive.cfg} cfg  configuration settings
+ * @constructor */
+ai.survive = function(brdEngine, cfg) {
+    this.brdEngine = brdEngine;
+    this.cfg = ai.copyObj(ai.survive.bestCfg);
+    ai.copyObj(cfg, this.cfg);
+    if (this.cfg.freeCells <= 0)
+        this.cfg.freeCells = ai.survive.bestCfg.freeCells;
+    if (!this.cfg.maxDepth || this.cfg.maxDepth < 0 || 20 <= this.cfg.maxDepth)
+        this.cfg.maxDepth = ai.survive.bestCfg.maxDepth;
+    this.cfg.altAI = new ai.StaticDeepMerges(brdEngine, ai.survive.altAICfg);
+}
+ai.survive.bestCfg = {freeCells: 8, maxDepth: 5};
+ai.survive.altAICfg = {scoreCoef: 1, maxValCoef: 0, cornerBonus: 0, edgeBonus: 0, freeBonus: 0, weightThreshold: 0};
+/** Select best direction for next step. */
+ai.survive.prototype.analyse = function(brd2d) {
+    var origBrd = new this.brdEngine(brd2d);
+    var nextBrd = new this.brdEngine();
+    var bestW = -1;
+    var bestDir;
+    var freeCnt = origBrd.freeCnt();
+    if (freeCnt >= this.cfg.freeCells)
+        return this.cfg.altAI.analyse(brd2d);
+    for (var i = 0; i < ai.dirs.length; i++) {
+        var dir = ai.dirs[i];
+        if (origBrd[dir](nextBrd)) {
+            var w = this.evalFn(nextBrd, 1);
+            console.log("dir: %s, w: %d", dir, w);
+            if (w > bestW) {
+                bestW = w;
+                bestDir = dir;
+            }
+        }
+    }
+    return bestDir;
+}
+ai.survive.prototype.evalFn = function(brd, depth) {
+    if (brd.freeCnt() >= this.cfg.freeCells)
+        return 1;
+    if (depth >= this.cfg.maxDepth)
+        return 0;
+    var wMin = +Infinity;
+    var randBoard = new this.brdEngine();
+    var nextBrd = new this.brdEngine();
+exit:
+    for (var i = 0; i < 3; i++) {
+        for (var j = 0; j < 3; j++) {
+            if (brd.get(i, j) !== 0)
+                continue;
+            brd.copy(randBoard);
+            randBoard.set(i, j, 1);
+            var wMax = -1;
+            for (var diri = 0; diri < ai.dirs.length; diri++) {
+                if (randBoard[ai.dirs[diri]](nextBrd)) {
+                    var w = this.evalFn(nextBrd, depth+1);
+                    if (w === 1) {
+                        wMax = 1;
+                        break;
+                    }
+                    wMax = Math.max(wMax, w);
+                }
+            }
+            if (wMax === -1) {
+                wMin = -1;
+                break exit;
+            }
+            wMin = Math.min(wMin, wMax);
+        }
+    }
+    if (wMin === +Infinity)
+        return -1;
+    return wMin;
+}
+/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
+ai.survive.prototype.cleanup = function() {
+}
+