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

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

Related

Refactoring JavaScript function results

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;

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");
}

simple comparison script doesnt seem to work

I keep getting a syntax error caused by the final else statement at the end of the script. This seems to stop anymore JS running on the page, but I can't figure out why it's causing an error. More than likely, it's a really simple syntax thing that I just can't see, because I've been looking at it too long. If anyone could help that would be great. I've declared the variables in the code, but in the actual program these are based on other conditions and will be integers.
var nbdJDay = 70;
var mmWindow = 1;
var dayCompare = nbdJDay;
if (dayCompare < 85 && dayCompare > 14) {
mmWindow = 2;
} else if (dayCompare < 15 && dayCompare > -15) {
mmWindow = 3;
} else {
mmWindow = 0;
}

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/

Handling events with new data before previous event has completed

This code takes two inputs: div, the div (actually a textbox) and target (a number). It'll then try and in/decrement the number in a pseudo-animated way. The problem is that I'm using jQuery sliders as one form of input, which can result in multiple calls before the first call finished. This isn't a problem unless the slider is quickly increased, and then decreased before the increase rollUp finishes, resulting in an eternal decrementing div. I can't figure out what's causing it. Thoughts?
function rollNum(div, target) {
var contentString = $(div).val();
content = parseInt(contentString.substring(1));
if(content === target)
return;
else if(div !== "#costMinusMSP" && div !== "#savingsWithMSP") {
var total = rollNumTotalCost(div, target);
rollNum("#costMinusMSP", total);
rollNum("#savingsWithMSP", total /*- somehow find the cost here*/)
}
if(isNaN(content))
content = 0;
var remainingChange = target - content;
if(remainingChange > 0)
loopUp();
else
loopDown();
function loopUp() {
var length = remainingChange.toString().length;
var incrementBy = 1;
//Find how far away we are from target
for(var i=0;i<length-1;i++)
incrementBy *= 10;
content += incrementBy;
remainingChange -= incrementBy;
$(div).val("$" + (content))
if(content === target)
return;
else if(content > target) {
$(div).val("$" + (target));
return;
}
setTimeout(loopUp, 60);
}
function loopDown() {
remainingChange = Math.abs(remainingChange);
var length = remainingChange.toString().length;
var decrementBy = 1;
//Find how far away we are from target
for(var i=0;i<length-1;i++)
decrementBy *= 10;
content -= decrementBy;
remainingChange -= decrementBy;
if(content < target) {
$(div).val("$" + (target));
return;
}
//This ensures we won't promise our clients negative values.
if(content <= 0) {
$(div).val("$0");
return;
}
$(div).val("$" + (content))
if(content === target)
return;
setTimeout(loopDown, 60);
}
}
Strangely enough, adjusting another slider (that modifies an unrelated div) fixes the eternal decrement.
Things I have tried:
-Creating a boolean "running" that the function sets to true, then false before it returns. If running was true, then the function would wait until it was false to continue executing. This killed the browser or achieved maximum stack.
SomeKittens of years ago: You've learned a lot since you asked this, particularly about managing state & multiple events (not to mention how to properly ask a StackOverflow question). A simple answer would be something like this:
var rolling = false;
function rollNum(div, target) {
if (rolling) { return; }
rolling = true;
// Set rolling to false when done
}
That's all well and good but it ignores any events that are fired while we're rolling. The above won't adjust to changes on the slider made after the first adjustment, but before the numbers have finished rolling. Now, I (we?) would use Angular ($scope.$watch would come in handy here) but that didn't exist when you were working on this. Instead of passing a target number, why don't we check against the live value on the slider? (Note the use of vanilla JS, it's much faster).
var rollNum = function(textarea) {
var content = parseInt(textarea.value.substring(1), 10)
, target = parseInt(document.getElementById('sliderId').value, 10);
if (content === target) {
return;
}
// Roll up/down logic
setTimeout(function() { rollNum(textarea); }, 60);
};
A few other misc changes:
Use brackets after if statements. Waaaay easier to debug
Don't forget the radix param in parseInt
Unfortunately, you didn't think to include a JSFiddle, so I can't provide a live demonstration.

Categories