GameLoop

Copyright(c) 2012 Stefano Balietti MIT Licensed

nodeGame container of game-state functions, and parameters


(function (exports, node) {
  

Global scope

var GameState = node.GameState,
  JSUS = node.JSUS;

exports.GameLoop = GameLoop;

GameLoop constructor

Creates a new instance of GameLoop

Takes as input parameter an object like

{ 1: { state: myFunc, rounds: numRounds, // optional, defaults 1 }, 2: { state: myNestedState, rounds: numRounds, // optional, defaults 1 },
// any arbitray number of state-objects is allowed }

From the above example, the value of the state property can be a function or a nested state object (with internal steps). For example

myFunc = function() {};

myNestedState = { 1: { state: myFunc2, } 2: { state: myFunc3, } }

Params
loop object Optional. An object containing the loop functions
function GameLoop (loop) {

Public variables

limits

Array containing the internal representation of the boundaries of each state inside the game-loop

API
private
  this.limits = []; 
  

GameLoop.loop

The transformed loop container

  this.loop = loop || {};

  for (var key in this.loop) {
    if (this.loop.hasOwnProperty(key)) {
      

Transform the loop obj if necessary. When a state executes only one step, it is allowed to pass directly the name of the function. So such function must be incapsulated in a obj here.

      var loop = this.loop[key].state;
      if ('function' === typeof loop) {
        var o = JSUS.clone(this.loop[key]);
        this.loop[key].state = {1: o};
      }
      
      var steps = JSUS.size(this.loop[key].state)
      
      var round = this.loop[key].rounds || 1;
      this.limits.push({rounds: round, steps: steps});
    }
  }
  

GameLoop.length

The total number of states + steps in the game-loop

Warning: may not be working in old browsers. Use #size() instead

See
GameLoop.size()
  if (node.support.getter) {
    Object.defineProperty(this, 'length', {
        set: function(){},
        get: this.size,
        configurable: true
    });
  }
  else {
    this.length = null;
  }
  
}

GameLoop methods

GameLoop.size

Returns the total number of states + steps in the game-loop

GameLoop.prototype.size = function() {
  if (!this.limits.length) return 0;
  return this.steps2Go(new GameState());
};

GameLoop.exist

Returns TRUE, if a gameState exists in the game-loop

Params
gameState GameState The game-state to check
GameLoop.prototype.exist = function (gameState) {
  if (!gameState) return false;
  gameState = new GameState(gameState);
  
  if (typeof(this.loop[gameState.state]) === 'undefined') {
    node.log('Unexisting state: ' + gameState.state, 'WARN');
    return false;
  }
  
  if (typeof(this.loop[gameState.state]['state'][gameState.step]) === 'undefined'){
    node.log('Unexisting step: ' + gameState.step, 'WARN');
    return false;
  }

States are 1 based, arrays are 0-based => -1

  if (gameState.round > this.limits[gameState.state-1]['rounds']) {
    node.log('Unexisting round: ' + gameState.round + 'Max round: ' + this.limits[gameState.state]['rounds'], 'WARN');
    return false;
  }
    
  return true;
};

GameLoop.next

Returns the next state in the loop

An optional input parameter can control the state from which to compute the next state

Params
gameState GameState Optional. The reference game-state. Defaults, node.game.state
Returns
GameState boolean The next game-state, or FALSE if it does not exist
GameLoop.prototype.next = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  

Game has not started yet, do it!

  if (gameState.state === 0) {
    return new GameState({
               state: 1,
               step: 1,
               round: 1
    });
  }
  
  if (!this.exist(gameState)) {
    node.log('No next state of non-existing state: ' + gameState, 'WARN');
    return false;
  }
  
  var idxLimit = Number(gameState.state)-1; // 0 vs 1 based
  
  if (this.limits[idxLimit]['steps'] > gameState.step){
    var newStep = Number(gameState.step)+1;
    return new GameState({
      state: gameState.state,
      step: newStep,
      round: gameState.round
    });
  }
  
  if (this.limits[idxLimit]['rounds'] > gameState.round){
    var newRound = Number(gameState.round)+1;
    return new GameState({
      state: gameState.state,
      step: 1,
      round: newRound
    });
  }
  
  if (this.limits.length > gameState.state){    
    var newState = Number(gameState.state)+1;
    return new GameState({
      state: newState,
      step: 1,
      round: 1
    });
  }
  

No next state: game over

  return false; 
};

GameLoop.previous

Returns the previous state in the loop

An optional input parameter can control the state from which to compute the previous state

Params
gameState GameState Optional. The reference game-state. Defaults, node.game.state
Returns
GameState boolean The previous game-state, or FALSE if it does not exist
GameLoop.prototype.previous = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  
  if (!this.exist(gameState)) {
    node.log('No previous state of non-existing state: ' + gameState, 'WARN');
  }
  
  var idxLimit = Number(gameState.state)-1; // 0 vs 1 based
  
  if (gameState.step > 1){
    var oldStep = Number(gameState.step)-1;
    return new GameState({
      state: gameState.state,
      step: oldStep,
      round: gameState.round
    });
  }
  else if (gameState.round > 1){
    var oldRound = Number(gameState.round)-1;
    var oldStep = this.limits[idxLimit]['steps'];
    return new GameState({
      state: gameState.state,
      step: oldStep,
      round: oldRound
    });
  }
  else if (gameState.state > 1){
    var oldRound = this.limits[idxLimit-1]['rounds'];
    var oldStep = this.limits[idxLimit-1]['steps'];
    var oldState = idxLimit;
    return new GameState({
      state: oldState,
      step: oldStep,
      round: oldRound
    });
  }
  

game init

  return false; 
};

GameLoop.getName

Returns the name associated with a game-state

Params
gameState GameState Optional. The reference game-state. Defaults, node.game.state
Returns
string boolean The name of the game-state, or FALSE if state does not exists
GameLoop.prototype.getName = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  if (!this.exist(gameState)) return false;
  return this.loop[gameState.state]['state'][gameState.step]['name'];
};

GameLoop.getFunction

Returns the function associated with a game-state

Params
gameState GameState The reference game-state
Returns
object boolean The function of the game-state, or FALSE if state does not exists
GameLoop.prototype.getFunction = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  if (!this.exist(gameState)) return false;
  return this.loop[gameState.state]['state'][gameState.step]['state'];
};

