Zielony Smok - logo witryny

Ruch drogowy Nagela – Schreckenberga

O automatach komórkowych możesz przeczytać w rozdziale 24 książki Matematyka dla programistów Java oraz w rozdziale 21 książki Matematyka dla programistów JavaScript.

Strona używa skryptu nagel.js

Zawartość możesz zobaczyć w
przeglądarce obsługującej element <canvas>
z kontekstem "2d"


Listing

var nagel = new Nagel();
timer = setInterval("nagel.runs()", 500);
            

Skrypt nagel.js

var cv = document.getElementById('canvas');
var ctx = cv.getContext('2d');
var width = cv.width;
var height = cv.height;
var w = 800;
var h = 80;
var liczbaPol = 100;
var szer = 8;
var len = szer * liczbaPol;
var params = 2;// predkosc, kolor
var timer;
var kolory = [ "#000000", "#0000FF", "#00FFFF", "#C0C0C0", "#008000",
		"#808080", "#800000", "#FF0000", "#FF00FF", "#008080" ];
function Nagel() {
	this.autos1 = [];
	this.autos2 = [];
	for (var i = 0; i < liczbaPol; i++) {
		this.autos1[i] = [];
		this.autos2[i] = [];
	}
	this.clear();
};
Nagel.prototype.runs = function(){
	this.autos2 = this.clone(this.autos1);
	//przegladamy wszystkie komorki zaczynajac od ostatniej
	for(var i = liczbaPol - 1; i >= 0; i--){
		var speed = 0;
		var dist = 0;
		//sprawdzamy czy komorka jest zajeta czy nie
		if(this.autos2[i][0] != -1){
			//jesli tak zapisujemy predkosc
			speed = this.autos2[i][0];
			//sprawdzamy liczbe pustych kratek przed samochodem
			//czyli odleglosc od poprzedzającego samochodu
			for(var j = i + 1; j < liczbaPol; j++){
				//jesli kratka jest wolna
				if(this.autos2[j][0] == -1){
					//zwiekszamy dystans
					dist++;
				}
				//jesli jest zajeta - przerywamy zliczanie
				//dystansu
				else{
					break;
				}
			}
			//jesli samochod ma zbyt duza szybkosc w stosunku
			//do odleglosci - zmniejszamy szybkosc
			if(dist < speed){
				speed = dist;
			}
			//albo jesli samochod ma wolna odleglosc, a nie
			//ma maksynmalnej szybkosc - podnosimy szybkosc 0 1
			else if((dist > speed) && (speed < 5)){
				speed++;
			}
			//wprowadzamy czynnik rozpraszający kierowcę
			//co powoduje hamowanie

			var rand1 = Math.random();
			if(rand1 < 0.3){
				if(speed > 0){
					speed--;
				}
			}
			//jesli szybkosc jest wieksza od zero
			//przestawiamy samochod do przodu
			if((speed > 0) && (i + speed < 99)){
				this.autos2[i + speed][0] = speed;
				this.autos2[i + speed][1] = this.autos2[i][1];
				this.autos2[i][0] = -1;
				this.autos2[i][1] = -1;
			}
			else{
				this.autos2[i][0] = -1;
				this.autos2[i][1] = -1;
			}
		}
	}
	//indeks komórki tablicy zawierającej ostatni samochód;
	//jeśli w tablicy nie ma zadnego samochodu indeks bedzie
	//mial wartosc 100;
	var index = 100;
	for(var m = 0; m < liczbaPol; m++){
		if(this.autos2[m][0] != -1){
			index = m;
			break;
		}
	}
	//jesli w pierwszej komorce od lewej nie ma samochodu
	var x;
	if(index > 0){
		x = Math.random();
		if(x < 0.7){
			//
			//int s = Math.min(index, 5);
			var s = 1;
			var c = this.randomInRange(0, 9);
			this.autos2[0][0] = s;
			this.autos2[0][1] = c;
			//System.out.println(index + " " + s + " " + c);
		}
	}
	//-
	this.autos1 = this.clone(this.autos2);
	this.drawNagel();
};
Nagel.prototype.drawNagel = function(){
	ctx.save();
	ctx.beginPath();
	ctx.fillStyle = "#FFFFFF";
	ctx.rect(0, 0, w, h);
	ctx.fill();
	ctx.beginPath();
	ctx.lineWidth=0.5;
	ctx.strokeStyle="#a3a3a3";
	var z = 0;
	ctx.moveTo(0, h/2);
	ctx.lineTo(len, h / 2);
	ctx.moveTo(0, szer+h/2);
	ctx.lineTo(len, szer + h / 2);
	for(var i = 0; i < liczbaPol; i++){
		ctx.moveTo(z, h/2);
		ctx.lineTo(z, szer + h / 2);
		z += szer;
	}
	ctx.stroke();
	for(var i = 0; i < liczbaPol; i++){
		if(this.autos1[i][1] > -1){
			ctx.beginPath();
			ctx.fillStyle=kolory[this.autos1[i][1]];
			ctx.rect(1 + i * szer, 2 + h / 2, szer - 2, szer / 2);
			ctx.fill();
		}
	}
	ctx.fillStyle="#000000";
	for(var i = 0; i < liczbaPol; i++){
		if(this.autos1[i][0] > -1){
			ctx.beginPath();
			ctx.fillText("" + this.autos1[i][0], 1 + i * szer, -5 + h / 2);
			ctx.fill();
		}
	}
	ctx.restore();
};
Nagel.prototype.clear = function() {
	for (var j = 0; j < liczbaPol; j++) {
		for (var k = 0; k < params; k++) {
			this.autos1[j][k] = -1;
			this.autos2[j][k] = -1;
		}
	}
};
Nagel.prototype.clone = function(array) {
	var r = array.length;
	var c = array[0].length;
	var array1 = [];
	for (var k = 0; k < r; k++) {
		array1[k] = [];
	}
	for (var i = 0; i < r; i++) {
		for (var j = 0; j < c; j++) {
			array1[i][j] = array[i][j];
		}
	}
	return array1;
};
Nagel.prototype.randomInRange = function(min, max) {
	var random = -1;
	if (min > max) {
		return new Error('Pierwsza liczba musi być mniejsza od drugiej');
	} else {
		random = this.cutDecimal(Math.floor(Math.random() * (max - min + 1)) + min);
	}
	return random;
};
Nagel.prototype.cutDecimal = function(nr) {
	var temp = nr.toString();
	var temp1 = temp.indexOf(".");
	var temp2 = "";
	if (temp1 > -1) {
		temp2 = temp.substr(0, temp1);
	} else {
		temp2 = temp;
	}
	return parseInt(temp2);
};