Refactoring JavaScript function results - javascript

I'm working on a project using Leaflet's Mapping API. Right now, I'm cleaning up my code and there's one section I feel could be made better.
I have it set when the location is found, the location is checked both in accuracy and in bounds:
function checkLocation(position)
{
if(position.accuracy > 100)
{
return 4;
}
else if((position.latlng.lat <= **bound** || position.latlng.lat >= **bound**) || (position.latlng.lng >= **bound** || position.latlng.lng <= **bound**))
{
return 5;
}
return 0;
}
Basically, if the accuracy is too low, I throw an error with error code 4. If the coordinates are outside of where I want them to be, I throw an error with error code 5 (These are to correspond to Leaflet's builtin error codes 1-3 so I can switch on them later). I return 0 just to say there wasn't an error.
This function is called by the locationFound event, which has the following code:
var temp = checkLocation(position);
if(temp != 0)
{
// Handle error code
return;
}
This also works, but I'm not fond of how this looks. What I want is for this bit to only take like two to three lines, preferably without an if statement. I originally had the code for checkLocation in this section, but I thought having it on its own would make for cleaner and more reader-friendly code.
My question is is there any way to improve this bit? I looked into lambda expressions but didn't think it fit and I tried using a Promise, but at that point, I was losing lines trying to cut down on lines. I don't want to code golf the code, but I'm still pretty new to JavaScript and I don't know if there's any way to simplify this while still looking professional. I'm also up for changing the checkLocation function if it means improving the code.

If you refactor to this:
function invalidAccuracy(position) {
return position.accuracy > 100;
}
function outOfBounds(position) {
return (position.latlng.lat <= **bound** || position.latlng.lat >= **bound**) || (position.latlng.lng >= **bound** || position.latlng.lng <= **bound**);
}
You can handle it like this:
function checkLocation(position) {
if(invalidAccuracy(position))
return 4;
if(outOfBounds(position))
return 5;
return 0;
}
You can (if you want) put it in 1 line then:
return invalidAccuracy(position) ? 4:
outOfBounds(position) ? 5 :
0;

Related

Javascript - if-statement with multiple numeric conditions doesn't work

I'm trying to make a simple program in javascript+html. If exp exceeds within a certain range/exceeds a certain number, the level displayed goes up by 1. I've tried to make it show onload, but the level doesn't change no matter what happens to the exp staying at the highest one I've written code for so far.
Javascript:
var exp6 = localStorage.exp6;
var pexp6 = parseInt(exp6);
function char6() {
res.innerHTML = res6;
var lsps = pexp6;
localStorage.setItem("lsp", lsps);
return PrUpdate();
}
var lsp = localStorage.lps;
function PrUpdate() {
if (lsp <= 999) {
lvl.innerHTML = 1;
}
else if (lsp >= 1000 && lsp <= 1999) {
lvl.innerHTML = 2;
}
else if (lsp >= 2000 && lsp <= 2999) {
lvl.innerHTML = 3;
}
else if (lsp >= 3000 && lsp <= 3999) {
lvl.innerHTML = 4;
}
else if (lsp >= 4000 && lsp <= 4999) {
lvl.innerHTML = 5;
}
}
I've also included the setChar() function in the window.onload of the page. I've tried including the function itself in it as well, but whether I add it at the end of the setChar() or in the window.onload the problem stays the same. All other functions work fine, it's just this part that doesn't. I'm also trying to make it generic to fit other 'accounts' I'm trying to make to save myself time. But I just can't make it work.
Edit:
I've figured out why it didn't work, and it was cause I had my localStorage.lsp in the wrong place.
I'm trying to figure out now how to make it so I don't have to refresh the page to get it to appear.
[ Solved my issue :), if unclear by my edit above]
The way you are trying to access values from localstorage is incorrect. This is not valid: localstorage.exp6.
Instead try this: localstorage.getItem('exp6')
See the documentation of Web Storage API for more information

Collision detection is not returning inside limits

