the other dell

Introduction - Probability & Non-uniform distributions

Random Number Distribution

The tutorial doesn’t directly invite play with the Processing version of the random number distribution graph, and so it seems a little odd to recreate it as-is in JavaScript. However, I want to get my head around using the Canvas for data-visualisation as well as simulation, making this totally relevant.

Frames

I decided to begin modularising the code. I’ve created a namespace called Frames and given it a couple of useful functions (just the setupCanvas and a clearContext methods). It also, internally, keeps a hold of the drawing context. I did this simply to begin the idea of a helper module for the code. It’ll mutate over time. This is almost certainly premature.

var Frames = ( function () {
	var context;

	//
	// helper functions
	//
	function setupCanvas(width, height) {
		var canvas = document.createElement( 'canvas' );

		context = canvas.getContext( '2d' );

		canvas.width = width || window.innerWidth;
		canvas.height = width || window.innerHeight;
		document.body.appendChild( canvas );

		return context;
	}

	function clearContext () {
		context.clearRect( 0, 0, context.canvas.width, context.canvas.height );
	}

	return {
		setupCanvas: setupCanvas,
		clearContext: clearContext
	};
})();

Probability

Exercise i.1 Down and to the right

I’d already read ahead through the chapter so I didn’t think about this too hard. The solution which came to mind first was to compose an array of uneven amounts of 1s and -1s, in the constructor.

Each call to step(), two variables are created containing a random pick from this uneven distribution of step possibilities. These variables are then added, one each to the Walker’s x and y co-ordinate. Because the array of modifiers has more 1s than -1s, the walker tends to walk down and right more often.

class Walker {
  int x;
  int y;

  int[] directions;

  Walker() {
    x = width/2;
    y = height/2;

    directions = new int[10];
    directions[0] = -1;
    directions[1] = -1;
    directions[2] = -1;
    directions[3] = -1;
    directions[4] =  1;
    directions[5] =  1;
    directions[6] =  1;
    directions[7] =  1;
    directions[8] =  1;
    directions[9] =  1;
  }

  void display() {
    stroke(0);
    point(x,y);
  }

  void step() {
    int stepx = directions[ int(random(10)) ];
    int stepy = directions[ int(random(10)) ];
    x += stepx;
    y += stepy;
  }
}

In JavaScript

Something I came across by chance (because I was rushing and being a little “sloppy”) is that I got a better result using and array of length 9, rather than one of length 10. The bias seemed gentler this way.

Walker.prototype.step = function () {
	var bias = [-1, -1, -1, -1, 1, 1, 1, 1, 1 ];
	var stepX = bias[ parseInt( Math.random() * 9, 10 ) ];
	var stepY = bias[ parseInt( Math.random() * 9, 10 ) ];

	this.x += stepX;
	this.y += stepY;

	return this;
}

The rest of the code for this is the same as for the last Walker example, so I’ve not included it here.

Exercise i.2 Aces

What is the probability of drawing two aces in a row from a > deck of fifty-two cards?

There are two versions of this question:

1. if the first ace is replaced in the deck

The probability is calculated as follows:

4 / 52 * 4 / 52 = 0.00591715976331361

2. if the first ace is left out of the deck

The probability is calculated as follows:

4 / 52 * 3 / 51 = 0.004524886877828055

It seems more difficult to pull two aces from the deck if first ace is removed from play after it’s drawn.

Exercise i.3 Dynamic random walking

Create a random walker with dynamic probabilities. For example, can you give it a 50% chance of moving in the direction of the mouse?

The preceding text had suggested using testing a random number against values as a way to divide up the chances into ranges.

In Processing

I misread the instruction as “30%” rather than “50%”, so my solution checks against 0.3 rather than 0.5.

void step() {
  float r = random(1);
  int choice = int(random(4));

  if (mousePressed && r < 0.2) {
    x += mouseX < x? -1: 1;
    y += mouseY < y? -1: 1;
    return;
  }

  if (choice == 0) {
    x++;
  } else if (choice == 1) {
    x--;
  } else if (choice == 2) {
    y++;
  } else {
    y--;
  }
}

