How can I retrieve neighboring cells from a 2D array using Javascript?

I'm currently following a tutorial on creating grid-based games using vanilla JavaScript. The tutorial I'm referring to can be found at https://www.youtube.com/watch?v=aKYlikFAV4k&t=1848s&ab_channel=TheCodingTrain

However, I'm facing some challenges in getting the neighboring cells for each cell in my grid. Being a beginner in coding, any assistance would be highly appreciated!

Below is an excerpt of the code I've been working on:

//GLOBAL VARIABLES 
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const wh = 600;
const cellSize = 30;
const rows = 20;
const cols = 20;
const grid = new Array(rows);
const open = [];
const closed = [];
let start;
let end;

//FUNCTIONS 
//Immediately-invoked function expression
(function() {
  setup();
})();

function Cell(x, y) { 
  this.x = 0;
  this.y = 0;
  this.f = 0;
  this.g = 0;
  this.h = 0;
  this.show = function(color) { 
    ctx.fillStyle = color;
    ctx.fillRect(this.x, this.y, cellSize, cellSize);
    ctx.strokeStyle = 'white';
    ctx.strokeRect(this.x, this.y, cellSize, cellSize);
  }
}

function setup() {
  let interval = setInterval(update, 120);
  canvas.setAttribute('width', wh);
  canvas.setAttribute('height', wh);
  document.body.insertBefore(canvas, document.body.childNodes[0]); 
  createGrid();
  setStartEnd();
}

function createGrid() {
  for (let i = 0; i < rows; i++) { 
    grid[i] = new Array(cols);
  }
  let x = 0;
  let y = 0;
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      grid[i][j] = new Cell();
      grid[i][j].x = x;
      grid[i][j].y = y;
      grid[i][j].show();
      x = x + 1 * 30;
    }
    x = 0;
    y = y + 1 * 30;
  }
}

function setStartEnd() {
  start = grid[0][0];
  end = grid[cols - 1][rows - 1];
  open.push(start);
}

function removeArray(arr, e) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === e) {
      arr.splice(i, 1);
    }
  }
}

function update() {
  for (let i = 0; i < open.length; i++) {
    open[i].show('green');
  }

  for (let i = 0; i < closed.length; i++) {
    closed[i].show('red');
  }
}

Answer №1

By not having Cell store its own x,y position in the grid, you're making things a bit more challenging for yourself.

If you transfer some of the logic from your nested i,j for loop to the Cell class, it will simplify the process. I made modifications to the Cell class to store its grid coordinates (x and y) rather than pixel coordinates. With this change, you can do something like this in the update function:

  const nextOpenSet = new Set();
  open.forEach(cell => {
    const above = grid[cell.y - 1]?.[cell.x];
    if (above) nextOpenSet.add(above);
    
    const below = grid[cell.y + 1]?.[cell.x];
    if (below) nextOpenSet.add(below);
    
    const left = grid[cell.y][cell.x - 1];
    if (left) nextOpenSet.add(left);
    
    const right = grid[cell.y][cell.x + 1];
    if (right) nextOpenSet.add(right);
  });
  
  open = Array.from(nextOpenSet);

Below is an example that you can run:

//GLOBAL VARIABLES 
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const wh = 600;
const cellSize = 30;
const rows = 20;
const cols = 20;
const grid = new Array(rows);
let open = [];
const closed = [];
let start;
let end;

//FUNCTIONS 
(function() {
  setup();
})();

function Cell(x, y) {
  this.x = x;
  this.y = y;
  this.show = function(color) {
    ctx.fillStyle = color;
    ctx.fillRect(this.x * cellSize, this.y * cellSize, cellSize, cellSize);
    ctx.strokeStyle = 'white';
    ctx.strokeRect(this.x * cellSize, this.y * cellSize, cellSize, cellSize);
  }
}

function setup() {
  let interval = setInterval(update, 120);
  canvas.setAttribute('width', wh);
  canvas.setAttribute('height', wh);
  document.body.insertBefore(canvas, document.body.childNodes[0]);
  createGrid();
  setStartEnd();
}

function createGrid() {
  for (let i = 0; i < rows; i++) {
    grid[i] = new Array(cols);
  }
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      grid[i][j] = new Cell(i, j);
      grid[i][j].show();
    }
  }
}

function setStartEnd() {
  start = grid[0][0];
  end = grid[cols - 1][rows - 1];
  open.push(start);
}

function removeArray(arr, e) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === e) {
      arr.splice(i, 1);
    }
  }
}

