--- a/ai.js Thu Sep 11 18:12:24 2014 +0300
+++ b/ai.js Thu Sep 11 19:22:04 2014 +0300
@@ -4,6 +4,19 @@
ai.dirs = ["up", "right", "down", "left"];
ai.canDirs = ["canUp", "canRight", "canDown", "canLeft"];
+/* Create empty 'to' if argument missing. */
+ai.copyObj = function(from, to) {
+ if (to == null || typeof to !== "object")
+ to = {};
+ if (from == null || typeof obj !== "object")
+ return to;
+ for (var attr in cfg) {
+ if (from.hasOwnProperty(attr))
+ to[attr] = from[attr];
+ }
+ return to;
+}
+
// 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.
@@ -109,60 +122,51 @@
////////////////////////////////////////////////////////////////
-// 1 level deep on max scores.
+// 1 step deep with linear weight function on score, max value,
+// bonuses for max value stay at corner or edge and bonuses
+// for each free field.
////////////////////////////////////////////////////////////////
-ai.nextMaxScore = function(brdEngine) {
+ai.oneStepDeep = function(brdEngine, cfg) {
this.brdEngine = brdEngine;
+ this.cfg = ai.copyObj(ai.oneStepDeep.bestCfg);
+ ai.copyObj(cfg, this.cfg);
}
-ai.nextMaxScore.prototype.analyse = function(brd) {
+ai.oneStepDeep.bestCfg = {scoreCoef: 1, maxValCoef: 0, cornerBonus: 0, edgeBonus: 0, freeBonus: 0};
+ai.oneStepDeep.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.oneStepDeep.prototype.analyse = function(brd) {
var origBrd = new this.brdEngine(brd);
var nextBrd = new this.brdEngine();
- 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)) {
- var score = nextBrd.score();
- if (maxScore < score) {
+ var weight = this.weight(nextBrd);
+ if (maxWeight < weight) {
bestDir = dir;
- maxScore = score;
+ maxWeight = weight;
}
}
}
return bestDir;
}
/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
-ai.nextMaxScore.prototype.cleanup = function() { }
-
-
-
-////////////////////////////////////////////////////////////////
-// 1 level deep on max value.
-////////////////////////////////////////////////////////////////
-
-ai.nextMaxValue = function(brdEngine) {
- this.brdEngine = brdEngine;
-}
-ai.nextMaxValue.prototype.analyse = function(brd) {
- var origBrd = new this.brdEngine(brd);
- var nextBrd = new this.brdEngine();
- var maxMax = -1;
- var bestDir;
- for (var i = 0; i < ai.dirs.length; i++) {
- var dir = ai.dirs[i];
- if (origBrd[dir](nextBrd)) {
- var max = nextBrd.score();
- if (maxMax < max) {
- maxMax = max;
- bestDir = dir;
- }
- }
- }
- return bestDir;
-}
-/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
-ai.nextMaxValue.prototype.cleanup = function() { }
+ai.oneStepDeep.prototype.cleanup = function() { }