// Cloned by Bharath@2024 on 6 Nov 2024 from World "A star (clone by test2) (clone by Rasinkton Fernando)" by Rasinkton Fernando
// Please leave this clone trail here.
//#### Car start and end marked with the same car color
const diagonal = false; // No diagonal movement for a street-like setup
const cw = 900;
const ch = 600;
const numCars = 4;
let cols, rows;
let w, h;
const grid = [];
const cars = [];
const wallAmount = 1.0;
const backcolor = 'black';
const wallcolor = 'yellow';
// Colors for each car
const carColors = ['blue', 'green', 'red', 'cyan'];
class Spot {
constructor(i, j) {
this.i = i;
this.j = j;
this.f = 0;
this.g = 0;
this.h = 0;
this.neighbors = [];
this.previous = undefined;
// Introduce random street placement by setting probabilities for rows and columns
const isStreetRow = random(1) < 0.3; // 30% chance of an open street row
const isStreetCol = random(1) < 0.6; // 30% chance of an open street column
this.wall = !(isStreetRow || isStreetCol); // Only walls if neither row nor column is open
}
show(col) {
fill(this.wall ? wallcolor : col || backcolor);
noStroke();
rect(this.i * w, this.j * h, w, h);
}
addNeighbors(grid) {
let { i, j } = this;
if (i < cols - 1) this.neighbors.push(grid[i + 1][j]);
if (i > 0) this.neighbors.push(grid[i - 1][j]);
if (j < rows - 1) this.neighbors.push(grid[i][j + 1]);
if (j > 0) this.neighbors.push(grid[i][j - 1]);
}
}
class Car {
constructor(start, end, color) {
this.start = start;
this.end = end;
this.path = [];
this.current = start;
this.color = color;
this.recalculatePath();
}
recalculatePath() {
let openSet = [this.start];
let closedSet = [];
this.path = [];
while (openSet.length > 0) {
let winner = openSet.reduce((best, spot, idx) => spot.f < openSet[best].f ? idx : best, 0);
let current = openSet[winner];
if (current === this.end) {
let temp = current;
this.path = [];
while (temp) {
this.path.push(temp);
temp = temp.previous;
}
this.path.reverse();
return;
}
openSet = openSet.filter((spot) => spot !== current);
closedSet.push(current);
current.neighbors.forEach((neighbor) => {
if (!closedSet.includes(neighbor) && !neighbor.wall) {
let tempG = current.g + 1;
if (!openSet.includes(neighbor)) {
openSet.push(neighbor);
} else if (tempG >= neighbor.g) {
return;
}
neighbor.g = tempG;
neighbor.h = heuristic(neighbor, this.end);
neighbor.f = neighbor.g + neighbor.h;
neighbor.previous = current;
}
});
}
}
move() {
if (this.path.length > 1) {
let nextSpot = this.path[1];
let blockingCar = cars.find(otherCar => otherCar !== this && otherCar.current === nextSpot);
if (!blockingCar) {
this.current = nextSpot;
this.path.shift();
} else {
this.recalculatePath();
}
}
}
drawPath() {
noFill();
stroke(this.color);
strokeWeight(3);
beginShape();
this.path.forEach(spot => vertex(spot.i * w + w / 2, spot.j * h + h / 2));
endShape();
}
show() {
// Draw start point as a white square
fill('this.color');
//noStroke();
stroke(this.color);
strokeWeight(3);
rect(this.start.i * w, this.start.j * h, w, h);
// Draw end point as a white circle
fill('white');
ellipse(this.end.i * w + w / 2, this.end.j * h + h / 2, w * 0.8, h * 0.8);
// Draw the car at its current position
fill(this.color);
stroke(this.color);
strokeWeight(3);
//triangle(this.current.i * w, this.current.j * h, w, h)
rect(this.current.i * w, this.current.j * h, w, h);
}
}
function heuristic(a, b) {
return abs(a.i - b.i) + abs(a.j - b.j);
}
function setup() {
frameRate(2);
createCanvas(cw, ch);
cols = floor(width / 20);
rows = floor(height / 20);
w = width / cols;
h = height / rows;
for (let i = 0; i < cols; i++) {
grid[i] = new Array(rows);
for (let j = 0; j < rows; j++) {
grid[i][j] = new Spot(i, j);
}
}
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j].addNeighbors(grid);
}
}
for (let i = 0; i < numCars; i++) {
let start, end;
do {
start = grid[floor(random(cols))][floor(random(rows))];
} while (start.wall);
do {
end = grid[floor(random(cols))][floor(random(rows))];
} while (end.wall || end === start);
start.wall = end.wall = false;
let color = carColors[i % carColors.length];
cars.push(new Car(start, end, color));
}
}
function draw() {
background(backcolor);
grid.flat().forEach((spot) => spot.show());
cars.forEach(car => {
car.drawPath();
car.move();
car.show();
});
}