Add Blind cycle AI. Add example of setting passing.
authorOleksandr Gavenko <gavenkoa@gmail.com>
Tue, 09 Sep 2014 19:37:44 +0300
changeset 27 8f96d09a4d94
parent 26 fba85224a8f0
child 28 caf0be6d7e68
Add Blind cycle AI. Add example of setting passing.
2048.html
ai.js
--- a/2048.html	Tue Sep 09 18:45:26 2014 +0300
+++ b/2048.html	Tue Sep 09 19:37:44 2014 +0300
@@ -11,6 +11,9 @@
   <script src="ai.js"></script>
 
   <style>
+    body {
+      font-size: 11pt;
+    }
     h1, div.area {
       text-align: center;
       margin: 10px auto;
@@ -39,13 +42,21 @@
       background-color: wheat;
     }
     div.ai > h5 {
-      margin: 2px 0;
+      margin: 2px 0 2px 6em;
     }
     button.ai {
       position: absolute;
       left: 1em;
       top: -1em;
     }
+    div.ai > div.option {
+      display: inline-block;
+      float: left;
+      margin: 1px 4px;
+    }
+    .clearfix {
+      clear: both;
+    }
   </style>
 </head>
 <body>
@@ -103,9 +114,16 @@
         <button class="ai">enable</button>
         <h5>bling random</h5>
       </div>
-      <div class="ai" id="ai-next-max-score">
+      <div class="ai" id="ai-blind-cycle">
         <button class="ai">enable</button>
-        <h5>next merge makes max score</h5>
+        <h5>blind cycle</h5>
+        <div class="option">
+          <input type="checkbox" name="clockwise"/> clockwise
+        </div>
+        <div class="option">
+          <input type="checkbox" name="whilePossible"/> max move in one direction
+        </div>
+        <div class="clearfix"></div>
       </div>
       <div class="ai" id="ai-next-max-value">
         <button class="ai">enable</button>
@@ -381,6 +399,12 @@
       "ai-random": function() {
         return new ai.random(ui.brdEngine);
       },
+      "ai-blind-cycle": function(aiDom) {
+        var cfg = {};
+        cfg.clockwise = aiDom.querySelectorAll("input[name='clockwise']")[0].checked;
+        cfg.whilePossible = aiDom.querySelectorAll("input[name='whilePossible']")[0].checked;
+        return new ai.blindCycle(ui.brdEngine, cfg);
+      },
       "ai-next-max-score": function() {
         return new ai.nextMaxScore(ui.brdEngine);
       },
@@ -419,9 +443,8 @@
     ui.ai.enable = function(aiDom) {
       if (ui.ai.current)
         ui.ai.current.cleanup();
-      var ai = ui.ai.algList[aiDom.id];
       ui.ai.moveToTop(aiDom);
-      ui.ai.current = ai();
+      ui.ai.current = ui.ai.algList[aiDom.id](aiDom);
     }
 
     ui.brdEngine = BoardArr2d; // TODO make user selectable
--- a/ai.js	Tue Sep 09 18:45:26 2014 +0300
+++ b/ai.js	Tue Sep 09 19:37:44 2014 +0300
@@ -2,6 +2,7 @@
 
 var ai = {};
 ai.dirs = ["up", "down", "left", "right"];
+ai.canDirs = ["canUp", "canDown", "canLeft", "canRight"];
 
 // 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.
@@ -29,6 +30,43 @@
 
 
 ////////////////////////////////////////////////////////////////
+// Blind cycle AI.
+////////////////////////////////////////////////////////////////
+
+ai.blindCycle = function(brdEngine, cfg) {
+    this.brdEngine = brdEngine;
+    this.cfg = cfg || {};
+    this.cfg.untilPossible = this.cfg.untilPossible || false;
+    this.cfg.clockwise = this.cfg.clockwise || false;
+}
+ai.blindCycle.dirs = ["left", "down", "right", "up"];
+ai.blindCycle.canDirs = ["canLeft", "canDown", "canRight", "canUp"];
+ai.blindCycle.prototype.nextDir = function(dir) {
+    if (this.cfg.clockwise)
+        return (dir + (4-1)) % 4;
+    else
+        return (dir + 1) % 4;
+}
+ai.blindCycle.prototype.analyse = function(brd) {
+    var origBrd = new this.brdEngine(brd);
+    this.prevDir = this.prevDir || 0;
+    if (!this.cfg.untilPossible)
+        this.prevDir = this.nextDir(this.prevDir);
+    console.log(this.prevDir);
+    while (true) {
+        if (origBrd[ai.blindCycle.canDirs[this.prevDir]]())
+            return ai.blindCycle.dirs[this.prevDir];
+        this.prevDir = this.nextDir(this.prevDir);
+    }
+}
+/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
+ai.blindCycle.prototype.cleanup = function() {
+    delete this.prevDir;
+}
+
+
+
+////////////////////////////////////////////////////////////////
 // 1 level deep on max scores.
 ////////////////////////////////////////////////////////////////