Board Game Experiment, with JS Prototypes and Canvas

The Computer Player

This is the user’s opponent object. This other child of player has to decide by itself of its best actions. There are plenty of things to improve for sure, but we’ll get a basic AI able to play against our user.

function Computer(i, base, limit) {
  'use strict';
  this.name = 'Computer';
  // Call the parent constructor
  Player.call(this, i, base, limit);
}
// Inherit Player
Computer.prototype = Object.create(Player.prototype);

The opponent

First of all, we need to decide which player is our main opponent. This is mostly for the four players game configuration.

Computer.prototype.getOpponent = function () {
  'use strict';
  var i, opponent = false, path, oppPath;
  for (i = 0; i < game.players.length; i += 1) {
    path = game.players[i].getPath();
    // Is the path of that player the shortest ? Or randomly if equal :
    if ((this.i !== i) && (!opponent || (path < oppPath) || ((path === oppPath) && (Math.random() > 0.5)))) {
      opponent = game.players[i];
      oppPath = path;
    }
  }
  // Return the opponent with the shortest way to his goal line
  return opponent;
};

Determining the advantage

The difference we get with this function is this computer‘s path length minus its opponent one : the lower it is, the closer it gets to win. So for a negative result, we have the advantage, and for a positive one, our opponent has it.

Computer.prototype.getDifference = function (opponent) {
  'use strict';
  // Return the difference between this Player's path and the given opponent's path
  return (this.getPath() - opponent.getPath());
};

Get a smart fence

What we’re basically doing here is to try every possible fence, and return the one that gets us the lowest difference.

It is only planning one action forward, but for a smarter AI we could extend this method to compute several moves ahead.

Computer.prototype.getFence = function () {
  'use strict';
  var a, b, opponent = this.getOpponent(), difference = this.getDifference(opponent), newDif, fence = false, span;
  // If we cannot put any other fence, no need to continue
  if ((this.limit === 0) || (difference < 0)) { return false; }
  // For each position on board
  for (a = 0; a < game.size; a += 1) {
    for (b = 0; b < game.size; b += 1) {
      // We set a fence object.
      span = {a: a, b: b, horizontal: true};
      // Get the difference of path length for a valid potential object
      newDif = game.validFence(span, 1, opponent);
      if ((newDif !== false) && (newDif < difference)) {
        // That fence is valid and giving us the advantage
        difference = newDif;
        fence = jQuery.extend({}, span);
      }
      // Let's rotate and try again on the vertical axis.
      span.horizontal = false;
      newDif = game.validFence(span, 1, opponent);
      if ((newDif !== false) && (newDif < difference)) {
        difference = newDif;
        fence = jQuery.extend({}, span);
      }
    }
  }
  // Return the more advantageous fence, or false if we didn't set any
  return fence;
};

Now be smart

This function plays a smart fence if we found any. Otherwise, it moves the computer’s pawn to the accessible square with the shortest path to its goal line.

Computer.prototype.play = function () {
  'use strict';
  var action = this.getFence();
  if (action) {
    // We found a fence to put.
    this.putUp(action);
  } else {
    action = this.getAccess();
    // Let's move to the next position
    this.move(action);
  }
};