Board Game Experiment, with JS Prototypes and Canvas

The Square Object

Constructor

Every Square owns coordinates on the board (a the “easting”, and b the “southing”).

Then for each one of them we want to know the paths : how long we got until the closest winning position for every pawn. So we can decide later on what’s the smartest move to make. What we’re calling paths are actually path lengths.

For every direction from this position, we’re either blocked by a fence (false), out of the board (false), getting to another square (a Square instance), or a pawn (a Player instance). That’s what the accesses are.

function Square(a, b) {
  'use strict';
  // The coordinates
  this.a = a;
  this.b = b;
  // Lengths of the shortest paths from this square to the closest winning position, for every players goals.
  this.paths = {
    up: b,
    right: game.size - a,
    down: game.size - b,
    left: a
  };
  // We'll need this property to make sure that we're not overriding any calculation currently made on this object
  this.token = false;
}

// This is still part of the construction process, but it can only be run once every square on the board exists.
Square.prototype.initAccess = function () {
  'use strict';
  // What do we access for every directions from this square
  this.access = {
    up: (this.b !== 0) ? game.board[this.a][this.b - 1] : false,
    right: (this.a !== game.size) ? game.board[this.a + 1][this.b] : false,
    down: (this.b !== game.size) ? game.board[this.a][this.b + 1] : false,
    left: (this.a !== 0) ? game.board[this.a - 1][this.b] : false
  };
};

The Path Finder

With those accesses, we can run the path finder : the core of our coming AI. This method will set every square’s shortest path length for a given direction (goal).

Square.prototype.pathFinder = function (goal, value) {
  'use strict';
  var move;
  if (!value) {
    // No value to set : we haven't found a way yet. So let's take that token and find it !
    this.token = true;
    // Is this a winning position ?
    if (this.paths[goal] === 0) {
      // Yep ! So the longest possible path length is "one" from the neighbouring positions.
      value = 1;
    } else {
      // Nope. Let's set the path to false, we need to reset it.
      this.paths[goal] = false;
    }
  } else {
    // We got a value here, let's set it.
    this.paths[goal] = value;
    // And logically, we add one to the neighbouring positions paths.
    value += 1;
  }
  // Then for every valid access (!== false)
  for (move in this.access) {
    if (this.access.hasOwnProperty(move) && this.access[move]) {
      // If the position is not already busy finding its way (token === false)
      if (!this.access[move].token) {
        // Get to work !
        this.access[move].pathFinder(goal, false);
      }
      // Ok now, if the longest possible path we found is either shorter or the only one we found so far for the position
      if (value && ((this.access[move].paths[goal] === false) || (this.access[move].paths[goal] > value))) {
        // Let's set it up !
        this.access[move].pathFinder(goal, value);
      }
    }
  }
};