GameLoop.getAllParams

Returns all the parameters associated with a game-state

Params
gameState GameState The reference game-state
Returns
object boolean The state object, or FALSE if state does not exists
GameLoop.prototype.getAllParams = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  if (!this.exist(gameState)) return false;
  return this.loop[gameState.state]['state'][gameState.step];
};

GameLoop.jumpTo

Returns a state N steps away from the reference state

A negative value for N jumps backward in the game-loop, and a positive one jumps forward in the game-loop

Params
gameState GameState The reference game-state
N number The number of steps to jump
Returns
GameState boolean The "jumped-to" game-state, or FALSE if it does not exist
GameLoop.prototype.jumpTo = function (gameState, N) {
  if (!this.exist(gameState)) return false;
  if (!N) return gameState;
  
  var func = (N > 0) ? this.next : this.previous;
  
  for (var i=0; i < Math.abs(N); i++) {
    gameState = func.call(this, gameState);
    if (!gameState) return false;
  }
  return gameState;
};

GameLoop.steps2Go

Computes the total number steps left to the end of the game.

An optional input parameter can control the starting state for the computation

Params
gameState GameState Optional. The reference game-state. Defaults, node.game.state
Returns
number The total number of steps left
GameLoop.prototype.steps2Go = function (gameState) {
  gameState = (gameState) ? new GameState(gameState) : node.game.state;
  var count = 0;
  while (gameState) { 
    count++;
    gameState = this.next(gameState);
  }
  return count;
};

GameLoop.prototype.toArray = function() {
  var state = new GameState();
  var out = [];
  while (state) { 
    out.push(state.toString());
    var state = this.next(state);
  }
  return out;
};

GameLoop.indexOf

Returns the ordinal position of a state in the game-loop

All steps and rounds in between are counted.

Params
gameState GameState The reference game-state
Returns
number The state index in the loop, or -1 if it does not exist @see GameLoop.diff
GameLoop.prototype.indexOf = function (state) {
  if (!state) return -1;
  return this.diff(state, new GameState());
};

GameLoop.diff

Returns the distance in steps between two states in the game-loop

All steps and rounds in between are counted.

It works under the assumption that state1 comes first than state2 in the game-loop.

Params
state1 GameState The reference game-state
state2 GameState Optional. The second state for comparison. Defaults node.game.state
Returns
number The state index in the loop, or -1 if it does not exist
GameLoop.prototype.diff = function (state1, state2) {
  if (!state1) return false;
  state1 = new GameState(state1) ;
  
  if (!state2) {
    if (!node.game.state) return false;
    state2 = node.game.state
  }
  else {
    state2 = new GameState(state2) ;
  }
  
  
  var idx = 0;
  while (state2) {
    if (GameState.compare(state1, state2) === 0){
      return idx;
    }
    state2 = this.next(state2);
    idx++;
  }
  return -1;
};
  

Closure

})(
  'undefined' != typeof node ? node : module.exports
  , 'undefined' != typeof node ? node : module.parent.exports
);