Code viewer for World: New World (clone by Singir...

// Cloned by Singireddy bhavana on 8 Nov 2024 from World "New World (clone by Singireddy bhavana) (clone by Singireddy bhavana)" by Singireddy bhavana 
// Please leave this clone trail here.
 


// Cloned by Singireddy bhavana on 8 Nov 2024 from World "New World (clone by Singireddy bhavana)" by Singireddy bhavana 
// Please leave this clone trail here.
 


// Cloned by Singireddy bhavana on 8 Nov 2024 from World "New World" by Singireddy bhavana 
// Please leave this clone trail here.
 
// Cloned by bhavana singireddy on 8 Nov 2024 from World "2D traffic World with "autonomous cars" using A* pathfinding" by singireddy bhavana 
// Please leave this clone trail here.
 
//---- normal P5 code -------------------------------------------------------

// Set up global variables for the grid, cars, and other settings
let cols = 20; // Number of columns in the grid
let rows = 20; // Number of rows in the grid
let grid = []; // 2D array for the grid structure
let cellSize = 35; // Size of each grid cell
let cars = []; // Array to hold car objects
let simulationRunning = true; // Automatically start the simulation
let moveInterval = 15; // Number of frames to wait between moves

// Array of colors for the cars
const carColors = ["#FF5733", "#33FF57", "#3357FF", "#FF33A8"]; 

// Function to set up the canvas and initialize the grid and cars
function setup()       
{
    createCanvas(cols * cellSize, rows * cellSize); // Setting canvas size
    frameRate(30); // Setting a moderate frame rate to control overall speed
    initializeGrid();  // Initializing the grid structure
    placeCars(4);  // Placing 4 cars in random start and end positions
    drawGrid(); // Drawing the grid layout
}

// Function to continuously draw the simulation
function draw()             
{
    if (!simulationRunning) return; // Only run if simulation is active
    background(240); // Light background color
    drawGrid();  // Draw the grid with streets and blocks

    // Move and display each car at the specified interval
    if (frameCount % moveInterval === 0) {
        cars.forEach(car => {
            car.move();
        });
    }

    // Display each car
    cars.forEach(car => {
        car.display();
    });
}

// Function to initialize the grid with streets and blocks
function initializeGrid() {
    for (let i = 0; i < cols; i++) {
        grid[i] = [];
        for (let j = 0; j < rows; j++) {
            // Define streets: every second row and column is a street
            if (i % 2 === 0 || j % 2 === 0) {
                grid[i][j] = { x: i, y: j, isStreet: true }; // Street cell
            } else {
                grid[i][j] = { x: i, y: j, isStreet: false }; // Block cell
            }
        }
    }
}

// Function to draw the grid layout
function drawGrid() {
    for (let i = 0; i < cols; i++) {
        for (let j = 0; j < rows; j++) {
            if (grid[i][j].isStreet) {
                fill(220); // Light gray for streets
                stroke(180); // Darker gray for street edges
            } else {
                fill(50); // Dark gray for blocks
                stroke(100); // Lighter edge for blocks
            }
            rect(i * cellSize, j * cellSize, cellSize, cellSize);

            // Draw intersections as special markers
            if (grid[i][j].isStreet && i % 2 === 0 && j % 2 === 0) {
                fill(255, 255, 100); // Yellow for intersections
                ellipse((i + 0.5) * cellSize, (j + 0.5) * cellSize, cellSize * 0.3, cellSize * 0.3);
            }
        }
    }
}

// Class defining car properties and methods
class Car {
    constructor(x, y, destination, color) {
        this.x = x;
        this.y = y;
        this.destination = destination;
        this.path = [];
        this.color = color;
        this.waitCounter = 0;
        this.findPath(); // Initial path calculation
    }

    // Calculate path using A* algorithm
    findPath() {
        this.path = aStarPath(this.x, this.y, this.destination.x, this.destination.y);
    }

    // Move the car along its path
    move() {
        if (this.path.length > 0) {
            let nextStep = this.path[0];

            if (!isCarBlocking(this, nextStep.x, nextStep.y)) {
                this.path.shift(); // Move to next step if not blocked
                this.x = nextStep.x;
                this.y = nextStep.y;
                this.waitCounter = 0; 
            } else {
                this.waitCounter++; // Increase wait time if blocked
                if (this.waitCounter > 5) {
                    this.findPath(); // Recalculate path if waiting too long
                    this.waitCounter = 0; 
                }
            }
        }
    }

    // Display the car on the grid
    display() {
        fill(this.color);
        noStroke();
        ellipse((this.x + 0.5) * cellSize, (this.y + 0.5) * cellSize, cellSize * 0.6, cellSize * 0.6);
    }
}

// Place a given number of cars at random start and destination points
function placeCars(numCars) {
    for (let i = 0; i < numCars; i++) {
        let startX, startY, destX, destY;
        do {
            startX = floor(random(cols));
            startY = floor(random(rows));
            destX = floor(random(cols));
            destY = floor(random(rows));
        } while (!grid[startX][startY].isStreet || !grid[destX][destY].isStreet || (startX === destX && startY === destY));

        let car = new Car(startX, startY, { x: destX, y: destY }, carColors[i % carColors.length]);
        car.findPath();
        cars.push(car);
    }
}

// A* algorithm to calculate path
function aStarPath(startX, startY, goalX, goalY) {
    let openSet = [{ x: startX, y: startY, g: 0, h: heuristic(startX, startY, goalX, goalY) }];
    let cameFrom = {};
    let closedSet = new Set();

    while (openSet.length > 0) {
        openSet.sort((a, b) => (a.g + a.h) - (b.g + b.h));
        let current = openSet.shift();

        if (current.x === goalX && current.y === goalY) {
            return reconstructPath(cameFrom, current);
        }

        closedSet.add(`${current.x},${current.y}`);
        let neighbors = getNeighbors(current);

        for (let neighbor of neighbors) {
            if (closedSet.has(`${neighbor.x},${neighbor.y}`) || !grid[neighbor.x][neighbor.y].isStreet) {
                continue;
            }

            let gScore = current.g + 1;
            let hScore = heuristic(neighbor.x, neighbor.y, goalX, goalY);
            let openNode = openSet.find(n => n.x === neighbor.x && n.y === neighbor.y);

            if (!openNode || gScore < openNode.g) {
                cameFrom[`${neighbor.x},${neighbor.y}`] = current;
                if (!openNode) {
                    openSet.push({ x: neighbor.x, y: neighbor.y, g: gScore, h: hScore });
                }
            }
        }
    }
    return [];
}

// Reconstruct path from end to start
function reconstructPath(cameFrom, current) {
    let totalPath = [current];
    while (`${current.x},${current.y}` in cameFrom) {
        current = cameFrom[`${current.x},${current.y}`];
        totalPath.push(current);
    }
    return totalPath.reverse();
}

// Manhattan distance heuristic
function heuristic(x1, y1, x2, y2) {
    return abs(x1 - x2) + abs(y1 - y2);
}

// Get neighboring cells
function getNeighbors(node) {
    let directions = [
        { x: 1, y: 0 }, { x: -1, y: 0 },
        { x: 0, y: 1 }, { x: 0, y: -1 }
    ];
    return directions
        .map(dir => ({ x: node.x + dir.x, y: node.y + dir.y }))
        .filter(n => n.x >= 0 && n.x < cols && n.y >= 0 && n.y < rows);
}

// Check if any car is blocking the path
function isCarBlocking(car, x, y) {
    return cars.some(otherCar => otherCar !== car && otherCar.x === x && otherCar.y === y);
}