
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
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);
};
