Add Blind cycle AI. Add example of setting passing.
--- 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.
////////////////////////////////////////////////////////////////