Code viewer for World: New World
let cols = 30;
let rows = 20;
let grid = new Array(cols);
let w, h;
let start = [];
let end = [];
let openSet = [];
let closedSet = [];
let paths = [];
let carCount = 4; // Number of agents

let roadImage; // Placeholder for road image
let intersectionImage; // Placeholder for intersection image

// Colors for visualization
let backcolor = [255, 255, 255]; // Background color
let closedcolor = [255, 0, 0];   // Closed set color (red)
let opencolor = [0, 255, 0];     // Open set color (green)
let pathcolor = [0, 0, 255];     // Path color (blue)

function preload() {
  // Load images for road and intersection (custom)
  // Replace these with actual image files
  roadImage = loadImage('/uploads/nivedithavudayagiri/Road-2-way.png');
  buildingImage = loadImage('/uploads/nivedithavudayagiri/New-york-buildings-4.png');
}
let pathFound = []; // Track if the path is found for each car

function setup() {
  createCanvas(900, 600);

  frameRate(2);

  w = width / cols;
  h = height / rows;

  for (let i = 0; i < cols; i++) {
    grid[i] = new Array(rows);
  }

  for (let i = 0; i < cols; i++) {
    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 carIndex = 0; carIndex < carCount; carIndex++) {
    start[carIndex] = grid[Math.floor(random(0, cols))][Math.floor(random(0, rows))];
    end[carIndex] = grid[Math.floor(random(0, cols))][Math.floor(random(0, rows))];
    start[carIndex].wall = false;
    end[carIndex].wall = false;

    openSet[carIndex] = [start[carIndex]];
    closedSet[carIndex] = [];
    paths[carIndex] = [];
    pathFound[carIndex] = false; // Initialize pathFound to false
  }
}

function draw() {
  background(backcolor);
  drawRoadsAndIntersections();

  for (let carIndex = 0; carIndex < carCount; carIndex++) {
    if (pathFound[carIndex]) continue; // Skip processing if path is already found

    if (openSet[carIndex].length > 0) {
      let winner = 0;

      for (let i = 0; i < openSet[carIndex].length; i++) {
        if (openSet[carIndex][i].f < openSet[carIndex][winner].f) {
          winner = i;
        }
      }

      let current = openSet[carIndex][winner];

      if (current === end[carIndex]) {
        console.log("Path found for Agent " + (carIndex + 1));

        paths[carIndex] = reconstructPath(current);

        // Draw the path as a line from start to end
        stroke(random(255), random(255), random(255)); // Random color for each car
        strokeWeight(2);
        for (let i = 0; i < paths[carIndex].length - 1; i++) {
          let startX = paths[carIndex][i].i * w + w / 2;
          let startY = paths[carIndex][i].j * h + h / 2;
          let endX = paths[carIndex][i + 1].i * w + w / 2;
          let endY = paths[carIndex][i + 1].j * h + h / 2;
          line(startX, startY, endX, endY);
        }

        pathFound[carIndex] = true; // Mark path as found for this car
        continue;
      }

      removeFromArray(openSet[carIndex], current);
      closedSet[carIndex].push(current);

      let neighbors = current.neighbors;
      for (let i = 0; i < neighbors.length; i++) {
        let neighbor = neighbors[i];

        if (!closedSet[carIndex].includes(neighbor) && !neighbor.wall) {
          let tempG = current.g + 1;

          let newPath = false;
          if (openSet[carIndex].includes(neighbor)) {
            if (tempG < neighbor.g) {
              neighbor.g = tempG;
              newPath = true;
            }
          } else {
            neighbor.g = tempG;
            newPath = true;
            openSet[carIndex].push(neighbor);
          }

          if (newPath) {
            neighbor.h = heuristic(neighbor, end[carIndex]);
            neighbor.f = neighbor.g + neighbor.h;
            neighbor.previous = current;
          }
        }
      }
    } else {
      console.log("Replanning for Agent " + (carIndex + 1));
      openSet[carIndex] = [start[carIndex]];
      closedSet[carIndex] = [];
    }

    // Draw start and end points
    fill(0, 255, 255);
    ellipse(start[carIndex].i * w + w / 2, start[carIndex].j * h + h / 2, w / 2, h / 2);
    fill(255, 0, 255);
    ellipse(end[carIndex].i * w + w / 2, end[carIndex].j * h + h / 2, w / 2, h / 2);
  }
}
// Reconstructs the path from the end node
function reconstructPath(current) {
    try{
  let path = [];
  let temp = current;
  while (temp) {
    path.push(temp);
    temp = temp.previous;
  }
  return path.reverse(); // Reverse the path for correct order
    }catch{
        console.log('Problem with reconstructing path')
    }
}

// Utility function to remove an element from the array
function removeFromArray(arr, elt) {
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i] === elt) {
      arr.splice(i, 1);
    }
  }
}

// Spot object for each cell in the grid
function Spot(i, j) {
  this.i = i;
  this.j = j;
  this.f = 0;
  this.g = 0;
  this.h = 0;
  this.neighbors = [];
  this.previous = undefined;
  this.wall = random(1) < 0.3; // Randomly assign some spots as walls

  this.show = function(col) {
    fill(col);
    noStroke();
    rect(this.i * w, this.j * h, w - 1, h - 1);
  };

  this.addNeighbors = function(grid) {
    let i = this.i;
    let j = this.j;
    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]);
  };
}

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

// Visualize roads and intersections (placeholders for images)
function drawRoadsAndIntersections() {
  for (let i = 0; i < cols; i++) {
    for (let j = 0; j < rows; j++) {
      if (!grid[i][j].wall) {
        image(roadImage, i * w, j * h, w, h);
      } else {
        image(buildingImage, i * w, j * h, w, h);
      }
    }
  }
}