variable changes when it shouldn't - javascript

Here is what I am trying to do with this code below. I am receiving the position of an enemy every six frames from the server.
The client-side enemies are stored in an array (called enemies)as objects and these enemy objects have position vectors as a property (called pos), that has an x and y. There is also another position vector (called previousPos) that stores the second most recent position the enemy was at. I am doing this so I can lerp between these two positions so the game can consume less bandwidth while still being smooth.
data[i].x contains the x position that the server sends out to the client every 6 frames, and I am attempting to set the position of the enemy (with pos) to what the server sent out while keeping the enemy's previous position (with previousPos) so I can lerp between them.
This is the function I run whenever the server sends a message regarding enemy stats:
for (var i = 0; i <= enemies.length - 1; i++) { //iterates through all enemies
testerino++; //used to ensure what iteration this is on
if (data[i].x != undefined || data[i].y != undefined) {
console.log(enemies[i].pos.x,enemies[i].previousPos.x,data[i].x, testerino);
if (data[i].x != enemies[i].pos.x) enemies[i].previousPos.x = enemies[i].pos.x; //proven they are different
if (data[i].y != enemies[i].pos.y) enemies[i].previousPos.y = enemies[i].pos.y;
console.log(enemies[i].pos.x,enemies[i].previousPos.x,data[i].x, testerino);
}
if (data[i].x != undefined) enemies[i].pos.x = data[i].x;
if (data[i].x != undefined) console.log(enemies[i].pos.x,enemies[i].previousPos.x,data[i].x, testerino);
if (data[i].y != undefined) enemies[i].pos.y = data[i].y;
}
In the console it returns:
(first number is pos.x, second: previousPos.x, third: what loop we are on)
sketch.js:213 587.8102829077167 587.8102829077167 567.8102829082868 225
sketch.js:216 587.8102829077167 587.8102829077167 567.8102829082868 225
sketch.js:219 567.8102829082868 567.8102829082868 567.8102829082868 225
Notice that between line 216 and 219 only enemies[i].pos.x is assigned to, and yet somehow enemies[i].previousPos.x was also changed as well! Even though I never assigned anything to it!
Any ideas to what may have went wrong?

Earlier in the code I did indeed do:
this.previousPos = this.pos;
within the constructor of the enemy function, not knowing that javascript has something called referencing. This means that previousPos was used as a nickname for position, so all changes to pos happenned to previousPos too, as they were the same variable. The library I used had a vector copy method (now i know why its there...) and I think I replaced that code with:
this.previousPos = this.pos.copy()
as to ensure that previousPos was made into a clone, and not a nickname to the same variable as assignment through the equals sign would've done.

Related

changing values in array

