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