ai.js
author Oleksandr Gavenko <gavenkoa@gmail.com>
Mon, 08 Sep 2014 00:18:13 +0300
changeset 16 ab283d2534db
parent 14 9b49e710f5a7
child 18 42d62e5123b2
permissions -rw-r--r--
Fix typo.

"use strict";

var ai = {};

// 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.



////////////////////////////////////////////////////////////////
// Random AI.
////////////////////////////////////////////////////////////////

ai.random = function(brdEngine) {
    this.brdEngine = brdEngine;
}
ai.random.prototype.analyse = function(brd) {
    var origBrd = new this.brdEngine(brd);
    while (true) {
        var rnd = Math.floor(Math.random()*4);
        if (origBrd[["canUp", "canDown", "canLeft", "canRight"][rnd]]())
            return ["up", "down", "left", "right"][rnd];
    }
}
/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
ai.random.prototype.cleanup = function() { }



////////////////////////////////////////////////////////////////
// 1 level deep on max scores.
////////////////////////////////////////////////////////////////

ai.nextMaxScore = function(brdEngine) {
    this.brdEngine = brdEngine;
}
ai.nextMaxScore.prototype.analyse = function(brd) {
    var origBrd = new this.brdEngine(brd);
    var nextBrd = new this.brdEngine();
    var maxScore = -1;
    var action;
    if (origBrd.up(nextBrd)) {
        maxScore = nextBrd.score();
        action = "up";
    }
    if (origBrd.left(nextBrd)) {
        var score = nextBrd.score();
        if (maxScore < score) {
            action = "left";
            maxScore = score;
        }
    }
    if (origBrd.down(nextBrd)) {
        var score = nextBrd.score();
        if (maxScore < score) {
            action = "down";
            maxScore = score;
        }
    }
    if (origBrd.right(nextBrd)) {
        var score = nextBrd.score();
        if (maxScore < score) {
            action = "right";
            maxScore = score;
        }
    }
    return action;
}
/* 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 action;
    if (origBrd.up(nextBrd)) {
        maxMax = nextBrd.max();
        action = "up";
    }
    if (origBrd.left(nextBrd)) {
        var max = nextBrd.score();
        if (maxMax < max) {
            action = "left";
            maxMax = max;
        }
    }
    if (origBrd.down(nextBrd)) {
        var max = nextBrd.max();
        if (maxMax < max) {
            action = "down";
            maxMax = max;
        }
    }
    if (origBrd.right(nextBrd)) {
        var max = nextBrd.max();
        if (maxMax < max) {
            action = "right";
            maxMax = max;
        }
    }
    return action;
}
/* Mark that next board will be unrelated to previous, so any stored precompution can be cleared. */
ai.nextMaxScore.prototype.cleanup = function() { }


////////////////////////////////////////////////////////////////
// N level deep on score value without random.
////////////////////////////////////////////////////////////////

ai.deepMaxScore = function(brdEngine) {
    this.brdEngine = brdEngine;
}
ai.deepMaxScore.prototype.analyse = function(brd) {
    var origBrd = new this.brdEngine(brd);
    var nextBrd = new this.brdEngine();
    var maxScore = -1;
    var action;
    if (origBrd.up(nextBrd)) {
        maxScore = this.bestScore(nextBrd);
        action = "up";
    }
    if (origBrd.left(nextBrd)) {
        var score = this.bestScore(nextBrd);
        if (maxScore < score) {
            action = "left";
            maxScore = score;
        }
    }
    if (origBrd.down(nextBrd)) {
        var score = this.bestScore(nextBrd);
        if (maxScore < score) {
            action = "down";
            maxScore = score;
        }
    }
    if (origBrd.right(nextBrd)) {
        var score = this.bestScore(nextBrd);
        if (maxScore < score) {
            action = "right";
            maxScore = score;
        }
    }
    return action;
}
ai.deepMaxScore.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 maxScore = brd.score();
    var nextBrd = new this.brdEngine();
    if (brd.up(nextBrd))
        maxScore = Math.max(maxScore, this.bestScore(nextBrd, seenBrds) - 1);
    if (brd.down(nextBrd))
        maxScore = Math.max(maxScore, this.bestScore(nextBrd, seenBrds) - 1);
    if (brd.left(nextBrd))
        maxScore = Math.max(maxScore, this.bestScore(nextBrd, seenBrds) - 1);
    if (brd.right(nextBrd))
        maxScore = Math.max(maxScore, this.bestScore(nextBrd, seenBrds) - 1);
    return maxScore;
}