AStarAlgorithm/index.html
2022-05-15 16:29:53 +02:00

269 lines
10 KiB
HTML

<html>
<head>
</head>
<body onmousemove="//mouseMove(canv, event)" onmousedown="mousePressed(event)">
<script type="text/javascript">
var WALL_CHANCE = 0.5;
function random(min, max) {
return Math.random()*(max-min)+min;
}
function dist(x, y, a, b) {
return Math.sqrt(Math.pow(x-a,2) + Math.pow(y-b,2));
}
function constrain(x, y, z) {
return ( x < y ) ? y : (( x > z ) ? z : x);
}
class Tile {
constructor(i, j) {
this.i = i;
this.j = j;
this.neighbors = [];
this.previous = undefined;
this.wall = (Math.random() <= WALL_CHANCE) ? true : false;
this.f = 0;
this.g = 0;
this.h = 0;
}
addNeighbors(g) {
for (var c = -1; c < 2; c++) {
for (var d = -1; d < 2; d++) {
var a = constrain(c+this.i,0,g.tiles.length-1);
var b = constrain(d+this.j,0,g.tiles[this.i].length-1);
var e = g.tiles[a][b];
if (!(a == this.i && b == this.j) && !this.neighbors.includes(e)) {
this.neighbors.push(e);
}
}
}
}
}
class Grid {
constructor(width, height) {
this.tiles = [];
for (var i = 0; i < width; i++) {
var row = [];
for (var j = 0; j < height; j++) {
row.push(new Tile(i, j));
}
this.tiles.push(row);
}
}
setup() {
for (var i = 0; i < this.tiles.length; i++) {
for (var j = 0; j < this.tiles[i].length; j++) {
this.tiles[i][j].addNeighbors(this);
}
}
var is = 0, js = 0, ie = 0, je = 0;
while (true) {
is = Math.floor(random(0,this.tiles.length));
js = Math.floor(random(0,this.tiles[is].length));
while (true) {
var x = Math.floor(random(0,this.tiles.length));
var y = Math.floor(random(0,this.tiles[x].length));
if (x != is && y != js) {
ie = x;
je = y;
break;
}
}
if (this.tiles[is][js].wall == false && !this.tiles[ie][je].wall == false) {
break;
}
}
this.start = this.tiles[is][js];
this.end = this.tiles[ie][je];
this.start.wall = false;
this.end.wall = false;
this.openSet = [this.start];
this.closedSet = [];
this.path = [];
this.finished = false;
}
gameOfLifeCheck(px, py) {
var al = 0;
var col = (this.tiles[px][py].wall)?1:0;
for (var i = -1; i < 2; i++) {
for (var j = -1; j < 2; j++) {
var pos = {x:(px+i+cols)%cols, y:(py+j+rows)%rows};
al += (this.tiles[Math.floor(pos.x)][Math.floor(pos.y)].wall)?1:0;
}
}
al -= col;
if (col == 0 && al == 3) {
return 1;
} else if (col == 1 && (al < 2 || al > 3)) {
return 0;
} else {
return col;
}
}
gameOfLifeStep() {
var newGrid = new Grid(cols, rows);
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
newGrid.tiles[i][j].wall = (this.gameOfLifeCheck(i, j))?true:false;
}
}
this.tiles = newGrid.tiles;
this.setup();
}
findPathAStar() {
if (this.openSet.length > 0) {
var winner = 0;
for (var i = 0; i < this.openSet.length; i++) {
if (this.openSet[i].f < this.openSet[winner].f) {
winner = i;
}
}
var current = this.openSet[winner];
if (current === this.end) {
this.finished = true;
console.log("Found Path!");
}
this.closedSet.push(
this.openSet.splice(
this.openSet.indexOf(current),
1
)[0]
);
var neighbors = current.neighbors;
for (var i = 0; i < neighbors.length; i++) {
var neighbor = neighbors[i];
if (!this.closedSet.includes(neighbor) && !neighbor.wall) {
var tempG = current.g + dist(neighbor.i, neighbor.j, current.i, current.j);
var newPath = false;
if (this.openSet.includes(neighbor)) {
if (tempG < neighbor.g) {
neighbor.g = tempG;
newPath = true;
}
} else {
neighbor.g = tempG;
newPath = true;
this.openSet.push(neighbor);
}
if (newPath) {
neighbor.h = dist(neighbor.i, neighbor.j, this.end.i, this.end.j);
neighbor.f = neighbor.g + neighbor.h;
neighbor.previous = current;
}
}
}
} else {
this.finished = true;
console.log("No Path found!");
}
this.path = [];
var temp = current;
this.path.push(temp);
while (temp.previous) {
this.path.push(temp.previous);
temp = temp.previous;
}
}
}
var interv, frames = 30, canv, ctx/*, mouse = {x:0, y:0}*/;
var scl = 20, cols, rows, dead, alive, grid;
function setup() {
canv = document.createElement("canvas");
canv.style.position="fixed";
canv.style.top="0px";
canv.style.left="0px";
canv.style.zIndex="-1";
canv.width=window.innerWidth;
canv.height=window.innerHeight;
ctx=canv.getContext("2d");
document.body.appendChild(canv);
cols = Math.round(canv.width/scl);
rows = Math.round(canv.height/scl);
dead = "rgb(0,0,0)";
alive = "rgb(255,255,255)";
grid = new Grid(cols, rows);
grid.setup();
}
function draw() {
if (!grid.finished) {
grid.findPathAStar();
}
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
var c = grid.tiles[i][j];
ctx.strokeStyle = "black";
ctx.fillStyle = (grid.tiles[i][j].wall) ? alive : dead;
if (!grid.finished) {
if (grid.openSet.includes(c)) {
ctx.fillStyle = "blue";
}
if (grid.closedSet.includes(c)) {
ctx.fillStyle = "rgb(170, 0, 170)";
}
}
if (grid.path.includes(c)) {
ctx.fillStyle = "green";
}
if (c == grid.start) {
var g = 255*(7/8);
ctx.fillStyle = "rgb("+g+", "+g+", 0)";
}
if (c == grid.end) {
ctx.fillStyle = "red";
}
if (c.wall) {
ctx.fillStyle = "white";
}
ctx.fillRect(i*scl+1, j*scl+1, scl-2, scl-2);
ctx.beginPath();
ctx.rect(i*scl, j*scl, scl, scl);
ctx.stroke();
ctx.fill();
ctx.closePath();
}
}
}
function mousePressed(evt) {
// if (evt.button == 1) {
grid.gameOfLifeStep();
/* } else if (evt.button == 0) {
var x = Math.floor(mouse.x/scl), y = Math.floor(mouse.y/scl);
grid.tiles[x][y].wall = !grid.tiles[x][y].wall;
}*/
}
/* function mouseMove(canvas, evt) {
var rect = canvas.getBoundingClientRect();
mouse = {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}*/
setup();
interv = setInterval(draw, 1000/frames);
</script>
</body>
</html>