function update() {
  for (let i = 0; i < open.length; i++) {
    open[i].show('green');
  }

  for (let i = 0; i < closed.length; i++) {
    closed[i].show('red');
  }
  
  const nextOpenSet = new Set();
  open.forEach(cell => {
    const above = grid[cell.y - 1]?.[cell.x];
    if (above) nextOpenSet.add(above);
    
    const below = grid[cell.y + 1]?.[cell.x];
    if (below) nextOpenSet.add(below);
    
    const left = grid[cell.y][cell.x - 1];
    if (left) nextOpenSet.add(left);
    
    const right = grid[cell.y][cell.x + 1];
    if (right) nextOpenSet.add(right);
  });
  
  open = Array.from(nextOpenSet);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is placing JavaScript on the lowest layer the best approach?

I'm facing a unique situation that I haven't encountered before and am unsure of how to address it. My website has a fixed top header and footer. On the left side, there is a Google Adsense ad in JavaScript. When scrolling down, the top header s ...

Unable to transfer the function's output to a variable

This is a code snippet relating to an object Obj.prototype.save = function (fn){ var aabb = Obj.reEditName(this.name, function(newName) { return newName; // Additionally attempted var foo = newName; return foo; ...

Verifying child attributes within a collection using AngularJS expressions

Is there a way to write an angular expression that can check each child item in a list and return true if any child has a specific property value? My issue involves a chart legend generated by an ng-repeat expression. I want the wrapping element to be sho ...

React component not displaying HERE map controls

Having trouble implementing zoom in and zoom out controls on HERE maps in React. Despite following the documented steps, I am unable to find a solution. I have meticulously followed all instructions provided at: The link to my map component can be found ...

Developing a standard jQuery function for adding event listeners

Attempting to replicate the functionality of Google Maps' addListener using jQuery listeners for clicks, keypresses, etc. In Moogle Maps, you can use .event.addListener(map, 'click', function()... or switch 'click' with 'drag ...

Expanding the outer div with Jquery's append() function to accommodate the inner div elements perfectly

I am facing an issue where my outer div does not expand automatically to fit the elements I append inside it using jQuery. The structure of my div is as follows: <div class="well" id='expand'> <div class="container"> < ...

Invoke a function while rendering or utilize a getter

Is it better to use a class method or a getter when a render method needs to return a calculated value? class User extends Component { getFullName () { const { fname, lname } = this.props return `${lname}, ${fname}` } render () { return ...

The modal window obstructs my view on the screen

You are working with a modal form that triggers a POST method in your controller https://i.sstatic.net/0vbOy.png Here is the view code: <div class="modal fade" id="agregarProducto"> <div class="modal-dialog" role="document"> < ...

Combining strings within a string after a specific word with nested Concatenation

In a given string variable "str," I am looking to concatenate another string between "InsertAfterMe" and "InsertBeforeMe". str="This is a string InsertAfterMe InsertBeforeMe" s1="sometext" s2="soMoreText" aList=[1,2,3,4,5] The concatenated string shoul ...

Vue2 is not compatible with the vue-email-editor component

I checked out the official website to install the vue-email-editor. Here is the link for the unlayer vue-email-editor component However, I encountered the following error: vue.runtime.esm.js?c320:4573 [Vue warn]: Error in render: "TypeError: (0 , ...

Implementing Angular checkbox repetition controlled from an external controller

I'm looking to streamline my controller by setting a variable from outside the controller to populate my checkbox list. Can this be done? Check out my current code snippet here: http://jsfiddle.net/ilmansg/Lx37kr3e/1/ VIEW HTML <div ng-controlle ...

Is it possible to import SVG files and inline them in Angular?

Behold, an SVG Circle: <svg viewBox="0 0 104 104"> <circle cx="52" cy="52" r="50" stroke="#003EFF" stroke-width="4" fill="#00FF98" /> </svg> The Angular Project imports it in this manner: import circle from './circle.svg'; ...

Using GreenSock to animate and manipulate the tween function's parameters

I have two functions that are called on mouse events: function menuBtnOver(e){ var b = e.data; b.setPosition(b.x, b.y+5); } function menuBtnOut(e){ var b = e.data; b.setPosition(b.x, b.y-5); } Additionally, there is another function: setP ...

Executing asynchronous functions within a loop using useEffect

My current scenario is as follows: export default function Component({ navigation }) { const [ item, setItem ] = useState([]); useEffect(() => { AsyncStorage.getItem('someItem') .then(data => JSON.parse(data)) ...

Anomaly in the default checked state of checkboxes

I'm currently working on a project and encountering an issue with the code below. I need to incorporate a forEach() loop within getElements() instead of using map(). Additionally, I want the default state of a checkbox to remain checked even after nav ...

Mapping over an array and ignoring any undefined properties in a dynamic object

Looking for a way to dynamically create objects in the 'map' function to reduce the final array size. The goal is to avoid adding properties with undefined values. For example, if 'offst: undefined', skip this property but add others wi ...

From converting Javascript code to PHP and using the innerHTML function for deletion

I'm currently working on implementing a script and could use some assistance with two specific issues that I'm struggling to resolve. The main goal is to enable users to create a running route and then store the route in a database using coordina ...

Access numerical values from JSON objects using JavaScript

I need assistance with implementing a JavaScript function to retrieve data from a JSON file and then display it on my webpage. The goal is to iterate through the values in a while loop and dynamically insert them into specific HTML elements. xhttp.onrea ...

The website becomes unresponsive and locks up after being on the same page for several

We are dealing with a PHP web application that heavily utilizes javascript and jquery. The main issue we are facing involves a create/read/update/delete page where users can modify content. These modifications occur using AJAX, which prevents a full page r ...

Node.js module retriever showing as blank

My current challenge involves the creation of a settings class with one getter. Here is how it currently looks: class Configuration { get endpoint() { return 'https://api.example.com'; } } module.exports.Configuration = Configuration; In a ...