Full code here
I am trying to setup the functions to detect collisions and for now just log to the console. This is the section for checkCollision function;
Player.prototype.update = function(dt) {
checkCollision(this.leftLimit, this.rightLimit);
this.leftLimit = this.x - 40.5;
this.rightLimit = this.x + 40.5;
}
function checkCollision(playerl,playerr) {
for (var i = 0; i < 5; i++) {
var thisEnemy = allEnemies[i];
if (thisEnemy.leftlimit > playerl && thisEnemy.rightLimit < playerr) {console.log("1")}
else {console.log('else')}
}
}
Question
The character is never registering as colliding with the enemy, why is this not working?
Testing/Debugging
I know this function is working as consoles logging else, I've also put logging in other locations and when in the Enemy.prototype.update function, console was showing values like 202.000000093, since the for..else function is using < or >, not absolute values, that should be fine, but still nothing is matching inside the player left and right limits. I also tried changing the Enemy limits to be smaller, +/- 40.5, incase the enemy was too wide to fit inside the player limits.
player.leftLimit and player.rightLimit are undefined when checkCollision method is first running
I added a better if statement to check if there's a collision;
if (
thisEnemy.leftLimit < player.rightLimit &&
thisEnemy.rightLimit > player.leftLimit &&
thisEnemy.upperLimit > player.lowerLimit &&
thisEnemy.lowerLimit < player.upperLimit) {
console.log("collision");
}

Recursive function (maze solver) - can't find a bug;(((

