Adding characters to a two-dimentional array in Javascript - javascript

I am really having a hard time trying to fill my two dimensional array in Javascript.
I have a different array with lots of letters that I want to add to my 'board' but even the board dose not seem to be working correctly. Whenever I try to print board to the web page using the draw Board method I get NaN for the place where the letter A is. The rest is displaying the number 0.
var ROW = 10;
var COLUMN = 10;
var board = [['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, 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 drawBoard(board) {
var str = '';
for (var x = 0; x < ROW; x++){
str += '<div class="row">';
for (var y = 0; y < COLUMN; y++){
str += '<div class="column">' +
+ board[x][y] + '</div>' + '</div>';
}
str += '</div>';
}
$('#board').append(str);
}
$(function(){
drawBoard(board);
});
What I want to do is have this string:
var Letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'];
make a for loop to just board[x][y] = Letters.pop(). And then display the board with the new letters.
Are there any better ways to add an array to a two dimentional array than just running two for loops?
Why dose my board display NaN and not the letter. I have tried many different things.

To answer the first question. If you look at your code:
str += '<div class="column">' +
+ board[x][y] + '</div>' + '</div>';
you can see that you have a + +board[x][y], not a + when adding board[x][y]. The unary + tries to convert the value of board[x][y] to a number before concatenating giving you the NaN error( as #Bergi pointed out).
To add an element to the end of an array you can use the push() method (in your caseboard.push(Letters)). This will place the element, which can be an array, at the end of the array.
If you want to replace a line in the array you can use board[x] = Letters.

Related

Javascript - Uncaught TypeError with 2D Array [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I have a simple html page with embedded js functions like below
<script>
function getSelectedPlaces(rowNum, arr) {
var count = 0;
for (let i = 0; i < 9; i++) {
if (arr[rowNum][i] == 0) {
continue;
}
++count;
}
return count;
}
function start() {
var arr = [
[0, 0, 0, 1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 1, 1, 0, 1, 0, 0, 1]
];
alert(getSelectedPlaces(0, arr));
}
</script>
<p style="color: green">
The content above was created with JavaScript.<br>
This content is created with <b>HTML</b>.<br>
You can edit JavaScript and HTML in the left part of the page
and click "<b>Run code</b>" to view results in the right part of the page.
</p>
<b>LESSON 4: CALL A JAVASCRIPT FUNCTION:</b>
<input type=button onClick="start()" value="Generate random number">
However, I am getting an error saying "JavaScript error: Uncaught TypeError: Cannot read property '0' of undefined on line 5", where line 5 is if (arr[rowNum][i] == 0) {
Looking for some help as I am new to JS
You need to separate your sub-arrays with commas:
var arr = [
[0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 0, 1, 0, 0, 1]
];
Your are missing comma in array creation.
var arr = [
[0, 0, 0, 1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 1, 1, 0, 1, 0, 0, 1]
];
function getSelectedPlaces(rowNum, arr) {
var count = 0;
for (let i = 0; i < 9; i++) {
if (arr[rowNum][i] == 0) {
continue;
}
++count;
}
return count;
}
function start() {
var arr = [
[0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 0, 1, 0, 0, 1]
];
alert(getSelectedPlaces(0, arr));
}
start();

Running into Uncaught TypeError: Cannot read property of undefined

I have an algorithm that will modify a 10x10 2D array for a BattleShip game to randomly place ships down in a random direction.
The board looks like this:
var board= [
[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], // 2
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 3
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 4
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 5
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 6
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 7
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // 8
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // 9
];
The algorithm will turn the 0's into 1's and place a random ship at a random index, and at a random direction. The array is like this: var array = [5, 4, 3, 3, 2] (The numbers represent the length e.g. five 1's, four 1's, etc.) The algorithm works good most times and will run until the array is empty.
The problem is, I keep occasionally running into Uncaught TypeError: Cannot read property of <some integer> undefined ONLY when trying to place the ship in either the UP or DOWN direction as it reaches out of bounds. The error occurs for the if statements that check if the direction chosen is out of bounds like so:
// check out of bounds for UP direction
if (x - 1 < 0 || array[x - i][y] == undefined) {
break;
}
// check out of bounds for DOWN direction
if (x + 1 > 9 || array[x + i][y] == undefined) {
break;
}
I believe the error is occurring with something to do with the negative index from trying to perform array[x - i][y] and array[x + i][y]. I thought I already fixed this by adding my additional OR check with x - 1 < 0 and x + 1 > 9 but still I am running into this exception.
Per the comments, the problem is there is no bounds checking on array[x + i] and array[x - i]. Because of that, the calls to array[x +/- i][y] result in a cannot read property ... of undefined error.

requestanimationframe drawing with for loop issue

I'm working on a tetris game - still - and am trying to use requestAnimationFrame to draw my T piece on the black board.
This is the problem. the requestAnimationFrame draws the piece 2 times, then stops drawing even though the for loop is still running. That is, after two times, I only see the black background. When I comment out the black background the piece shows up/animates just fine.
I really am at a loss why this is happening.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
const T = [
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 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, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
]
var piece = T[0];
const player = {
position: {x: 5, y: -1},
piece: piece,
}
function colorPiece(piece, offset) {
for(y = 0; y < piece.length; y++) {
for(x = 0; x < piece.length; x++) {
if (piece[y][x] !== 0) {
ctx.fillStyle = "red";
ctx.fillRect(x + offset.x, y + offset.y, 1, 1);
}
}
}
}
function drawCanvas() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.scale(20, 20);
colorPiece(player.piece, player.position);
}
function update() {
drawCanvas();
requestAnimationFrame(update);
}
update();
OK - working version, with a fiddle here. A number of changes. The biggest are:
Don't use canvas.scale(), since it's cumulative per this (see "More Examples"). Instead, use 20*x and 20*y for blocks 20x20.
Edit Based on a further test, it looks like this was the most significant change.
Rename so that piece is not used as all of a variable, a field name in player, and a parameter of colorPiece
Move the ctx creation into update() (now called doUpdate()) per this fiddle example. Pass ctx as a parameter to other functions.
Move the red fillStyle assignment out of the loop, since you only need to do it once, and then you can draw all the rectangles without changing it.
In the loops:
for(var y = 0; y < thePiece.length; ++y) {
for(var x = 0; x < thePiece[y].length; ++x) { ... } }
Keep x and y in the local scope, using var.
When you are ready to go across a row, that's thePiece[y].length, i.e., the length of the row. Using thePiece.length there would have broken for non-square elements of T.
Added a <p id="log"/> and a javascript framenum so that I could see that doUpdate() was indeed being called.
If you haven't already, make sure to open the console while you're testing so you can see error messages. If drawCanvas causes an error, it will prevent requestAnimationFrame from being called again. I think that's why the fiddle I linked above calls requestAnimationFrame at the beginning rather than the end of the frame-draw function.
Hope this helps!
Code
const T = [
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 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, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]
],
]
const player = {
position: {x: 5, y: -1},
piece: T[0]
}
function colorPiece(ctx, thePiece, offset) {
ctx.fillStyle = "red";
for(var y = 0; y < thePiece.length; ++y) {
for(var x = 0; x < thePiece[y].length; ++x) {
if (thePiece[y][x] !== 0) {
ctx.fillRect(20*(x + offset.x), 20*(y + offset.y), 20, 20);
}
}
}
}
function drawCanvas(ctx) {
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
colorPiece(ctx, player.piece, player.position);
}
var framenum=0;
function doUpdate(timestamp) {
document.getElementById("log").innerHTML = framenum.toString();
++framenum;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
drawCanvas(ctx);
window.requestAnimationFrame(doUpdate);
}
doUpdate();

Practicing 2D Arrays

I'm writing a script that will generate a square room within a larger map. The code looks like this:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
map[mapX + j][mapY] = roomType;
map[mapX][mapY + j] = roomType;
};
};
paintRoom(3, 4);
console.log(map);
The result that I want is 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, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 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 instead I end up with 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, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 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 am I missing here? I'm just starting out, and would like to figure out as much as possible on my own, so if anyone could give me a hint instead of answering outright, I would really appreciate it.
It is doing what you've asked, if you follow the code carefully. It just needs an extra loop. Since what you're doing is 2 dimensional then you'll need 2 loops as well...
var paintRoom = function(mapX, mapY) {
for (var x = 0; x < roomSize; x++) {
for (var y = 0; y < roomSize; y++) {
map[mapX + x][mapY + y] = roomType;
}
};
};
you a missing 1 loop:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
for (var k = 0; k < roomSize; k++) {
map[mapX + j][mapY + k] = roomType;
}
};
};
paintRoom(3, 4);
console.log(map);
https://jsfiddle.net/nfnpesmd/

