New 60 G VPS server.
Code viewer for World: A star (clone by Bharath@2024)
// Fix for p5.js AudioContext warning, ensures sound context starts after user interaction
function userStartAudio() {
  getAudioContext().resume();
}

const numVehicles = 4;
const gridMatrix = [];
const vehicleColors = ['red', 'green', 'blue', 'yellow'];
const vehicleArray = [];
let numCols, numRows;
let cellWidth, cellHeight;
const backColor = 'black';
const wallColor = 'gray';

// Spot class to represent a cell in the grid
class Cell {
  constructor(i, j) {
    this.i = i;
    this.j = j;
    this.isBarrier = random(1) < 0.3; // Randomly create barriers (walls)
    this.gScore = 0;
    this.hScore = 0;
    this.fScore = 0;
    this.neighbors = [];
    this.previous = undefined;
  }

  // Display the cell as a rectangle or wall
  show() {
    if (this.isBarrier) {
      fill(wallColor);
    } else {
      fill(backColor);
    }
    noStroke();
    rect(this.i * cellWidth, this.j * cellHeight, cellWidth, cellHeight);
  }

  // Add adjacent (neighboring) cells to the current cell
  addAdjacent(gridMatrix) {
    const { i, j } = this;
    if (i < numCols - 1) this.neighbors.push(gridMatrix[i + 1][j]);
    if (i > 0) this.neighbors.push(gridMatrix[i - 1][j]);
    if (j < numRows - 1) this.neighbors.push(gridMatrix[i][j + 1]);
    if (j > 0) this.neighbors.push(gridMatrix[i][j - 1]);
  }
}

// Vehicle class to represent a moving object
class Vehicle {
  constructor(startCell, endCell, color) {
    this.startCell = startCell;
    this.endCell = endCell;
    this.color = color;
    this.path = [];
    this.currentCell = startCell;
    this.calculatePath();
  }

  // A* pathfinding algorithm to calculate the path from start to end
  calculatePath() {
    let openSet = [this.startCell];
    let closedSet = [];
    this.path = [];

    while (openSet.length > 0) {
      let lowestIndex = openSet.reduce((best, cell, idx) => cell.fScore < openSet[best].fScore ? idx : best, 0);
      let currentCell = openSet[lowestIndex];

      if (currentCell === this.endCell) {
        let temp = currentCell;
        this.path = [];
        while (temp) {
          this.path.push(temp);
          temp = temp.previous;
        }
        this.path.reverse();
        return;
      }

      openSet.splice(lowestIndex, 1);
      closedSet.push(currentCell);

      currentCell.neighbors.forEach(neighbor => {
        if (!closedSet.includes(neighbor) && !neighbor.isBarrier) {
          let tempG = currentCell.gScore + 1;
          if (!openSet.includes(neighbor)) {
            openSet.push(neighbor);
          } else if (tempG >= neighbor.gScore) {
            return;
          }
          neighbor.gScore = tempG;
          neighbor.hScore = this.heuristic(neighbor, this.endCell);
          neighbor.fScore = neighbor.gScore + neighbor.hScore;
          neighbor.previous = currentCell;
        }
      });
    }
  }

  // Heuristic function for A* algorithm (Manhattan distance)
  heuristic(a, b) {
    return abs(a.i - b.i) + abs(a.j - b.j);
  }

  // Move the vehicle to the next position in its path
  move() {
    if (this.path.length > 1) {
      let nextCell = this.path[1];
      this.currentCell = nextCell;
      this.path.shift();
    }
  }

  // Draw the path of the vehicle (colored line)
  drawPath() {
    noFill();
    stroke(this.color);
    strokeWeight(3);
    beginShape();
    this.path.forEach(cell => vertex(cell.i * cellWidth + cellWidth / 2, cell.j * cellHeight + cellHeight / 2));
    endShape();
  }

  // Display the vehicle's current position and destination
  show() {
    // Display destination cell as a colored triangle
    fill(this.color);
    noStroke();
    triangle(
      this.endCell.i * cellWidth + cellWidth / 2, this.endCell.j * cellHeight + cellHeight / 2,
      this.endCell.i * cellWidth, this.endCell.j * cellHeight,
      this.endCell.i * cellWidth + cellWidth, this.endCell.j * cellHeight + cellHeight
    );

    // Display vehicle's current position as a colored rectangle
    fill(this.color);
    noStroke();
    rect(this.currentCell.i * cellWidth, this.currentCell.j * cellHeight, cellWidth, cellHeight);
  }
}

function setup() {
  createCanvas(800, 500);
  userStartAudio(); // Ensure audio context resumes after user interaction

  numCols = floor(width / 30); // Grid columns
  numRows = floor(height / 30); // Grid rows
  cellWidth = width / numCols;  // Width of each cell
  cellHeight = height / numRows;  // Height of each cell

  // Create the grid
  for (let i = 0; i < numCols; i++) {
    gridMatrix[i] = new Array(numRows);
    for (let j = 0; j < numRows; j++) {
      gridMatrix[i][j] = new Cell(i, j);
    }
  }

  // Add adjacent cells to each cell in the grid
  for (let i = 0; i < numCols; i++) {
    for (let j = 0; j < numRows; j++) {
      gridMatrix[i][j].addAdjacent(gridMatrix);
    }
  }

  // Create vehicles with random start and end positions
  for (let i = 0; i < numVehicles; i++) {
    let startCell, endCell;
    do {
      startCell = gridMatrix[floor(random(numCols))][floor(random(numRows))];
    } while (startCell.isBarrier);
    
    do {
      endCell = gridMatrix[floor(random(numCols))][floor(random(numRows))];
    } while (endCell.isBarrier || endCell === startCell);

    startCell.isBarrier = endCell.isBarrier = false;
    
    let color = vehicleColors[i % vehicleColors.length];
    vehicleArray.push(new Vehicle(startCell, endCell, color));
  }
}

function draw() {
  background(backColor);

  // Display the grid
  gridMatrix.flat().forEach(cell => cell.show());

  // Update and display each vehicle
  vehicleArray.forEach(vehicle => {
    vehicle.drawPath();
    vehicle.move();
    vehicle.show();
  });
}