Find connected components in javascript 2d matrix - javascript

My array maybe looks like this:
var array = [
[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
I'd like to find all connected components in this 2d matrix like the 'E'-character in the middle, the (lets call it SQUARE) in the left corner above and the other "square" in the right bottom and mark them all with different numbers to get a result like this:
var result = [
[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0]
[0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,3,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
My code that works absolutely well looks like this:
var array = [
[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
function find_connected_components(array) {
var default_value=1;
function test_connection(array, i, j, value) {
if (array[i] && array[i][j] === -1) {
array[i][j] = value;
test_connection(array, i + 1, j, value);
test_connection(array, i, j + 1, value);
return true;
}
}
array.forEach(function (a) {
a.forEach(function (b, i, bb) {bb[i] = -b;});
});
array.forEach(function (a, i, aa) {
a.forEach(function (b, j, bb) {test_connection(aa, i, j, default_value) && default_value++;});
})
console.log(array.map(a => [a.join('')]).map(a => [a.join('')]))
}
find_connected_components(array)
But- now my error appears until I rotate my array from above. SO that it looks like this:
var error_array = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
]
The result for the error_array above is completely wrong & I have no clue how to fix this.
PS: I haven't edited a ERROR-array code snippet because my question would be to long. Soo please try the error_array for your own.
And I hope somebody can explain how to fix my code:)
Edit 1 : This is the output for the error_array
Thanks a million in advance!
Greetings jonas

One problem: your test_connection is kind of like a flood fill algorithm, but it only moves to right and down. You need to modify your function to fill up and to the left as well.
It works for the first case pretty well because the "E" shape can be filled correctly when only moving right and down from the top-left point. But when the "E" is flipped (your second case, the recursive call no longer reaches the horizontal bars of the "E".

First, change the value of 1 to -1, because you need to use 1 as flag.
Then you could iterate the elements and perform a check and if it has the flag -1, then change it to the actual value. Proceed with the element of the right and bottom.
If an element was found, increment value.
function test(array, i, j, value) {
if (array[i] && array[i][j] === -1) {
array[i][j] = value;
test(array, i -1, j, value);
test(array, i + 1, j, value);
test(array, i, j - 1, value);
test(array, i, j + 1, value);
return true;
}
}
var data = [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
value = 1;
data.forEach(function (a) {
a.forEach(function (b, i, bb) {
bb[i] = -b;
});
});
data.forEach(function (a, i, aa) {
a.forEach(function (b, j, bb) {
test(aa, i, j, value) && value++;
});
});
document.getElementById('out').innerHTML = data.map(function (a) { return a.join(' '); }).join('\n');
<pre id="out"></pre>

Related

Javascript 2d array select around from single point

Say I have a 15x15 2d array
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
See the character A? at y:9 and x:4 (index starts with 0).
What I want to do here is to update the array where I select or update the 0s around the A to, say, asterisk (*).
For an example, lets say I want 0s around the A as far as 3 indexes to be updated as *
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, *, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, *, *, *, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, *, *, *, *, *, 0, 0, 0, 0, 0, 0, 0, 0],
[0, *, *, *, A, *, *, *, 0, 0, 0, 0, 0, 0, 0],
[0, 0, *, *, *, *, *, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, *, *, *, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, *, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
What is the most efficient way to achieve this?
EDIT
What I've tried:
var s_length = 4, coordinate_y_x = [9, 4]
for (let i1 = 0; i1 < s_length; i1++) {
for (let i = 0; i < s_length; i++) {
if (map[coordinate_y_x[0] - i][coordinate_y_x[1]] != undefined) map[coordinate_y_x[0] - i][coordinate_y_x[1]] = 1
if (map[coordinate_y_x[0]][coordinate_y_x[1] - i]!= undefined) map[coordinate_y_x[0]][coordinate_y_x[1] - i] = 1
}
for (let i = s_length; i > 0; i--) {
console.log("loop2");
if (map[coordinate_y_x[0] + i][coordinate_y_x[1]]!= undefined) map[coordinate_y_x[0] + i][coordinate_y_x[1]] = 1
if (map[coordinate_y_x[0]][coordinate_y_x[1] + i]!= undefined) map[coordinate_y_x[0]][coordinate_y_x[1] + i] = 1
}
}
I managed to change what's left, right, top, and bottom from this code with given point and length, but I can't seem to figure out how to do the rest (between directions)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, A, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
One way is with a somewhat spiral matrix walk, but instead of a "square" walk, yours will be diagonal / "diamond" shape. Additionally, we don't really care about the "connectiveness" of the path, so I'll jump around a bit. That is, when a walk has finished a ring, it isn't important that the next ring start on a neighboring cell of the previous ring's last step.
In your example data, I've marked the cells that the algorithm would visit in order (1st, 2nd, 3rd, etc.)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 15, 7, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 14, 6, 2, 8, 18, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 13, 5, 1, A, 3, 9, 19, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 24, 12, 4, 10, 20, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 23, 11, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Note, I've chosen to always start from the left side of the origin, but that is arbitrary. You could start from the top, right, or bottom side.
So our three loops (in order) will be
The length we want to "expand" by can be thought of as a separate "ring." So loop each ring.
Next, loop each "side" of that ring.
Finally, loop each "step" along that side.
To keep things symmetric, each side will only occupy a single "corner" cell. So for example when looping the 3rd ring, each side would only be 3 steps each. Here I have each side labeled as a, b, c, and d.
* * * b * * *
* * a * b * *
* a * * * b *
a * * X * * c
* d * * * c *
* * d * c * *
* * * d * * *
Otherwise the only tricky part is figuring out how to change directions as you loop each side.
A very simple way to do this is store "deltas," how much we expect each x and y value (where we currently are) to change for each step. We know we'll be moving 1 step each time, so it is just a matter of moving right / down (positive +) or left / up (negative -).
I decided to store these values in an array, but you can probably do some modulo math to switch between them. Looping over a constant is just a little easier to understand. So moving up and to the right would have an x_delta value of 1 and y_delta value of -1, etc.
Finally, you need a "in bounds" check as you are completing your walk. The algo will still try and "visit" these cells, but won't try to write to the array if it doesn't exist. This is one area of the algo you can probably improve.
Put it all together, and you have this:
const data = Array(15)
.fill()
.map(v => Array(15).fill(0));
// Assumes the graph won't contain `undefined` values. Otherwise, do a `length` check on the arrays
function inBounds(data, [y, x]) {
return data?.[y]?.[x] !== undefined;
}
const deltas = [
[ 1, -1], // Up right
[ 1, 1], // Down right
[-1, 1], // Down left
[-1, -1], // Up left
];
function fillFrom({origin: [oy, ox], data, length, value}) {
// Walk in diamond "rings" around our origin
for (let size = 1; size <= length; size++) {
// Start from the left side of our ring
let x = ox - size;
let y = oy;
// Move along 4 sides of the diamond
for (let [xd, yd] of deltas) {
// Move each step along the side
for (let step = 0; step < size; step++) {
if (inBounds(data, [y, x])) {
data[y][x] = value;
}
x += xd;
y += yd;
}
}
}
return data;
}
// Updates data "in place." Would need to deep clone if you wanted to keep things immutable
fillFrom({origin: [9, 4], data, length: 3, value: 1});
data[9][4] = 'A';
console.log(data.map(r => r.join('')).join('\n'));

How I may break from this recursivity in JavaScript for a maze path finder?

I have been practicing some exercises, and among them I am now trying to create a code for finding a path inside a maze matrix created in js.
Now, this code works, it finds the correct path, and I even p[rint it to be sure its the correct one, but I am having one issue. I am not sure what to do in case my path cannot arrive to the destination.
For example, these are 2 of my samples, the correct path is marked with 1 and the "walls" with a 0:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 2],
[0, 1, 1, 1, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]
But, if I cut one path, preventing my fidner to arrive to the destination, I am unable to find a way to break the recursivity.
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 0, 0, 2],
[0, 1, 1, 1, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]
In short, I can return the correct path, but I am not sure , in case It cannot find a way to the "exit", to return "Invalid path", or "There is no path to the destination"
Bellow is the complete code:
class mazeSolver {
constructor() {
this.myMaze = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 2],
[0, 1, 1, 1, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
this.traverse = function (column, row) {
if (this.myMaze[column][row] === 2) {
console.log("You found the exit at: " + column + "-" + row);
console.log("Path: ")
for (let i = 0; i < this.myMaze.length; i++) {
console.log(this.myMaze[i])
}
}
else if (this.myMaze[column][row] === 1) {
this.myMaze[column][row] = 8;
console.log("You passed by " + row + "-" + column);
if (column < this.myMaze.length - 1) {
this.traverse(column + 1, row);
}
if (row < this.myMaze[column].length - 1) {
this.traverse(column, row + 1);
}
if (column > 0) {
this.traverse(column - 1, row);
}
if (row > 0) {
this.traverse(column, row - 1);
}
}
};
}
}
I appreciate any input.
Thanks!
Some comments on your code:
Use console.log inside the traverse method for debugging only, not for something important as reporting the path that was found. That should actually be left to the caller to do.
If the recursive call finds the target, no other recursive call should be made. Instead that success should immediately be returned to the caller, who should do the same...
The path could be collected during backtracking. This path could be the return value in case of success (and undefined otherwise).
Do not initialise a hardcoded matrix in the constructor. Instead pass the matrix as argument to the constructor.
Make traverse a prototype method, instead of defining it on the instance.
In a matrix, we usually consider the first dimension as rows, and the second dimension as columns. You did it the other way round.
It is easier to protect your traversal against out-of-range access by the use of the ?. operator.
Here is the updated code:
class MazeSolver {
constructor(matrix) {
this.myMaze = matrix;
}
traverse(column, row) {
if (this.myMaze[row]?.[column] === 2) {
return [[column, row]]; // Return path. Caller can extend it
} else if (this.myMaze[row]?.[column] === 1) {
this.myMaze[row][column] = 8;
console.log("You passed by " + column + "," + row);
const path = this.traverse(column + 1, row)
?? this.traverse(column, row + 1)
?? this.traverse(column - 1, row)
?? this.traverse(column, row - 1);
if (path) path.unshift([column, row]); // Extend the path found
return path;
}
}
}
// Maze without solution:
const solver = new MazeSolver([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 2],
[0, 1, 1, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]);
const path = solver.traverse(0, 3);
if (path) {
console.log("found a path (column, row):")
console.log(JSON.stringify(path));
} else {
console.log("No path found");
}
your solution doesn't work for some cases, take this example
this.myMaze = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 2],
[0, 1, 1, 1, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
];
result:
You passed by 3-0
You passed by 3-1
You passed by 4-1
You passed by 5-1
You passed by 5-2
You passed by 5-3
You passed by 6-3
You passed by 7-3
You passed by 8-3
You passed by 9-3
maze.js:39
if (this.myMaze[row][column] === 2) {
^
TypeError: Cannot read property '3' of undefined
at mazeSolver.traverse (maze.js:39:33)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:53:26)
at mazeSolver.traverse (maze.js:53:26)
at mazeSolver.traverse (maze.js:50:26)
at mazeSolver.traverse (maze.js:50:26)
first thing I can tell about your algorithm is it's an eager algorithm, meaning
that you chose the first available path.
Second thing about recursion is you must have an exit condition that will be true at some point, you don't have it your case, you are not even exiting the function at any point.
third you are switching between column and row, column is the vertical array, row is the horizontal array.
here is a code that is an eager solution, that will at least avoid the error above
class mazeSolver {
constructor() {
this.solution_found=false;
this.myMaze = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 2],
[0, 1, 1, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
this.traverse = function (row, column) {
if (this.myMaze[row][column] === 2) {
this.solution_found=true;
console.log("You found the exit at: " + row + "-" + column);
console.log("Path: ")
for (let i = 0; i < this.myMaze.length; i++) {
console.log(this.myMaze[i])
}
}
else if (this.myMaze[row][column] === 1) {
this.myMaze[row][column] = 8;
console.log("You passed by " + row + "-" + column);
if (column < this.myMaze.length - 1) {
if(row +1> this.myMaze.length - 1)
return
this.traverse(row + 1, column);
}
if (row < this.myMaze[row].length - 1) {
if(column+1 > this.myMaze.length - 1)
return
this.traverse(row, column + 1);
}
if (row > 0) {
if(row-1 < 0){
return
}
this.traverse(row - 1, column);
}
if (column > 0) {
if(column-1 < 0){
return
}
this.traverse(row, column - 1);
}
}
};
}
}
maze = new mazeSolver();
maze.traverse(3, 0)
if(!maze.solution_found){
console.log('solution not found')
}
to develop an algorithm that will find the path 100% if the path exists, try doing some research on search algorithms, mainly path finding, e.g., A* heuristic or Dijkstra's Algorithm.

Javascript line-height Property with ██████

I'm trying to, with a matrix (to represent black and white) display a QR code on a webpage (<p></p>). I'm using the ████ characters to display such, but even when the CSS property of the line-height is 0px, I still cannot remove all gaps (and the QR code doesn't read). My code and resulting image:
var dateTime = new Date("Nov 11, 2019, 11:40:30").getTime();
var width = 195;
var height = 20;
var qrCode = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
var myRequest = new Request('https://rohan-bhowmik.github.io/ctf-test/qr.txt');
var wCnt = 0;
var hCnt = 0;
var tick = setInterval(function () {
var currTime = new Date().getTime();
var diff = dateTime - currTime;
var dayCount = Math.floor(diff / (24 * 60 * 60 * 1000));
var hourCount = Math.floor(diff % (24 * 60 * 60 * 1000) / (60 * 60 * 1000));
var minuteCount = Math.floor(diff % (60 * 60 * 1000) / (60 * 1000));
var secondCount = Math.floor(diff % (60 * 1000) / (1000));
var msCount = Math.floor(diff % (1000));
var sentence = dayCount + " " + hourCount + " " + minuteCount + " " + secondCount + " " + msCount;
document.getElementById("timer").innerHTML = sentence;
var count = -1;
if (diff <= 1) {
document.getElementById("alive").style = "display: inline; word-wrap: break-word; line-height: 0px;";
document.getElementById("alive").innerHTML = "";
clearInterval(tick);
var offSet = 0;
var text = setInterval(function () {
var chars = ['y', 'o', 'u', 'c', 'h', 'e', 'a', 't', 'e', 'd'];
count++;
wCnt++;
if (wCnt + offSet >= width) {
console.log(hCnt);
document.getElementById("alive").innerHTML += "<br>";
wCnt = 0;
offSet = 0;
hCnt++;
count = 0;
}
var m = 59;
var n = 0;
if (wCnt >= m && wCnt < m+34 && hCnt >= n && hCnt < n+34) {
if (qrCode[hCnt - n][wCnt - m] == 1) {
document.getElementById("alive").innerHTML += "&#9608";
offSet += 1.25;
} else{
document.getElementById("alive").innerHTML += "&#20&#20&#20";
offSet += 1.25;
}
} else {
document.getElementById("alive").innerHTML += chars[(count) % 10];
}
}, 0.1);
}
}, 1);
You can do this by using imageData. You may need to resize the pixel to get the wanted size. The rendered code is readable by qr-droid.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="500" height="500"> <!-- resize width and height to fit qr-code -->
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var qrCode = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var pixelSize = 5;
var imgData = ctx.createImageData(pixelSize, pixelSize);
// creates pixelSize*pixelsize "pixel of pixels"
for (let i = 0; i < imgData.data.length; i += 4){
imgData.data[0+i] = 0;
imgData.data[1+i] = 0;
imgData.data[2+i] = 0;
imgData.data[3+i] = 255;
}
var max_x = qrCode[0].length;
var max_y = qrCode.length;
// draw pixels according to qrCode matrix.
for (let y = 0; y < max_y; y++){
for (let x = 0; x < max_x; x++){
if (qrCode[y][x] == 1) ctx.putImageData(imgData, x*pixelSize, y*pixelSize);
}
}
</script>
<!-- The canvas tag is not supported in Internet
Explorer 8 and earlier versions.-->
</body>
</html>
Introduction to using canvas imagedata: https://www.w3schools.com/tags/canvas_imagedata_data.asp
Horizontal gaps are most likely just likely space between lines. Setting line-height to equal value as font-size (or just unitless 1). Simple examples:
just monospace blocks, no gaps but more rectangular and possibly light bleeding between blocks:
<div style="
white-space: pre;
font-family: monospace;
font-size: 20px;
line-height: 20px;
">
███████
█ █
█ ███ █
█ ███ █
█ ███ █
█ █
███████
</div>
more square and less bleeding could be made with doubled characters stuck together with negative letter-spacing:
<div style="
white-space: pre;
font-family: monospace;
font-size: 20px;
line-height: 20px;
letter-spacing: -2px;
">
██████████████
██ ██
██ ██████ ██
██ ██████ ██
██ ██████ ██
██ ██
██████████████
</div>

How to display arrays as visuals in Javascript (e.g. for a maze)

So, I am making a maze, in javascript. I do not know how to display an array (such as 1's and 0's) graphically. The best way is to show you the code:
var maze= [
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0],
[0,0,1,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1],
[0,0,0,1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1],
];
With the 0's representing walls, and the 1's representing empty space, and 2 meaning the end of the maze, how can I display this as a maze using only javascript? Shall I make each 0 an individual rectangle? How can I do this?
Please do not make fun as I am just starting out.
Here is the code for reference (this is on "coding with chrome", as it was the easiest to use, as I did not have to import anything).
//PART 1 : THE CHARACTER
//Where is the character???
charX=10;
charY=10;
//Draw char
function drawChar(){
draw.circle(charX, charY, 5, "black");
}
//Loop happens at 40 milliseconds
setInterval (loop, 40);
//loop that clears screen
function loop(){
draw.rectangle(0,0, window.innerWidth, window.innerHeight,"white");
drawChar();
}
//Move Character
document.addEventListener("keydown", moveChar);
function moveChar (e) {
if(e.keyCode ==37){
//Left arrow
charX=charX-50;
}
if(e.keyCode== 38){
//Up arrow
charY=charY-50;
}
if(e.keyCode == 39){
//right arrow
charX=charX+50;
}
if(e.keyCode == 40){
//down arrow
charY=charY +50;
}
//PART 1 DONE :-)
//PART 2: Walls
//map of maze
var maze= [
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0],
[0,0,1,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1],
[0,0,0,1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1],
];
//How can we display this graphically, with the 0 being a wall, and 1 being an empty space?
span {
white-space: pre;
display: inline-block;
width: 24px;
}
<script>
var maze = [
[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1],
];
maze.forEach(function(arr, index) {
arr.forEach(function(path, i) {
var span = document.createElement("span");
if (path === 0) {
span.textContent = " ";
span.style.backgroundColor = "#000";
}
if (path === 1) {
span.textContent = " ";
span.style.backgroundColor = "yellow";
}
if (path === 2) {
span.textContent = "end";
span.style.backgroundColor = "green";
span.style.color = "gold";
}
document.body.appendChild(span)
});
document.body.appendChild(document.createElement("br"))
})
</script>

Javascript Conway's Game of Life Issues

I'm trying to make Conway's Game of Life in javascript. I made a function to count neighbors, and a function that produces the next generation of cells. However, I tried a test input, and the result isn't coming out right, and I can't find where the error is. Please help.
Here's the code:
(code attached)
/* Draws grid */
for (var i = 0; i < 15; i++) {
for (var j = 0; j < 15; j++) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#FFFFFF";
ctx.strokeStyle = "grey";
ctx.strokeRect(10 * j, 10 * i, 10, 10);
}
}
/* draws live cells */
function drawSquares(a) {
for (var i = 0; i < 15; i++) {
for (var j = 0; j < 15; j++) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#000000";
if (a[i][j] === 1) {
ctx.fillRect(10 * j, 10 * i, 10, 10);
}
}
}
}/* Counts neighbors */
function neighborCount(a, i, j, height, width){
var lifes = 0;
var neighbors = [
[-1, 1],
[0, 1],
[1, 1],
[-1, 0],
[1, 0],
[-1, -1],
[0, -1],
[1, -1]
];
/* loops through a cell's neighbors */
for (var z = 0; z < 8; z++){
/*checks if the neighbor isn't off the grid*/
if ((i + neighbors[z][0]) >=0 && (i + neighbors[z][0]) < height && (j + neighbors[z][1]) >=0 && (j + neighbors[z][1]) < width){
/*checks if it's alive*/
if (a[i + neighbors[z][0]][j + neighbors[z][1]] === 1){
lifes++;
}
}
}
return lifes;
}
/* game of life */
function life(a) {
var n = a; /*new generation of life */
var lifes = 0; /*neighbor counter*/
var height = a.length;
var width = a[0].length;
/*loops through all cells*/
for (var i = 0; i < height; i++){
for (var j = 0; j < width; j++){
lifes = neighborCount(a, i, j, height, width);
/* kills alive cells */
if(a[i][j] === 1 && (lifes < 2 || lifes > 3)){
n[i][j] = 0;
}
/* brings dead cells to life */
else if (a[i][j] === 0 && lifes ===3){
n[i][j] = 1;
}
}
}
drawSquares(n);
return(n);
}
/* test input */
var a = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
/* expected result:
var a = [
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]; */
life(a);
<canvas id="myCanvas" width="150" height="150"></canvas>

Categories