I am trying to make a game in Javascript. The game board is intialized to a zero-filled 2-D array. However, when I am setting the value of a single point, the complete column is getting set with that value. I think this is some issue with the way I am initializing the Array.
Method 1
# initialization
gameState = Array(6).fill(Array(7).fill(0))
# later in the game
gameState[2][4] = 1
# results in complete 4th index column to be assigned the value 1, like so -
0: (7) [0, 0, 0, 0, 1, 0, 0]
1: (7) [0, 0, 0, 0, 1, 0, 0]
2: (7) [0, 0, 0, 0, 1, 0, 0]
3: (7) [0, 0, 0, 0, 1, 0, 0]
4: (7) [0, 0, 0, 0, 1, 0, 0]
5: (7) [0, 0, 0, 0, 1, 0, 0]
Method 2
# initialization
let gameState = [];
for (let i=0; i<MAX_ROWS; i++) {
let row = []
for (let j=0; j<MAX_COLUMNS; j++) {
row.push(0)
}
gameState.push(row);
}
# again similar assignment
gameState[2][4] = 1
# results in correct state of the array
0: (7) [0, 0, 0, 0, 0, 0, 0]
1: (7) [0, 0, 0, 0, 0, 0, 0]
2: (7) [0, 0, 0, 0, 1, 0, 0]
3: (7) [0, 0, 0, 0, 0, 0, 0]
4: (7) [0, 0, 0, 0, 0, 0, 0]
5: (7) [0, 0, 0, 0, 0, 0, 0]
Can someone please explain what I am doing wrong here?
Your problem is pretty simple.
Array(6).fill(Array(7).fill(0))
Let's explain what this does.
Array(6)
creates a holey array with space for 6 items.
.fill(...)
will fill up these 6 holes with what ever you put in as argument.
Now comes the issue..
In Javascript, the arguments are evaluated before the execution of the function is run.
This means (in this exact case where .fill(...) is only ran once) your code is exactly the same as:
const innerArray = [0,0,0,0,0,0,0];
gameState = Array(6).fill(innerArray);
This means it fills the outer array with exactly the same array instance 6 times.
What you want is to create separate arrays each time. Just do this instead:
gameState = [...Array(6)].map(() => [...Array(7)].map(() => 0))
Related
I haven't been able to update these functions from an old application using glMatrix 1.2 to glMatrix 2.7:
calculateNormal() {
mat4.identity(this.normalMatrix);
mat4.set(this.modelViewMatrix, this.normalMatrix);
mat4.inverse(this.normalMatrix);
mat4.transpose(this.normalMatrix);
}
And the following function of multiplying a matrix by a 4-component vector doesn't exist:
calculateOrientation() {
mat4.multiplyVec4(this.matrix, [1, 0, 0, 0], this.right);
mat4.multiplyVec4(this.matrix, [0, 1, 0, 0], this.up);
mat4.multiplyVec4(this.matrix, [0, 0, 1, 0], this.normal);
}
In common the normal matrix is 3*3 matrix (mat3).
But anyway, glMatrix is well documented and according to the documentation of mat4 and vec4, your code can be ported like this:
calculateNormal() {
this.normalMatrix = mat4.clone(this.modelViewMatrix);
mat4.invert(this.normalMatrix, this.normalMatrix);
mat4.transpose(this.normalMatrix, this.normalMatrix);
}
May be it is not necessary to create the vectors in the following, but I don't kow if the vectors are existing in your case:
calculateOrientation() {
this.right = vec4.create();
vec4.set( this.right, 1, 0, 0, 0 );
vec4.transformMat4( this.right, this.right, this.matrix );
this.up = vec4.create();
vec4.set( this.up, 0, 1, 0, 0 );
vec4.transformMat4( this.up, this.up, this.matrix );
this.normal = vec4.create();
vec4.set( this.normal, 0, 0, 1, 0 );
vec4.transformMat4( this.normal, this.normal, this.matrix );
}
I am trying to develop a 2 player checkers game, for my college, but I am stuck at getting the index of the 2D array when I click on the piece.
I divided my HTML code in:
table - the game board
row - each row is the height of the array
cell - each cell is a piece and the width of the array
Then I setted a default array to start the game:
var board = [
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[2, 0, 2, 0, 2, 0, 2, 0],
[0, 2, 0, 2, 0, 2, 0, 2],
[2, 0, 2, 0, 2, 0, 2, 0],
];
Where the:
- 0 - empty cell
- 1 - Player 1 pieces
- 2 - Player 2 pieces
To get the position I am using this code
function getPosition() {
$('.row').on('click', function() {
console.log( $('.row').index(this) );
});
$('.cell').on('click', function() {
console.log( $('.cell').index(this) );
});
}
Get the height array position which should be between 0 and 7 are ok, but the cell from the row should be between 0 and 7 too, but using this I am getting from 0 to 63, using this parameters I have no idea how to start the next comparisons of the game.
Here is the code from codepen
http://codepen.io/michaelthompson/pen/jVdrav
In each instance you can simply use $(this).index() which will return the index within the element's siblings
But since clicking on a row always means clicking a cell you could combine them and do
$('.cell').on('click', function() {
var $cell = $(this),
columnIndex = $cell.index(),
rowIndex = $cell.parent().index();
});
What $('.cell').index(this) is doing is taking the whole collection of the class within the page and that's why you are getting 0-63
I need to draw a 3d house model (walls only) from a 2d path or array (explained later) I receive from FabricJS editor I've built. The type of data sent from 2d to 3d views doesn't matter.
My first (and only quite close to what I want to get) attempt was to create the array of 1s and zeros based on the room I want to draw, and then render it in ThreeJS as one cuboid per 'grid'. I based this approach on this ThreeJS game demo. So if the array look like this:
var map = [ //1 2 3 4 5 6 7 8
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1,], // 1
[1, 1, 0, 0, 1, 0, 0, 0, 0, 1,], // 2
[1, 0, 0, 0, 1, 1, 0, 0, 0, 1,], // 3
[1, 0, 0, 1, 1, 1, 1, 0, 0, 1,], // 4
[1, 0, 0, 0, 1, 1, 0, 0, 1, 1,], // 5
[1, 1, 1, 0, 0, 0, 0, 1, 1, 1,], // 6
[1, 1, 1, 0, 0, 1, 0, 0, 1, 1,], // 7
[1, 1, 1, 1, 1, 1, 0, 0, 1, 1,], // 8
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
];
I iterate through the array and render one block for every 1, and calculate it's position from indexes from the 2d 'map' (my array).
var UNITSIZE = 250, units = mapW;
for (var i = 0; i < mapW; i++) {
for (var j = 0, m = map[i].length; j < m; j++) {
if (map[i][j]) {
var wall = new t.Mesh(cube, material);
wall.position.x = (i - units/2) * UNITSIZE;
wall.position.y = WALLHEIGHT/2;
wall.position.z = (j - units/2) * UNITSIZE;
scene.add(wall);
}
}
}
It worked great till I wanted to place other models (.obj, but it doesn't matter. Let's call them furniture) near the walls. Each piece of furniture has it's (x=0, y=0, z=0) point in the center of the model, and since walls are cubes (with the same coord system, with 0 point in the center), furniture are rendered in the center of the wall (when we place it in the corner, only 1/4 of the model is visible). This is more/less how it looks like:
(black - how the walls should look like, blue - each cuboid of the wall, red - piece of furniture)
Thats why I would like to render walls as planes, probably from a 2d closed patch (I can export it from Fabric without a problem). I don't need walls to be thick nor to be visible "from behind", when camera moves through the wall. Any clues on how to achieve something like this?
"Help me StackOverflow, your my only hope."
You can manually populate the vertex and face arrays of a THREE.js mesh, so if you can export the closed path you need for example as an array of coordinates, you can iterate over it, and push needed information to your wall object.
Something like this
var coordArray = [...]; //Array of corner points of a closed shape from your source. Here assumed to be THREE.Vector2() for simplicity.
var walls = new THREE.Geometry();
for(var i = 0; i < coordArray.length(); i++){ //iterate over the coordinate array, pushing vertices to the geometry
var coordinates = coordArray[i];
walls.vertices.push(new THREE.Vector3(coordinates.x, coordinates.y, 0)); //vertex at floor level
walls.vertices.push(new THREE.Vector3(coordinates.x, coordinates.y, 10)); //vertex at the top part of the wall, directly above the last
}
var previousVertexIndex = walls.vertices.length - 2; // index of the vertex at the bottom of the wall, in the segment we are creating faces for
for(var i = 0; i < walls.vertices.length; i += 2){
walls.faces.push(new THREE.Face3(i, i + 1, previousVertexIndex));
walls.faces.push(new THREE.Face3(i + 1, previousVertexIndex + 1, previousVertexIndex));
previousVertexIndex = i;
}
walls.computeVertexNormals();
walls.computeFaceNormals();
scene.add(new THREE.Mesh(walls, new THREE.MeshLambertMaterial());
I have a grid stored in a one-dimensional array. The grid can be of variable size. I now have different blocks (2x2,2x3,2x4,3x3,3x4,3x5, 4x4 and so forth).
How do I fill the grid in now? It can have unused spaces left in the end but what is the fastest way here without looping through the array over and over trying out sizes?
For instance with this 5x5 grid.
var g1 = [
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
]
You could use a backtracking algorithm to solve this type of problem:
function process(var blockstate) {
if(gridIsFullOfBlocks(blockstate))
return true;
if(canPlaceBlock(blockstate)) {
blockstate = placeLargestBlock(blockstate);
return process(blockstate);
}
return false;
}
function fillBlocks(int size) {
var blockstate = new Array(size);
if(process(blockstate))
displayBlockstate(blockstate);
else
displayError(blockstate);
}
I have an array that looks like this
board = [
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 0 ,0, 0, 0]
];
Is there any way, just by using 2 for loops, like this
for(var i = 0; i < 7; i++){
for(var j = 0; j < 7; j++){
//actions here
}
}
to place 6 values of 1, first value of 1 to replace the first 0 in the array and the next 5 to be placed using the same rules for placing a queen on a chessboard. The result should look like this
board = [
[1, 0, 0, 0, 0 ,0, 0, 0],
[0, 0, 1, 0, 0 ,0, 0, 0],
[0, 0, 0, 0, 1 ,0, 0, 0],
[0, 1, 0, 0, 0 ,0, 0, 0],
[0, 0, 0, 1, 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]
];
I'm new to javascript and I have no clue on how to start this. Could someone please give me some hints.
board[xCord][yCord] = ValueToInsert;
I may have misread your question, so here is some more info.
You can "push" another array into a 1d array.
myArr.push([]);
Then you push the value like this:
myArr[Xcord].push(YValue);
You need to make a function to check whether placing a queen on xy coordinates is valid. The function would check whether there is a queen in that row, column or diagonals. You can also make those three sub-functions of the main function.
Then, as you go through the loop, use that function for each field and if it returns true, place the queen. If false, move on.
Of course, there will be many solutions in the end, so you might want to keep/store all of them in an array.
Also, think of ways to optimize the algorithm: for example, if you set a queen in a row, there's no need to check any other fields in that row, etc.
And when you decide to really go advanced with your skills, try using recursive functions to generate the solutions.