Processing will hold the value of mouseX (and mouseY) after the mouse has left the Processing window. I added the test for mousePressed so the user has to hold a mouse button down in order to get the walker to (30%) walk towards the cursor.

I find the terseness of the ternary conditional really appealing here.

I felt that the walker moved towards the mouse pointer too quickly to show the effect as “bias” rather than “typical behavior”. Changing the proportion of occurances of following the bias to 20% showed the effect off better, to me.

In JavaScript

Initially I followed the suggestion from the exercise directly: make the walker walk towards the mouse pointer, 50% of the time. I added the feature that this only happens when a mouse button is clicked.

Firstly, I copied the Frames namespace over from the Random Number Distribution graph. Then I added “private” variables and accessors to the closure for tracking mouse position and button state. I realised that in doing this I had begun to replicate the Processing API, and poorly. There already exists an implementation of the environment and API for JavaScript. There’s no need to copy it, and even less need to copy it badly.

var Frames = ( function () {
	var mouseX = 0 ;
	var mouseY = 0;
	var mousePressed = false;
	var context;

	function setMouseXY ( event ) {
		mouseX = event.pageX;
		mouseY = event.pageY;
	}

	function setMousePressedTrue ( event ) {
		mousePressed = true;
	}

	function setMousePressedFalse ( event ) {
		mousePressed = false;
	}

	//
	// helper functions
	//
	function setupCanvas(width, height) {
		var canvas = document.createElement( 'canvas' );

		context = canvas.getContext( '2d' );

		canvas.width = width || window.innerWidth;
		canvas.height = width || window.innerHeight;
		document.body.appendChild( canvas );

		canvas.addEventListener( 'mouseenter', setMouseXY );
		canvas.addEventListener( 'mousemove', setMouseXY );
		canvas.addEventListener( 'mousedown', setMousePressedTrue );
		canvas.addEventListener( 'mouseup', setMousePressedFalse );

		return context;
	}

	function clearCanvas () {
		context.clearRect( 0, 0, context.canvas.width, context.canvas.height );
	}

	return {
		setupCanvas: setupCanvas,
		clearCanvas: clearCanvas,
		mouseX: function getMouseX () { return mouseX || 0; },
		mouseY: function getMouseY () { return mouseY || 0; },
		mousePressed: function getMousePressed () { return mousePressed; }
	};
})();

Second, I created a function which returns random integers from within a range:

function randomInt ( max ) {
	if( max == 0 ) throw 'randomInt() cannot accept 0 for its max value';
	if( max == undefined ) max = 1;

	return parseInt( Math.random() * max, 10 );
}

I had been writing parseInt( Math.random() * foo, 10 ); (where foo is the upper bound of the range) several times during the examples and exercises. The equivalent code in Processing is neater and I wanted an equivalent. It’s not added to the Frames namespace because it’s too generic even for that.

Lastly, I reimplemented the Walker.step() to behave pretty much how my Processing implementation works. The JS one has the benefit of being the second version, and is neater as a result.

Walker.prototype.step = function () {
	var random = Math.random();
	var choice = randomInt( 4 );

	if( Frames.mousePressed() && random < 0.2 ) {
		this.x += Frames.mouseX() < this.x? -1: 1;
		this.y += Frames.mouseY() < this.y? -1: 1;
	} else {
		switch( choice ) {
			case 0: this.x++; break;
			case 1: this.x--; break;
			case 2: this.y++; break;
			case 3: this.y--; break;
		}
	}

	return this;
}

One of the things I like about the Processing API is that the environment properties are variables and “just there”. If the user wants to know where the mouse is, they use mouseX and mouseY. These variables are “live”, constantly updated (within contraints). There is no need to respond to an event, nor to call an accessor method. On the one hand this goes against the “don’t use globals” recommendation, but on the other hand, it’s a very simple, pleasing API feature. Frames, internally, needs to respond to mouse events to update the values of its internal properties (I assume Processing does this behind the scenes), but it currently only provides access to the values via accessors, like Frames.mouseX(). This isn’t as friendly as Processing. I suppose there are a few ways around this but I’m trying to do things quickly and to refine the details incrementally. This has made me want to understand functional ractive programming better (although there are non-frp solutions too).