Text File to JavaScript Nested Array - javascript

I have this .txt file to change to a nested array:
000011000000
000100001100
000001100001
010010001000
100101000100
101010010001
001000001001
000001000111
010100100010
010010010010
000000011100
001001110000
to the format:
var data = [
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
[1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0],
[1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
[0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0]
]
what I have done so far is:
Read the file:
function readMatrixFile(){
var inputElement = document.getElementById("adjencyMatrixInput");
var fileList = inputElement.files;
var plainMatrix = new FileReader();
plainMatrix.readAsText(fileList[0]);
plainMatrix.onload = function () {
//Add to Matrix
renderMatrix(plainMatrix)
}
}
and
2. Split the File
function renderMatrix(plainMatrix) {
var matrix = plainMatrix.result;
var mtx = [];
matrix = matrix.split("\n");
}
I know I need to push through a for loop, but not sure how to get the nested array.

Split the string by a newline, then map over each item and convert the string into an array of characters with spread syntax.
const str = `000011000000
000100001100
000001100001
010010001000
100101000100
101010010001
001000001001
000001000111
010100100010
010010010010
000000011100
001001110000`
const res = str.split("\n").map(e => [...e])
console.log(res)
To convert the characters to numbers, map over the array of characters and parse each item:
const str = `000011000000
000100001100
000001100001
010010001000
100101000100
101010010001
001000001001
000001000111
010100100010
010010010010
000000011100
001001110000`
const res = str.split("\n").map(e => [...e].map(e => +e))
console.log(res)

You turn matrix into a a string of ones and zeros, you just need to split the string and convert them to numbers
function renderMatrix(plainMatrix) {
var matrix = plainMatrix.result;
var mtx = matrix.split("\n"); // mtx is now an array of strings of ones and zeros
mtx = mtx.map(string => string.split('')); // mtx is now an array of arrays of number string
mtx = mtx.map(nested => nested.map(numberString => Number(numberString))); // mtx is now what you want
}

Related

How to fill an 2D array with a 2D Smaller array in JavaScript

I apologize if this is not well explained. I am quite new to JavaScript.
I have a 2D arrayA that is 10x10 and a 2D arrayB that is 5x8. The smaller arrayB is populated with data and the larger arrayA is just populated with 0's by default.
How can i move the data from arrayB to arrayA while still leaving the leftover space of arrayA as 0's?
The end result must be that arrayA should contain all of the data in the same order as arrayB but with the leftover space still just containing 0's.
Assuming I understood the question correctly, you can loop over each value of arrayB and assign it at the same indexes in arrayA:
const arrayA = Array(10).fill(0).map(_ => Array(10).fill(0))
const arrayB = Array(5).fill(0).map(_ => Array(8).fill(1))
for (let y = 0; y < arrayB.length; y++) {
for (let x = 0; x < arrayB[y].length; x++) {
arrayA[y][x] = arrayB[y][x]
}
}
console.log(arrayA.map(v => v.join(', ')).join('\n'))
The console.log is just for readability, to understand how the matrix looks.
A simple Array.map() will do the job:
const arrA = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 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 arrB = [
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
];
const B2A = () => arrA.map(
(val, index) => val.map(
(subVal, subIndex) => {
if(arrB[index] && arrB[index][subIndex]) return arrB[index][subIndex]
return subVal;
})
)
console.log(B2A());
Use Array.from and iterate, while iterate check if the value exists in filler array. If exists use that value otherwise same array value.
const fill = (arr1, arr2) =>
Array.from(arr1, (arr, row) =>
Array.from(arr, (value, col) => (arr2[row] && arr2[row][col]) || value)
);
const arrA = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 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 arrB = [
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]
];
console.log(JSON.stringify(fill(arrA, arrB)));

How to write out n*n Matrix values in JavaScript?