I am trying to build a battleship game and using functions.
I wish to create and randomise 1 & 0 in my array every time I run the function as seen in the array below
Since it is a battlefield game, is there any way to make the 1s be in a row /column of 4/3/2/1? , to mimic the different sizes of the battleships
let battelfield = [
[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,1,0,0,0],
[0,0,0,0,0,0,1,0,0,0],
[1,0,0,0,0,0,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0],
[1,0,0,1,0,0,0,0,0,0],
[1,0,0,1,0,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,0]
]`
For a battleship, the way I would do it would be (assuming your grid is already filled with 0s):
For each ship
randomly select a starting position
randomly select a direction (up, down, left, right)
add your ship (by changing however many 1s you need to, based on the size of the ship).
The checks you need to add would be:
At step 1, make sure there isn't a boat there already, in which case pick again.
At step 2, make sure you're not going to hit the side of your game board, or another ship, in which case try another direction. If all 4 directions have been tried and there isn't enough space for a ship, back to step 1.
I usually don't give full answers when OP doesn't really show they tried but I liked the challenge.
The idea is to:
Set your empty board.
Choose a random point in the board where the ship will start
Choose direction (H or V)
With the random point and direction, make sure there is room for the ship according to the limits of the board
Create a list of positions the ship will take
Test all positions to make sure they are free
Set the positions on the board as filled.
At any given time, if a check is not fulfilled I've put continue; this will stop the current iteration and back to the beginning of the while. That way, the code runs until it finds a spot, and return to leave the loop.
Also, I've made a 1d array instead of 2d because it felt easier for mathing it out and manipulations. Feel free to convert to 2D afterward, or not.
let battlefield = new Array(10*10).fill(0);
placeShip(3);
placeShip(4);
placeShip(4);
placeShip(5);
console.log(battlefield);
function placeShip(length){
while(true){
const start = Math.round(Math.random()*99);
if(battlefield[start]==='1') continue;
const orientation = Math.random() <=.5?'H':'V';
// Fill the positions where the ship will be placed.
const positions = new Array();
if(orientation === 'H'){
// First make sure we have room to place it
if(10-((start+1) % 10) < length)continue;
for(let p=start;p<start+length;p++){
// Set for each length the position the ship will take.
positions.push(p);
}
}else if(orientation === 'V'){
// Same as for H but we divide by 10 because we want rows instead of cells.
if(10-((start/10) % 10) < length)continue;
for(let p=start;p<start+length*10;p+=10){
// Set for each length the position the ship will take.
positions.push(p);
}
}
// Now let's check to make sure there is not a ship already in one of the positions
for(let i=0,L=positions.length;i<L;i++){
if(battlefield[positions[i]]!=="0")continue;
}
// Now let's put the ship in place
for(let i=0,L=positions.length;i<L;i++){
battlefield[positions[i]] = 1;
}
return;
}
}

How do I implement minimax with the chess.js node module

I'm currently working on creating a chess engine using chess.js, chessboard.js, and the minimax algorithm. I eventually want to implement alpha-beta, but for right now, I just want to get minimax to work. It seems like the computer is thinking, but it usually just does Nc6. If I move the pawn to d4, it usually takes with the knight, but sometimes it just moves the rook back and forth in the spot that was opened up by the knight. If there is nothing for the knight to take, the computer moves the Rook or some other pointless move. My best guess is that all of the moves are returning the same valuation, and so it just makes the first move in the array of possible moves, hence the top left rook being a prime target. I should note that part of my confusion is around the way a recursive function works, and most of the stuff I've found online about recursive functions leaves me more confused than when I started.
I'm using Express.js with the chessboard.js config in public/javascripts as a boardInit.js that's included in the index.ejs folder, and when the user makes a move, a Post request is sent to /moveVsComp. It sends it to the server, where the app.post function for /moveVsComp tells chess.js to make the move that the player made.
After the player move is recorded, the computer calls the computerMoveBlack function.
Function call in the post request:
let compMove = computerMoveBlack(3);
game.load(currentFen)
game.move(compMove)
res.status(200).send({snapback: false, fen: game.fen()})
computerMoveBlack Function:
function computerMoveBlack(depth) {
let bestMove = ['', 105];
for (let move of game.moves()) {
game.move(move)
let value = minimax(move, depth-1, false)
if (value < bestMove[1]) {
bestMove = [move, value]
}
game.undo()
}
console.log(bestMove[0])
return bestMove[0]
}
This function loops through all of the moves, and I was using this because it seemed like this was the best way to keep the best move instead of just returning a valuation of the current position.
Minimax Function:
function minimax(node, depth, maximizingPlayer) {
let value = maximizingPlayer ? -105 : 105
if (depth === 0 || game.game_over()) return getValuation()
if (maximizingPlayer) {
for (let move of game.moves()) {
game.move(move)
value = Math.max(value, minimax(move, depth-1, false))
game.undo()
}
return value
} else {
for (let move of game.moves()) {
game.move(move)
value = Math.min(value, minimax(move, depth-1, true))
game.undo()
}
return value
}
}
getValuation Function:
function getValuation() {
let evalString = game.fen().split(' ')[0];
let score = 0;
score += (evalString.split('r').length -1) * -5 || 0;
score += (evalString.split('b').length -1) * -3 || 0;
score += (evalString.split('n').length -1) * -3 || 0;
score += (evalString.split('q').length -1) * -9 || 0;
score += (evalString.split('p').length -1) * -1 || 0;
score += (evalString.split('R').length -1) * 5 || 0;
score += (evalString.split('N').length -1) * 3 || 0;
score += (evalString.split('B').length -1) * 3 || 0;
score += (evalString.split('Q').length -1) * 9 || 0;
score += (evalString.split('P').length -1) || 0;
return score;
}
I should note that I understand using a FEN in the valuation is very slow for this use case, but I'm not really sure what a better alternative would be.
Just as kind of a recap of the questions, I'm trying to figure out why it just makes the first move in the array every time, what is wrong with the format of my functions, and what a better way to get the valuation of a position is as opposed to string manipulation of the FEN.
I will point out a few suggestions below to help you on the way if you are just getting started. First I just want to say that you are probably right that all moves get the same score and therefore it picks the first possible move. Try to add some Piece Square Tables (PST) to your Evaluation function and see if it puts pieces on appropriate squares.
I would implement a Negamax function instead of Minimax. It is way easier to debug and you won't have to duplicate a lot of code when you later make more optimizations. Negamax is one of the standard chess algorithms.
It seems like you don't do the legal move generation yourself, do you know how the board is represented in the library that you use? Instead of using the FEN for evaluation you want to use the board (or bitboards) to be able to do more advanced evaluation (more on it further down).
The min/max value of -105/105 is not a good way to go. Use -inf and inf instead to not get into troubles later on.
Regarding the evaluation you normally use the board representation to figure out how pieces are placed and how they are working together. Chessprogramming.org is a great resource to read up on different evaluation concepts.
For your simple starting evaluation you could just start with counting up all the material score at the beginning of the game. Then you subtract corresponding piece value when a piece is captured since that is the only case where the score is changing. Now you are recalculating lots of things over and over which will be very slow.
If you want to add PST to the evaluation then you also want to add the piece value change for the moving piece depending on the old and new square. To try and sum up the evaluation:
Sum up all piece values at start-up of a game (with PST scores if you use them) and save it as e.g. whiteScore and blackScore
In your evaluation you subtract the piece value from the opponent if you capture a piece. Otherwise you keep score as is and return it as usual.
If using PST you change the own score based on the new location for the moved piece.
I hope it makes sense, let me know if you need any further help.

Minesweeper game - Maximum call stack side exceeded

So I'm making a minesweeper game in JS.
I have this function:
function doSquare(x, y) { //takes x,y coordinates of a square. checks and acts accordingly to what's around it
var revealed = [];
var size = board.length;
var mines = countAround(x,y);
table.rows[x].cells[y].innerHTML = mines;
if (mines === 0) {
for (var i=Math.max(0,x-1), l = Math.min(x+1, size-1); i<=l; i++) {
for (var j=Math.max(0, y-1), k = Math.min(y+1, size-1); j<=k; j++) {
if (x == i && y==j) {continue;}
if (revealed.indexOf(i+"."+j) === -1) {
doSquare(i, j);
revealed.push(i+"."+j);
}
}
}
}
}
The board's rows and cols are equal. countAround(x,y) returns the amount of mines around (x,y); revealed is an array which stores which squares have already been dealt with, to prevent dealing with them again.
This function is supposed to, when a square is clicked, reveal the number of mines near it and write it into the cell. Then, it checks every square around it, and if that square hasn't already been dealt with (if it isn't in the revealed array), the function doSquare() runs on it again. The function will not 'spread' from a square if the square has any mines next to it.
I get an error: maximum call stack size exceeded. But the function stops its 'spreading' upon reaching a square with mines, and also doesn't run on a square which already has been taken care of. So I would love an explanation as to why this happens.
I think the problem is that 'revealed' is defined inside your function. This means that each time the function is called, a new 'revealed' is created locally for the function. Therefore, a square with no mines around it will call doSquare for an adjacent square, which may in turn call doSquare on the original square. However, doSquare won't remember that it has already checked this square as a new local version of 'revealed' is created for this call.
Solution:
Either pass 'revealed' as an argument to doSquare so all calls use the same variable (i.e. function doSquare(x, y, revealed){..., making the initial call as doSquare(x, y, []);, or declare 'revealed' outside of doSquare, and empty it each time you wish to check for mines.

How to handle collisions with tile id javascript

Ive written a small game in JavaScript with the html5 canvas and am at the point of collision detection and getting rather confused.
I build my levels in tiled and then import the saved JSON file into the game.
In my level draw function i have a check to see if there are any layer properties and if the layer properties are collisions. If it does, that layer is returned and the loop carries on. When finished, the layer that was returned with collisions gets put through another loop so that the the tile values can be put into an array.
So in this array i have i have a series of arrays depending on how many rows of tiles there are in the layer, and these rows hold the data for that row for each tile.
What i would like to do is when the player x/y is in one of the tiles which doesn't equal 0, then collide.
How would i do this if all i have is the value that is in that tile space?
Here is a link to the live version of the game so you can see for yourself how the tiles are stored, i have put in some console.logs so you might want to use firebug or equivalent to look at that. To log in use
Username - guest
password - guest
TO clarify my question is: How do i create collisions between my player x/y and a tile value??
Thanks very much
UPDATE
Ok so i think im nearly there, my problem at the moment is how do i read the objects x and y out of the array and then check the collision, at the moment the collision detection on works with the last tile in the array (the bottom right of the screen), here is the code i implemented to go through the array:
this.check_coll = function(array,posX, posY){
var collided = false,
block_x,
block_y,
block_cx,
block_cy,
combined_hw = 32,
combined_hh = 32,
player_cx = posX+(32/2),
player_cy = posY+(32/2);
array.forEach(function(value,i){
//get obj x
block_x = value[1];
//get obj y
block_y = value[2];
block_cx = block_x+(32/2);
block_cy = block_y+(32/2);
collided = Math.abs(player_cx - block_cx)< combined_hw
&& Math.abs(player_cy - block_cy)< combined_hh;
});
return collided;
}
Any ideas guys??

Unfreeze bodies in Box2Djs or prevent from exiting world

I am working on a server side physics experiment where the user controls an object through a socket. The problem I am running into results when the user moves the object outside the boundaries of the world.
I am using Box2Djs as installed through npm.
I create world 500x500 and then attach the following listener to it:
var boundaryListener = new b2d.b2BoundaryListener();
boundaryListener.Violation = function (body) {
//we will move this body to the opposite side
var position = body.GetWorldCenter();
//snap to opposite side
if (position.x < 0) {
position.x = worldAABB.upperBound.x + position.x;
}
if (position.y < 0) {
position.y = worldAABB.upperBound.y + position.y;
}
if (position.x > worldAABB.upperBound.x) {
position.x -= worldAABB.upperBound.x;
}
if (position.y > worldAABB.upperBound.y) {
position.y -= worldAABB.upperBound.y;
}
body.m_flags = body.m_flags & (~b2d.b2Body.e_frozenFlag); //does nothing :(
}
this.world.SetBoundaryListener(boundaryListener);
worldAABB is the b2AABB that the world uses as a boundary.
The problem is that I have noticed that when the boundary listener is fired, the flags are set to 22 which is allowSleep, frozen, and island flags. It would seem that when a b2Body passes outside the world boundary, it is frozen. That last line is an attempt to unfreeze the body by messing with the internal flags, but I have a distinct feeling that's the wrong way to do it.
How can I unfreeze the body? There are no functions that clear the frozen flags that I can see (the javascript is over 10,000 lines long so I honestly haven't read the whole thing) and placing some bodies as walls seems to have no effect (the user's object passes right through them).
My walls are created like so:
//create walls
var wallShape = new b2d.b2PolygonDef();
wallShape.SetAsBox(500, 10);
wallShape.density = 0.0;
wallShape.friction = 0.3;
var bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 20);
var north = this.world.CreateBody(bodyDef);
north.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 499);
var south = this.world.CreateBody(bodyDef);
south.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(499,250);
bodyDef.angle = Math.PI / 2;
var east = this.world.CreateBody(bodyDef);
east.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(1, 250);
bodyDef.angle = Math.PI / 2;
var west = this.world.CreateBody(bodyDef);
west.CreateShape(wallShape);
Does anyone have any insights on how to fix this? There is very very little documentation I can find on using Box2D in javascript aside from the flash documentation that the website points to (which doesn't match half the time) and the C++ documentation which doesn't even talk about freezing.
It would probably be helpful to mention that the world has no gravity and all the objects have some linear and angular damping (its supposed to be a psuedo-in-space feel).
I had investigated Box2Djs source, and found next thing. Every time step Box2Djs checks if the body is inside the world boundaries. If body is out of range, then it "frozing", i.e. its excluding from collision detection. There this code (Body.js line 414):
Freeze: function(){
this.m_flags |= b2Body.e_frozenFlag;
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0.0;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.DestroyProxy();
}
}
Pay attention, this check performs every time step (b2Island.js 244). So, if you set e_frozenFlag at boundary listener, it will do nothing: flag will be set up at next time step. Thats more, after body had frozen, it losses its veolcity and its shapes looses theirs proxies in broad phase (as you can see from code above). Looks like proxies are not restroing automaticly, so, reseting flag is not enough.
I also not found somewhere in Box2Djs interface or logic for unfreezing bodies. Doing this manually is some kind of dirty trick, because you should acces BroadPhase, which is Box2Djs internal. Thats more, it dont help you, because on freezing body losses its velociy. But, as I see, you need continue body moving.
Solution is next. You should prevent body frozing at all in order to keep body in simulation after it moved out of world boundaries. It may be done by next trick. First, set world boundary with some large value. Then, set contact listener, and when body touches the walls, perform your boundary violation logic.
How to set contact listener in C++ you can see there: https://www.iforce2d.net/b2dtut/collision-callbacks Sory, I dont know java script and can't say, how to do this in Box2Djs.

Categories