Calculate percentage from an array

I'm trying to fill a jqPlot Chart with percentage values for a stacked bar chart. I get the data via mysql and COUNT. For example, if I have 4 categories and 12 months, I am able to produce:
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
Which produces a stacked bar chart with numbers, every number of each variable is a months value.
Now I want to show a stacked bar chart where the values of each month are percentages. I must somehow be able to make a percentage calculation with the values of the array. For example: add all values from position two (February) (100/(2+5+3+3)) and then multiply with positon two.
I am nowhere near a solution.
EDIT: Well, thanks for the fast answers.
I will try to explain better. I get the data from the 'MySQL' query, then to a PHP array, then convert it to a string to paste it to the JavaScript for plotting:
Try a for loop to calculate the percent you wanted to get and put it inside an array again
$(document).ready(function(){
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var s5 = new Array();
for (var i = 0; i < s1.length; i++){
//Or use your own formula on getting the value you wanted.
s5.push(100/(s1[i]+s2[i]+s3[i]+s4[i]);
}
// Can specify a custom tick Array.
// Ticks should match up one for each y value (category) in the series.
var ticks = ['January','February','March','April','May','June','July','August','September','October','November','December'];
var plot1 = $.jqplot('chart1', [s1, s2, s3, s4, s5], {
// The "seriesDefaults" option is an options object that will
// be applied to all series in the chart.
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {fillToZero: true}
},
// Custom labels for the series are specified with the "label"
// option on the series option. Here a series option object
// is specified for each series.
series:[
{label:'Hotel'},
{label:'Event Regristration'},
{label:'Airfare'}
],
// Show the legend and put it outside the grid, but inside the
// plot container, shrinking the grid to accomodate the legend.
// A value of "outside" would not shrink the grid and allow
// the legend to overflow the container.
legend: {
show: true,
placement: 'outsideGrid'
},
axes: {
// Use a category axis on the x axis and use our custom ticks.
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
},
// Pad the y axis just a little so bars can get close to, but
// not touch, the grid boundaries. 1.2 is the default padding.
yaxis: {
pad: 1.05,
tickOptions: {formatString: '$%d'}
}
}
});
});
<script>
/* are there to be more than 4 arrays? */
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
/* add new arrays to this array */
var arrs=[s1,s2,s3,s4];
var pc=[];
for( var i=0; i < arrs[0].length; i++ ){
var a=0;
for( var j=0; j < arrs.length; j++ ){
if( !isNaN( arrs[ j ][ i ] ) ) a+=arrs[ j ][ i ];
}
console.log( 'i=%d, j=%d, a=%d', i, j, a );
/* confused by the `then multiply with positon two` */
pc.push( a > 0 ? Math.round( 100 / a ) : 0 );
}
alert( pc );
</script>
If I understood correctly, it will work in your case :
function getPercent(array){
var return_array = [];
var total_sum = 0; // total sum of data
for(var i = 0; i < array.length; i++){
total_sum += array[i].reduce(function(pv, cv) { return pv + cv; }, 0);
}
for( var i=0; i < array[0].length; i++ ){
var sum = 0; // month sum
for( var j=0; j < array.length; j++ ){
sum += array[j][i];
}
return_array[i] = sum*100/total_sum; // percent calculation of the month
}
return return_array;
}
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var data=[s1,s2,s3,s4];
var percent = getPercent(data);
console.log(percent);
And results are :
[0, 61.904761904761905, 4.761904761904762, 4.761904761904762, 19.047619047619047, 9.523809523809524, 0, 0, 0, 0, 0, 0]

Categories

Resources