JS won't work, even though it has before

I’m trying to integrate a little “game” I made a year or two ago into a website (I’m very new to this), and it just wont work, well a very specific part won’t at least.

Basically the part that’s not working is the part that creates the player character, and I have no idea why, it worked before I attempted integration, but now its broken.

Original:
https://replit.com/@jacobmine2010/JavaScript-Grid

Attempt at integration:
https://replit.com/@jacobmine2010/The-Online-Grid#script.js

function Draw(){
	exp.length=0
	side.length = 0
	for (let i = sideLength; i != 0; i--){
		side.push('%  ')
	}
	for (let i = sideLength; i != 0; i--){
		if(i == y + 1){
			side.pop('#')
			side.splice(x, 0, "@  ")
			console.log(side) // debug
			exp.push(side)
			side.length = 0
			for (let i = sideLength; i != 0; i--){
				side.push('%  ')
			}
		}else{
			exp.push(side)
		}
	}
}

I would spend more time to solve this but I got to go to bed.

One issue I can immediately spot is that Array.prototype.pop doesn’t take in any parameters, it only removes the last element in the array.

To remove a specific element, you’ll want to use Array.prototype.splice: the first argument is the index, the second argument is how many elements to delete/remove, any other elements are inserted at that index.

If you wanted to remove the first '#' element, you’d first need to find it’s index, you can use Array.prototype.indexOf to do this.

So instead of side.pop('#'), you may instead have meant to do something like side.splice(side.indexOf('#'), 1).


I notice your for loop structure is a little odd:

The more common, traditional way of writing this would be:

for (let i = 0; i < sideLength; i++) {

But your method is not invalid and works just fine.


Edit: After writing the below, I realised that script3.js is not where your issue was and you wanted help with presumably script.js.

I rewrote your code likeso: let me know if that is what you wanted.

function Draw() {
	exp.length = 0
	side.length = 0
	// I converted the loops to a more traditional format as it's easier for me to understand
	for (let i = 0; i < sideLength; i++) {
		side.push('%  ')
	}
	// Note that here you started at `i = sideLength` where `sideLength` was `4`
	// `side[4]` is outside the bounds of the array since there are only 4 elements (the last element has anindex of 3)
	// This is one case where the traditional for loop actually fixes an issue for you and makes more sense
	for (let i = 0; i < sideLength; i++) {
		if (i == y + 1) {
			// You can make the second parameter 1 to essentially replace the element at index `x` with the third parameter
			side.splice(x, 1, "@  ")
			exp.push(side)
			// I don't really know what that second loop was actually doing so I removed it
		} else {
			exp.push(side)
		}
	}
}

In your code, you use the innerHTML attribute to set text, instead use textContent, it’s just generally safer (innerHTML allows you to convert a string to HTML, which can be abused by malicious users. Of course this isn’t really an issue in your case, but always good to follow best practices.).


Looking at your existing code, with some more explanation of what you’re hoping to achieve, I might be able to give you some guidance/assistance. I’m going to do my best to pack as much guidance as I can below to help you :smile:

First of all, you create this grid:

let height = 4 // height of the grid
let width = 4  // width of the grid

let y3 = ["# ", "# ", "# ", "# "]
let y2 = ["# ", "# ", "# ", "# "]
let y1 = ["# ", "# ", "# ", "# "]
let y0 = ["# ", "# ", "# ", "# "]

You use variables for each array. An important concept in programming is nested arrays (which just means arrays in arrays, or an array of arrays).

What you can do is create one variable that is an array, with four items, each one being one of your rows.

let grid = [
	["# ", "# ", "# ", "# "],
	["# ", "# ", "# ", "# "],
	["# ", "# ", "# ", "# "],
	["# ", "# ", "# ", "# "]
];

This, I think, is much neater, but is also much more handy from a programmatic perspective.

Let’s go back a step though, you have width and height parameters (which I’m assuming are for the grid), so why not create this array dynamically (by which I just mean, automatically create the array) using the width and height.

To do this, let’s break this process into steps;

  1. We want to start with an empty array
  2. We then want to fill it with height arrays
  3. We want to fill each array in the empty array with "# "
// start with an empty array
let grid = [];

// use a loop to create `height` arrays and add them to the grid
// (the variable name, `i`, doesn't matter, it's just a traditional choice)
for (let i = 0; i < height; i++) {
	// create another array
	let array = [];
	// fill the array with `width` "# "'s
	for (let j = 0; j < width; j++) {
		array.push("# ");
	}
	// add this array to `grid`
	grid.push(array);
}

Now for an important question, how do you access those elements? You would normally do grid[index], but now at each index we have an array, so grid[index] returns an array. We know how we would normally access an item from that array returned, just add [index] to the end, and that’s exactly how it works: grid[array index][element index].

Okay, but now it might be awkward to display this data right? Well, no. You can use a loop and not change anything really:

for (let i = 0; i < height; i++) {
	document.getElementById("y" + i) = grid[i];
}

And that brings me to another tip, Array.prototype.join. This cool method lets you join the items in an array into one string, and it lets you add something between every item (like a space character!): grid[i].join(" "). Which means you don’t have to do array.push("# ") and add spacing, you can just add the spacing when you display the array.

But what if you have a different height? Well that actually does mess things up a little, but don’t worry, it’s easy to fix. First, you can remove all those <p>s in your HTML, you don’t need them! You can write them with JavaScript!

There are two ways to do this, one is unsafe and generally considered bad practice so I won’t even mention it. Let’s go back to that loop that fills the grid:

let grid = [];

for (let i = 0; i < height; i++) {
	let array = [];
	for (let j = 0; j < width; j++) {
		array.push("# ");
	}
	grid.push(array);
}

What do we want to do? We want to add height paragraph elements to the DOM (DOM stands for Document Object Model, it just refers to how JavaScript sees and can interact with a HTML page). So we can just do this inside that main loop. To create a HTML element, we can use document.createElement("element tag") and pass in the element’s tag as a string. We then need to figure out what element we want to add it to, in this case, just the <body> (which we can conveniently access through document.body) and then we .append it to that element:

// Create a paragraph element
let p = document.createElement("p");
// I didn't mention this, but we can edit attributes likeso:
p.setAttribute("id", "y" + height);
// Then add the element to the <body>
document.body.append(p);

We can put this in the loop likeso:

let grid = [];

for (let i = 0; i < height; i++) {
	let p = document.createElement("p");
	p.setAttribute("id", "y" + height);
	document.body.append(p);

	let array = [];
	for (let j = 0; j < width; j++) {
		array.push("# ");
	}
	grid.push(array);
}

Now, a further improvement would be to store these in an array rather than refering to them via document.getElementById everytime (because this actually searches the DOM every time to find the element), but for now it’s perfectly fine.

Now let’s address the Draw function. We can make this a little more simple and readable. Let’s use two loops (like we did at the start) to loop through each element in the nested arrays:

function Draw() {
	for (let i = 0; i < height; i++) {
		for (let j = 0; j < width; j++) {
		}
	}
}

Now, let’s build a string in the first loop, adding to it from the second (not a great explanation but the code should be self explanatory):

function Draw() {
	for (let i = 0; i < height; i++) {
		// build a string
		let row = "";
		for (let j = 0; j < width; j++) {
			// add the j'th element from the i'th array in grid to the string
			row += grid[i][j];
		}
	}
}

Now all we have to do, is check if those j and i variables match up with x and y, and if it does we can instead add a different character:

function Draw() {
	for (let i = 0; i < height; i++) {
		let row = "";
		for (let j = 0; j < width; j++) {
			// if the player is in this cell of the grid
			if (x === j && y === i) {
				// print the player character instead (just an arbitrary character)
				row += "@";
			} /* otherwise */ else {
				// print whatever element was in the grid
				row += grid[i][j];
			}
		}
	}
}

And that should help you improve what you’ve got a bit!

7 Likes