Add detecting value at edge or corner, free cell count. Added AI that count
max value at edges or corner and free cell count.
--- a/2048.html Mon Sep 08 02:04:16 2014 +0300
+++ b/2048.html Mon Sep 08 17:43:10 2014 +0300
@@ -88,6 +88,7 @@
<button id="ai-next-max-score">next max score</button>
<button id="ai-next-max-value">next max value</button>
<button id="ai-deep-max-score">deep max score</button>
+ <button id="ai-deep-max-score-corner">deep max score corner</button>
</div>
</div>
@@ -354,6 +355,9 @@
document.getElementById("ai-deep-max-score").addEventListener("click", function() {
ui.ai = new ai.deepMaxScore(ui.brdEngine);
});
+ document.getElementById("ai-deep-max-score-corner").addEventListener("click", function() {
+ ui.ai = new ai.deepMaxScoreCorner(ui.brdEngine);
+ });
</script>
--- a/ai.js Mon Sep 08 02:04:16 2014 +0300
+++ b/ai.js Mon Sep 08 17:43:10 2014 +0300
@@ -137,3 +137,81 @@
/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
ai.deepMaxScore.prototype.cleanup = function() { }
+
+////////////////////////////////////////////////////////////////
+// N level deep on score value + max value prefer corner,
+// without random simulation.
+////////////////////////////////////////////////////////////////
+
+/* cfg.cornerBonus - value to add if max value at corner. */
+/* cfg.edgeBonus - value to add if max value at edge. */
+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.bestScore(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.bestScore = 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.bestScore(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() { }
+
--- a/board.js Mon Sep 08 02:04:16 2014 +0300
+++ b/board.js Mon Sep 08 17:43:10 2014 +0300
@@ -81,6 +81,14 @@
brd.brd[i][j] = this.brd[i][j];
return brd;
}
+BoardArr2d.prototype.free = function() {
+ var cnt = 0;
+ for (var i = 0; i < 4; i++)
+ for (var j = 0; j < 4; j++)
+ if (this.brd[i][j] === 0)
+ cnt++;
+ return cnt;
+}
BoardArr2d.prototype.score = function() {
var score = 0;
for (var i = 0; i < 4; i++) {
@@ -101,6 +109,27 @@
}
return max;
}
+BoardArr2d.prototype.find = function(val) {
+ var xy = [];
+ for (var i = 0; i < 4; i++) {
+ for (var j = 0; j < 4; j++) {
+ if (this.brd[i][j] === val)
+ xy.push([i,j]);
+ }
+ }
+ return xy;
+}
+BoardArr2d.prototype.atEdge = function(val) {
+ var brd = this.brd;
+ return (brd[0][0] === val) || (brd[0][1] === val) || (brd[0][2] === val) || (brd[0][3] === val)
+ || (brd[1][0] === val) || (brd[1][3] === val)
+ || (brd[2][0] === val) || (brd[2][3] === val)
+ || (brd[3][0] === val) || (brd[3][1] === val) || (brd[3][2] === val) || (brd[3][3] === val);
+}
+BoardArr2d.prototype.atCorner = function(val) {
+ var brd = this.brd;
+ return (brd[0][0] === val) || (brd[0][3] === val) || (brd[3][0] === val) || (brd[3][3] === val);
+}
BoardArr2d.prototype.canRight = function() {
for (var i = 0; i < 4; i++) {