// === Constants ===
// Enable diagonal moves
const diagonal = true;
// Canvas and grid settings
const cw = 900;
const ch = 600;
// Number of columns and rows
var cols = 18;
var rows = 12;
// "Street" parameters
const streetChance = 0.2; // Percentage chance that a row or column is open as a "street"
const backcolor = 'white';
const wallcolor = 'black';
const pathcolor = 'darkred';
const opencolor = 'lightgreen';
const closedcolor = 'lightpink';
const carColors = ['blue', 'green', 'orange', 'purple'];
// 2D grid array
var grid = new Array(cols);
// A* sets for pathfinding
var openSet = [];
var closedSet = [];
// Car objects with random start and border destinations
var cars = [];
const numCars = 4;
// Cell size
var w, h;
// Path and block management
var paths = [];
// === Setup ===
function setup() {
createCanvas(cw, ch);
w = width / cols;
h = height / rows;
// Initialize the grid and create a "street-like" structure
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);
if (Math.random() > streetChance && i % 2 !== 0 && j % 2 !== 0) {
grid[i][j].wall = true; // Make this cell a wall unless it’s a “street”
}
}
}
// Define neighbors for each cell
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j].addNeighbors(grid);
}
}
// Initialize cars with random positions and border destinations
for (let i = 0; i < numCars; i++) {
let start = getRandomEmptyCell();
let destination = getRandomBorderCell();
cars.push({ id: i, pos: start, dest: destination, path: [] });
}
console.log('Start Simulation');
}
// === Main Draw Loop ===
function draw() {
background(backcolor);
// Move and update paths for each car
for (let car of cars) {
// Recalculate path based on dynamic obstacles
if (car.path.length === 0 || grid[car.pos.i][car.pos.j] === car.dest) {
car.path = aStar(car.pos, car.dest);
}
// Move the car along the path
if (car.path.length > 0) {
let nextStep = car.path.shift(); // Take the next step
if (!isBlocked(nextStep)) { // Move if the next cell is not blocked
car.pos = nextStep;
}
}
}
// Draw grid and cars
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j].show();
}
}
for (let car of cars) {
fill(carColors[car.id]);
noStroke();
ellipse(car.pos.i * w + w / 2, car.pos.j * h + h / 2, w * 0.6, h * 0.6);
}
}
// === Spot (Cell) ===
function Spot(i, j) {
this.i = i;
this.j = j;
this.wall = false;
this.neighbors = [];
this.previous = undefined;
this.show = function() {
fill(this.wall ? wallcolor : backcolor);
noStroke();
rect(this.i * w, this.j * h, w, h);
};
this.addNeighbors = function(grid) {
if (this.i < cols - 1) this.neighbors.push(grid[this.i + 1][this.j]);
if (this.i > 0) this.neighbors.push(grid[this.i - 1][this.j]);
if (this.j < rows - 1) this.neighbors.push(grid[this.i][this.j + 1]);
if (this.j > 0) this.neighbors.push(grid[this.i][this.j - 1]);
if (diagonal) {
if (this.i > 0 && this.j > 0) this.neighbors.push(grid[this.i - 1][this.j - 1]);
if (this.i < cols - 1 && this.j > 0) this.neighbors.push(grid[this.i + 1][this.j - 1]);
if (this.i > 0 && this.j < rows - 1) this.neighbors.push(grid[this.i - 1][this.j + 1]);
if (this.i < cols - 1 && this.j < rows - 1) this.neighbors.push(grid[this.i + 1][this.j + 1]);
}
};
}
// === A* Algorithm ===
function aStar(start, end) {
// Initialize A* variables here (reset openSet and closedSet, set g, h, f values)
// A* pathfinding logic to calculate a path from start to end
// Return the computed path as an array of cells
}
// === Helper Functions ===
function getRandomEmptyCell() {
let cell;
do {
let i = Math.floor(Math.random() * cols);
let j = Math.floor(Math.random() * rows);
cell = grid[i][j];
} while (cell.wall);
return cell;
}
function getRandomBorderCell() {
let i, j;
if (Math.random() > 0.5) {
i = Math.random() > 0.5 ? 0 : cols - 1;
j = Math.floor(Math.random() * rows);
} else {
j = Math.random() > 0.5 ? 0 : rows - 1;
i = Math.floor(Math.random() * cols);
}
return grid[i][j];
}
function isBlocked(cell) {
return cars.some(car => car.pos.i === cell.i && car.pos.j === cell.j);
}