JavaScript goal oriented

In this graphic example with Canvas we will see how a simple function turns JavaScript into a goal-oriented programming language.

The example shows a car moving on a road to a destination, the goal. The easiest programming principle is to define the goal as an expression and place the action that tends toward this goal in an iteration.

Demonstration

The goal is to let the car move to the right edge of the frame.

JavaScript code

var car = new Image();
car.src="images/car-green.png";

var roadCanvas = document.getElementById("road");
var roadCtx = roadCanvas.getContext("2d");

function scenery() {
  roadCtx.fillStyle="white";
  roadCtx.rect(0,0,640,160);
  roadCtx.fill();
}

var xcar= 0;

car.onload=function() {
  roadCtx.drawImage(car, xcar, 60);
}	

var carInterval;
var stopFlag=false;
function startCar() {
  carInterval = setInterval(function() {
    scenery();
    roadCtx.drawImage(car, xcar, 60);
    xcar++;
    if(xcar >= 400 || stopFlag) {
      clearInterval(carInterval);
      return true;
    }	
  }, 20); 
}

HTML code

<input type="button" value="Go" onClick="stopFlag=false;startCar()">
<input type="button" value="Stop" onClick="stopFlag=true">

Optionally you can add a time constraint and in this case we are simply trying to get closer to the goal. But it becomes more difficult to manage, especially if multiple objects must be animated simultaneously.

However, goal-oriented programming will make things very simple. We define a "goal" function with these arguments:

  1. The condition to fulfill the goal.
  2. A maximum delay.
  3. And action to be performed iteratively to approach the goal.

Goal-oriented demonstration

Source code for the "goal" function

var stopDuo=false;
var goal = function(condi, dur, actio) { 
    var iter = setInterval(function() {
      if(condi() || stopDuo) {
        clearInterval(iter); 
        clearTimeout(limiter);
        return;
      }
      actio();
    }, 0);
    if(dur == "&") dur = 2147483647;
    var limiter=setTimeout(function() { clearInterval(iter); }, dur);
}

JavaScript code of the animation

var orange = new Image();
orange.src="images/car-orange.png";

var green = new Image();
green.src="images/car-green.png";

var raceCanvas = document.getElementById("race");
var raceCtx = raceCanvas.getContext("2d");

var xgreen = 0;
var xorange = 0 ;

green.onload=function() {
  raceCtx.drawImage(green, xgreen, 220);
}

orange.onload=function() {
  raceCtx.drawImage(orange, xorange, 60);
}

function redraw() 
{
  raceCtx.fillStyle="white";
  raceCtx.rect(0,0,640,320);
  raceCtx.fill();
  raceCtx.drawImage(orange, xorange, 60);
  raceCtx.drawImage(green, xgreen, 220);
}

function startDuo() {
 goal( function() { return (xorange >= 400); }, "&", function() {
    redraw();
    xorange++;
 });
 goal( function() { return(xgreen >= 400); }, "&", function() {
    redraw();
    xgreen+=2;
 });
}

HTML code

<input type="button" value="Go" onClick="stopDuo=false;startDuo()">
<input type="button" value="Stop" onClick="stopDuo=true;">

As you may see, this works asynchronously. Both cars move forward together, independently of one another. It is possible also to define a goal function acting synchronously:

var goalSync=function(condi, dur, actio) { 
  stopFlag = false;
  if(dur == "&") dur = 2147483647;
  var limiter=setTimeout(function() { stopFlag=true; }, dur);
  while(stopFlag == false) {
    if(condi()) {
      clearTimeout(limiter);
      stopFlag=true;
      return;
    }
    actio();
  }
}

In this case the two cars would move one after the other.

The two goal functions are part of the framework scriptol.js used by the Scriptol-JavaScript compiler. The language has a simpler syntax for implementing the goal orientation.