I'm new to JavaScript, so I decided to try to make a simple n*n Array. When I'm trying to write it out, I get, something starnge back.
var map = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 3, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 3, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
function GoTh() {
for (var i = 0; i < map.length; i++) {
for (var j = 0; j < map[i].length; j++) {
console.log(map[i][j]);
}
}
}
GoTh();
I expected it to write all 100 values, but it gives back this:
1 2 3 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 3 1
That's because same-value console.logs are grouped together in browsers' consoles.
This can usually be disabled, i.e. in Chrome & Opera:
In Firefox it's in console's settings (press F1 while using console)
Another option is to write more data along with the value, eg.:
console.log(i, j, map[i][j]);
The problem is the ouput in the console itself. If there are multiple similar entries - like the first 10 elements of value 1 in the first row plus the 1 in the second row, it will be grouped as a single entry of 11. You can see that there are multiple if you look to the right of a particular entry.

How to determine if chunks of a value could fit into an array

Given an input array of 1s and 0s of arbitrary length, such as:
[0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0]
How can I (most efficiently) calculate a new array detailing if chunks of size n 0s which can fit into the input?
Examples
Where output now means
1 == 'Yes a zero chunk that size could go here'
0 == 'Couldn't fit a chunk that size there'
Chunk size = 1 ([0]): [1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
Chunk size = 2 ([0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
Chunk size = 3 ([0,0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
Chunk size = 4 ([0,0,0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
I'm using ES6, so any language features are fine.
EDIT:
The output shouldn't just be a 'yes'/'no' a chunk of size 'n' can fit in this array. More specifically, it needs to be an array of the same length, where a '1' / 'true' array value represents either:
Yes, a chunk of size 'n' could start and fit here, or
Yes, this slot could contain a chunk of size 'n' that started before it
On that second point, this would mean for chunk size 3:
input = [1, 0, 0, 0, 0, 1];
output = [0, 1, 1, 1, 1, 0];
Edit 2:
This is the function I came up with but it seems very inefficient:
const calculateOutput = (input, chunkSize) => {
const output = input.map((value, index) => {
let chunkFitsHere = false;
const start = (index - (chunkSize) >= 0) ? index - (chunkSize) : 0;
const possibleValues = input.slice(start, index + chunkSize);
possibleValues.forEach((pValue, pIndex) => {
let consecutives = 0;
for (let i = 0; i < possibleValues.length - 1; i += 1) {
if (consecutives === chunkSize) {
break;
}
if (possibleValues[i+1] === 0) {
consecutives += 1;
} else {
consecutives = 0;
}
}
if (consecutives === chunkSize) {
chunkFitsHere = true;
}
});
return chunkFitsHere ? 1 : 0;
});
return output;
};
You could count the connected free places by reversing the array and take an flag for the last return value for mapping.
Array before final mapping and after, depending on n
1 0 4 3 2 1 0 0 2 1 0 0 0 3 2 1 0 2 1 array with counter
1 0 4 4 4 4 0 0 2 2 0 0 0 3 3 3 0 2 2 array same counter
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ------------------
1 0 1 1 1 1 0 0 1 1 0 0 0 1 1 1 0 1 1 n = 1
0 0 1 1 1 1 0 0 1 1 0 0 0 1 1 1 0 1 1 n = 2
0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 n = 3
0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 n = 4
function chunk(array, n) {
return array
.slice()
.reverse()
.map((c => v => v ? c = 0 : ++c)(0))
.reverse()
.map((l => v => l = v && (l || v))(0))
.map(v => +(v >= n));
}
var array = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0];
console.log(chunk(array, 1).join(' '));
console.log(chunk(array, 2).join(' '));
console.log(chunk(array, 3).join(' '));
console.log(chunk(array, 4).join(' '));
If you like only one mapping at the end, remove the last two map and use
.map((l => v => l = +(v && (v >= n || l)))(0));
for final mapping.
You can traverse array once, calculating length of the series of zeros. If it is long enough, fill output with series of 1 of the same length.
Note that you can fill output for different chunk lengths simultaneously (filling chunks in rows of 2d array with row index not exceeding zerolen)
Python code:
def zerochunks(a, n):
l = len(a)
result = [0] * l #list of l zeros
zerolen = 0
for i in range(l + 1):
### Short circuit evaluation to shorten code
if (i==l) or (a[i] != 0):
if (zerolen >= n): #series of zeros is finished here
for j in range(i - zerolen, i):
result[j] = 1
zerolen = 0
else:
zerolen += 1
return result
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 1))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 2))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 3))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 4))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 5))
>>>
[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
[0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 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]
And function for getting all arrays with chunks in maxn range:
def zerochunksall(a, maxn):
l = len(a)
result = [[0] * l for i in range(maxn)]
zerolen = 0
for i in range(l + 1):
if (i==l) or (a[i] != 0):
for k in range(0, zerolen):
for j in range(i - zerolen, i):
result[k][j] = 1
zerolen = 0
else:
zerolen += 1
return result
print(zerochunksall([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 5))
>>
[[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
[0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 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]]
function fit(input, n) {
var output = [];
for(var i = 0; i < input.length; i++) {
var fit = true;
for(var j = i; j < i + n; j++) {
if(j >= input.length || input[j]) { // either over the array size or occupied
fit = false;
break;
}
}
output.push(fit);
}
return output;
}
var input = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0];
console.log(fit(input, 1).map(v => +v));
console.log(fit(input, 2).map(v => +v));
console.log(fit(input, 3).map(v => +v));
console.log(fit(input, 4).map(v => +v));
outputs
[ 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1 ]
[ 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ]
[ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
[ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
These don't seem to exactly match your expected output though, but that may be because I'm assuming the flags in the array should mark the start of the chunk (i.e. can you fit N truthy values in the array starting from this position).
(See below, where e = your expected result, n = the output of my algorithm.)
input = [ 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0 ]
e = 2 = [ 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1 ]
n = 2 = [ 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ]
==== ==== ==== ====
You can use array.prototype.some to check if the chunk can fit starting to some index of the input array. To check if the chunk with it's actual length can fit, you can use array.prototype.every:
var input = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0];
var chunk = [0,0,0];
var res = input.some((e, i) => chunk.every((c, j) => input[i + j] === c));
console.log(res);
var input = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0];
var chunk = [0, 0, 0, 0, 0, 0, 0, 0];
var res = input.some((e, i) => chunk.every((c, j) => input[i + j] === c));
console.log(res);
You could use some method and then if the current element is 0 you can slice part of the array from current index and check if its all zeros.
const data = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0]
function check(arr, n) {
let chunk = Array(n).fill(0).join('');
return arr.some((e, i) => e === 0 && arr.slice(i, i + n).join('') == chunk)
}
console.log(check(data, 3))
console.log(check(data, 4))
console.log(check(data, 5))

Displaying an 11x11 Matrix on a Canvas

I've been trying to create a canvas that displays an 11x11 matrix.
const canvas = document.getElementById('canvasGame');
const context = canvas.getContext('2d');
context.scale(10, 10);
context.fillstyle = '#000';
context.fillstyle(0,0, canvas.width, canvas.height);
const matrix = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
Depending on the number inside the matrix it will create a rectangle of a certain colour.
I've created a basic function that goes through every entry.
if = 0, white rectangle.
else, black rectangle.
function drawMatrix(matrix){
matrix.forEach((row, y) =>{
row.forEach((value, x) => {
if(value === 0) {
context.fillStyle = 'white';
context.fillRect(x, y, 1, 1);
}
else
{
context.fillStyle = 'black';
context.fillRect(x, y, 1, 1);
}
});
});
}
drawMatrix(matrix);
However when I load my html file with my .js file and my canvas set-up it doesnt load anything apart from the styling I've applied to my canvas.
Screenshot: What it loads.
My HTML, if that matters.
<html>
<head>
<title>Testing Grounds</title>
<style>
body {
background: #345;
color: #fff;
font-family: sans-serif;
font-size: 2em;
text-align: center;
}
canvas {
border: dashed .2em #fff;
height: 90vh;
}
</style>
</head>
<body>
<h1>Test Zone</h1>
<p>Using a canvas to display 11x11 matrix</p>
<canvas id="canvasGame" width="350" height="350"/>
<script src="app.js"></script>
</body>
</html>
Here is also another way...
const canvas1 = document.getElementById('canvas1');
const context1 = canvas1.getContext('2d');
const canvas2 = document.getElementById('canvas2');
const context2 = canvas2.getContext('2d');
//context.scale(canvas.height / 16, canvas.height / 16);
matrix = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
function drawMatrix(matrix) {
z = matrix.map((c) => c.map((c) => c == 0 ? [255, 255, 255, 255] : [0, 0, 0, 255]));
i = new ImageData(Uint8ClampedArray.from(z.flat(2)), 12)
context1.putImageData(i, 0, 0);
context2.scale(16, 16);
context2.webkitImageSmoothingEnabled = false;
context2.mozImageSmoothingEnabled = false;
context2.imageSmoothingEnabled = false;
context2.drawImage(canvas1, 0, 0);
}
drawMatrix(matrix);
<center><canvas hidden id="canvas1" width=12 height=12></canvas></center>
<center><canvas id="canvas2" width=192 height=192></canvas></center>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
// every drawn pixel will be 16 times bigger
context.scale(canvas.height / 16, canvas.height / 16);
const matrix = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
function drawMatrix(matrix) {
// write all pixels cycling thru rows and columns
matrix.forEach((row, y) => {
row.forEach((value, x) => {
context.fillStyle = value && "black" || "white";
context.fillRect(x, y, 1, 1);
});
});
}
drawMatrix(matrix); // draw the matrix
<center><canvas id="canvas" width=192 height=192></canvas></center>
The rectangles you're creating are 1 by 1 pixel and always in the upper-left. You should calculate the width/height of the rectangle (width / 11, height / 11). Then translate the x and width using those values. Something like the following should work:
function drawMatrix(matrix){
var cellWidth = canvas.width / 11.0;
var cellHeight = vanvas.height / 11.0;
matrix.forEach((row, y) =>{
row.forEach((value, x) => {
context.fillStyle = cellColor(value);
context.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
});
});
}
function cellColor(val) {
if(value == 0)
{
return 'white';
}
return 'black';
}
drawMatrix(matrix);
This will calculate the width and height of the cell, loop through each element, and draw the rectangle with either white or black depending on the value.
You should also make sure that the drawMatrix function is called after the body is loaded.

Constant value changes regardless of being constant; also, changes to one row of 2D array propagate to others

I was trying to do the 6th day of AdventOfCode.com, when I stumbled upon an annoying problem, that I don't know the cause of. I
var input = ["turn on 7,6 through 9,6","turn on 1,3 through 6,9"];
var grid = 0;
function Create2Darray(dimension) {
var arr = [0];
var arr2 = [0];
for (i=0; i<dimension; i++) {
arr2[i] = 0;
}
for (k=0; k<dimension; k++) {
arr[k] = arr2;
}
return arr;
}
grid = Create2Darray(10);
const p = grid; // THIS IS WHAT IT IS ALL ABOUT
temp = grid[4];
temp[5] = 3;
grid[4] = temp;
p; // outputs [[0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0]] to console.
// Although we said: const p = grid;
// And at that time, grid was equal to [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
Secondly
this:
temp = grid[4];
temp[5] = 3;
grid[4] = temp;
What I expected was this:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 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 I got:
[[0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0], [0, 0, 0, 0, 0, 3, 0, 0, 0, 0]]
What am I doing wrong?
so the core questions:
Why did CONSTANT p change?
Why did ALL the "sub-arrays" within the main arrays change while I only selected the 5th value in the 4th "sub-array"?
About reference/copy
Javascript works "by reference", not "by copy" like C++. This means that after:
var a = [1, 2, 3];
var b = [a, a];
b is an array containing two references to the same array a, not two copies of a. For example after
b[0][0] = 99;
also b[1][0] will be 99 because b[0] and b[1] are references to the very same object.
If you want to build a matrix you need to build each row separately... for example:
var grid = [];
for (var i=0; i<100; i++) {
grid.push(new Array(100));
}
// Now grid is a matrix of 100x100 undefined elements
About const
Declaring a const reference to an array doesn't prevent the array content from being modified, you're only prevented from reassigning grid to reference something else.
A quick way to create a copy of an array is to use slice(0), for example instead of
for (k=0; k<dimension; k++) {
arr[k] = arr2;
}
you could have
for (k=0; k<dimension; k++) {
arr[k] = arr2.slice(0);
}
and then the code works as expected: every row of 2D array has the same content but the rows can be modified independently. See also: What's the point of .slice(0) here?

Categories

Resources