# HG changeset patch # User Oleksandr Gavenko # Date 1411414541 -10800 # Node ID e3a91b336976d3a618e6f9bf23a0b69ebc578361 # Parent 6d5a9d8b00be5d2fc9e2e7c78bdce91fea60ad94 Join N level deep on score value without random simulation AIs and add parameter customisation. diff -r 6d5a9d8b00be -r e3a91b336976 2048.html --- 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 @@
-
+
-
deep merges without simulation make max score
-
-
- -
deep merges without simulation make max score + bonus if max value at corner/edge
+
deep merges without random simulation
+
+ score weight +
+
+ max value weight +
+
+ max value at corner bonus +
+
+ max value at edge bonus +
+
+ free cell coefficient +
+
+ score threshold +
+
@@ -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); diff -r 6d5a9d8b00be -r e3a91b336976 ai.js --- 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.