I am studying javascript and all is pretty easy to me except for some things like recursive functions. I do understand the way they work but while working with an example, I realized I can't capture the bug that prevents it from functioning...
I have an array (map) below (0 is a closed cell, 1 means path is open) and the recursive function I am trying to use to "find" path out of this "maze" by going from its top left cell to the bottom-right one.. Basically just make the function to "find" this path of 1s. But it fails;(
var map = [
[1,1,0,0],
[0,1,1,0],
[0,0,1,0],
[0,0,1,1]
]
function findpath(x,y) {
if (x<0 || x>3 || y<0 || y>3) return false; //if it is outside of map
if (x==3 && y==3) return true; // if it is the goal (exit point)
if (map[y][x]==0) return false; //it is not open
map[y][x]=9; //here marking x,y position as part of solution path outlined by "9"
if (findpath(x,y-1) == true) return true;
if (findpath(x+1,y) == true) return true;
if (findpath(x,y+1) == true) return true;
if (findpath(x-1,y) == true) return true;
map[y][x]=8; //unmark x,y as part of solution path outlined by "8"
return false;
};
findpath(0,0);
The description of "it fails" is rarely, if ever, a useful error report.
In order for someone to help you, they need much more detail than that.
In this case, the import details came out of the JavaScript error console. You should always include any error messages in your question.
However, since your code was quite short I was able to cut-and-paste it into my console where I got the message:
RangeError: Maximum call stack size exceeded
This means that your function is recursing too deeply. You either
Have bad logic in your puzzle and you are recursing into the same values over and over again
The puzzle is too complicated and you can't solve it recursively like that.
You need to add console.log statements and observe what the code is doing and see why it is going so deep.
If it is a logic error, fix the logic error. (Hint: I'm pretty sure it is -- you never mark on the map where you've been so it freely goes back and forth and back and forth over the same spot).
If it isn't, then you need to use some more advanced trick to work around the recursion, such as using a generator function and storing the changes you do in the map separately.
Quick answer:
Its locking in a loop because the order of the checks.
Start from 0:0 then try 0:1. Then from 0:1 --"Ummm... 0:0 looks promising. Let's go there". So go back to 0:0... so it locks...
Try leaving backtracking last :
if(findpath(x+1,y)) return true;
if(findpath(x,y+1)) return true;
if(findpath(x,y-1)) return true;
if(findpath(x-1,y)) return true;
This get you out of the lock just by swapping the issue around. If you start from 3:3 trying to reach 0:0 you'll be locked again.
Whats missing its a way to mark visited squares.
I think you are trying to implement an a* algorithm
UPDATE:
Here is your idea working. Just added the backtracking checks you almost implemented.
<html>
<head>
</head>
<body>
<script>
var map = [
[1,1,0,0],
[0,1,1,0],
[1,1,1,0],
[1,0,1,1]
]
var goalx = 0;
var goaly = 3;
console.log();
function findpath(x,y) {
// illegal move check
if (x < 0 || x > (map[0].length -1) || y < 0 || y > (map.length - 1)) return false; //if it is outside of map
if (map[y][x]==0) return false; //it is not open
// end move check
if (x== goalx && y== goaly){
console.log('Reached goal at: ' + x + ':' + y);
return true; // if it is the goal (exit point)
}
if(map[y][x] == 9 || map[y][x] == 8)
return false;
console.log('Im here at: ' + x + ':' + y);
map[y][x]=9; //here marking x,y position as part of solution path outlined by "9"
if(findpath(x+1,y))
return true;
if(findpath(x,y+1))
return true;
if(findpath(x,y-1))
return true;
if(findpath(x-1,y))
return true;
map[y][x]=8; //unmark x,y as part of solution path outlined by "8"
return false;
};
findpath(3, 3);
</script>
</body>
</html>

Prevent touching corners (JS Game)

How can I prevent this map generator from creating touching corners like this:
-X
X-
Or
X-
-X
Here is a simplified example of the generator: http://jsfiddle.net/fDv9C/2/
Your question answers itself, almost.
Here's the fiddle: http://jsfiddle.net/qBJVY/
if (!!grid[y][x] && !!grid[y+1][x+1] && !grid[y+1][x] && !grid[y][x+1]) {
good=false;
grid[y+1][x]=2;
}
It simply checks for the combinations you do not want and patches them up. It always adds a grid point so as not to disconnect any parts of the map.
This in turn may lead to another situation where the issue may occur, but if it changed anything (that is, if it found a problem), it will simply check again. This can be optimized, for instance by recursively adjusting whatever was changed, but usually it only needs 1 or 2 passes. There's a limiter on there to not allow more than 100 passes, just in case there is some unforeseen circumstance in which it cannot fix it (I can't think of such a situation, though :) ).
Because of the way that you are creating board it's very difficulty to do this checking during generation. I create simple function that check board after. It's using flood algorithm. Here is the fiddle http://jsfiddle.net/jzTEX/8/ (blue background is original map, red background is map after checking)
Basically we create second array grid2. After filling grid we run recursively floodV function
function floodV(x,y) {
var shiftArray = [[0,1],[0,-1],[1,0],[-1,0]];
grid2[y][x]=1;
for(var k=0;k<4;k++) {
var x1=x+shiftArray[k][0];
var y1=y+shiftArray[k][1];
if(grid[y1][x1] == 1 && grid2[y1][x1] == 0 && checkV(x1,y1)) {
grid2[y1][x1] = 1;
floodV(x1,y1);
}
}
}
with the check function
function checkV(x,y) {
var checkVarr = [[-1,-1], [-1,1], [1,1], [1,-1]];
for(var k=0;k<4;k++) {
if(grid[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1 && grid[y+checkVarr[k][0]][x] == 0 && grid[y][x+checkVarr[k][1]] == 0 && grid2[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1)
return false;
}
return true;
}
This isn't perfect because we can sometimes throw away big parts of the map but if we try to start adding new elements we have to check whole map again (in worths case).
This is what I did: http://jsfiddle.net/fDv9C/13/
Where's the magic happening? Scroll down to lines 53 through 58:
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) continue;
In short your touching corner points can only occur at the computed next position. Hence if any one of the four corner neighbors of the next position exists, you must compute another next position.
You may even decrement the counter i when this happens to get as many paths as possible (although it doesn't really make a big difference):
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) {
i--;
continue;
}
See the demo here: http://jsfiddle.net/fDv9C/12/
Edit: I couldn't resist. I had to create an automatic map generator so that I needn't keep clicking run: http://jsfiddle.net/fDv9C/14/

javascript (nodejs) while loop bug

running the following code in nodejs cli:
var my_function = function() {
var next_value = 1
, value = undefined
, difference = undefined
, prev_difference = undefined
while ((typeof prev_difference === 'undefined') || (prev_difference > 0)) {
value = next_value
next_value = 2
difference = next_value - value
if (difference > prev_difference) {
throw new Error('Diminishing')
}
prev_difference = 0
}
return next_value
}
for (var i = 0; i< 300; i++) { console.log(i); console.log(my_function()) }
At iteration 282 of the loop I start getting the value '1' instead of '2'. Can't for the life of me understand why. This chunk of code is a reduction from something else I've been working on, hence the seemingly unnecessary if statement within the loop. There are a few ways to change this code such that the execution path does not get screwed up, but I'd like to understand why it's breaking with the current setup.
Also, if you have any tips for tools that could aid me in debugging something like this in the future I would be very grateful. For the most part I used console.log to narrow this down.
node.js version v0.8.6. Running on Mac OSX version 10.7.5.
Thanks
If you take out the IF statement it is gonna be fine, it will return only '2' on every iteration. The variable prev_difference is 'undefined' every time and this seems to cause issues.

Categories