Parse course in textual way from course in degrees? - javascript

So im making a compass in node-red, it should have course in degrees (int) as input and string(course) as output:
So i need function that takes in integer and gives me heading in string. How to do it simple and reliable?
I have to convert course 0-360 degrees in string for example: NORTH, NORTH-EAST, EAST......
I tried the following:
var course = parseInt(courseFloatDegrees);
var courseTxt = "";
if (course >= 349 && course <= 11 || course <= 359 && course >= 349 || course === 0) courseTxt = "N";
else if (course >= 11 && course <= 33) courseTxt = "NNE";
else if (course >= 33 && course <= 56) courseTxt = "NE";
else if (course >= 56 && course <= 78) courseTxt = "ENE";
else if (course >= 78 && course <= 101 || course == 90) courseTxt = "E";
else if (course >= 101 && course <= 124) courseTxt = "ESE";
else if (course >= 124 && course <= 146) courseTxt = "SE";
else if (course >= 146 && course <= 168) courseTxt = "SSE";
else if (course >= 168 && course <= 191 || course == 180) courseTxt = "S";
else if (course >= 191 && course <= 214) courseTxt = "SSW";
else if (course >= 214 && course <= 236) courseTxt = "SW";
else if (course >= 236 && course <= 258) courseTxt = "WSW";
else if (course >= 258 && course <= 281 || course == 270) courseTxt = "W";
else if (course >= 281 && course <= 303) courseTxt = "WNW";
else if (course >= 303 && course <= 326) courseTxt = "NW";
else if (course >= 326 && course <= 349) courseTxt = "NNW";
else courseTxt = "INVALID"
But sometimes i get nothing(null-empty string) or "INVALID". Does anybody know fast and simple way to do this without that much else if statements?

There could be ways of doing this more 'simply' in code, but your approach should work. The reason it doesn't is because your if statements are messed up around the 'N' region.
if ((course >= 349 && course <= 11) || (course <= 359 && course >= 349) || (course === 0)) courseTxt = "N";
If you look at the very first two conditions, they are illogical. More than 349 but less than 11? That's never going to happen. If you have a course of 7 degrees, that doesn't meet any of the specified criteria currently.
So the first thing to do is resolve that problem. You need to adjust the line to use OR instead of AND
if(course < 11 || course > 349) courseTxt = "N";
Now your code will be able to handle the settings either side of 360/0 degrees.
That should be enough to get your current code to work, assuming course is always less or equal to 360.
You asked if there is a way to avoid all the if statements. There are probably hundreds of ways to do this, but the simplest, other than if or case statements would probably be to use an array to look up the heading. Here is an example of how it could be done. You could obviously hardcode the step value, but this way you could update your array with any number of more granular headings, and it will still work.e
function getCourse(course)
{
// define our values
var degs = 360;
var strs =
["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"];
// make sure course is always within the expected range in case it is incremented past 360
course = course % degs;
// get the step amount based on the number of compass headings we have
var step = degs/strs.length;
// adjust for the last few degrees on the scale which will be north
if(course > degs - (step/2)) course += step/2;
// now just divide the course by the step and read off the relevant heading
var index = Math.floor(course / step);
return strs[index];
}

Nicky,
I used an approach similar to Toby's -- calculating an index into an array of course strings:
var deg = course % 360;
var dirs = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"];
var idx = Math.round(deg * (dirs.length-1)/360);
var dir = dirs[idx];
The trick is to repeat the "N" element at the beginning and end of the array, and use Math.round(...) to jump to the closest integer index number.

Related

Recursively setting a value depending on range using JavaScript

I don't know how to word this but this is what I'm trying to do:
if (score >= 0 && score <= 10) overallScore = 0;
else if (score >= 11 && score <= 20) overallScore = 1;
else if (score >= 21 && score <= 30) overallScore = 2;
else if (score >= 31 && score <= 40) overallScore = 3;
else if (score >= 91 && score <= 100) overallScore = 9;
...
Is there any way to recursively do this using a function?
overallScore = Math.max(0, Math.floor((score - 1) / 10));
no need for recursion. But if you need that:
const getOverall = score => score <= 10 ? 0 : getOverall(score - 10) + 1;
Recursion is not really appropriate here, since you can get the required value in constant time. Recursion becomes interesting when you need at least O(logn) time.
But as you ask for it, here is one way to make it recursive:
function range(score, depth = 0) {
return score <= 10 || depth >= 9 ? 0 : range(score-10, depth+1) + 1;
}
console.log(range(0)); // 0
console.log(range(10)); // 0
console.log(range(11)); // 1
console.log(range(60)); // 5
console.log(range(91)); // 9
console.log(range(110)); // 9

How NOT to break a function/loop on returning a value (Js)

Hey so I am making a 2D tile game, or really I am just messing around. I have made the map from an array, where 0 represents nothing, and other characters represents a walkable tile.
var map=[["t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t"],
["l","1","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","r"],
["l","r","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","r"],
["l","1","t","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","l","r"],
["l","1","1","t","t","t","t","t","t","t","t","t","t","t","t","r","0","0","l","r"],
["l","b","b","b","b","b","b","b","b","1","1","b","b","b","b","b","t","t","b","r"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","l","1","1","r","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","l","1","1","1","1","r","0","0","0","0","0","0","0"],
["t","t","t","t","t","t","t","1","1","1","1","1","1","t","t","t","t","t","t","t"]];
On screen it looks like this
You see my moveable character here as well.
Now I have come this far, and I'd like my character to collide with the empty tiles represented as the value of 0 in my map array.
This is my code for checking collision (brackets are correct in the script):
function collisioncheck(ind){
for(var i in map){
for(var j in map[i]){
if(yass==true){
if(map[i][j]==0){
if(ind==0 && playerPosX==j*32+32 && playerPosY>i*32-32 && playerPosY<i*32+32){
return false;
}else if(ind==1 && playerPosX==j*32-32 && playerPosY>i*32-32 && playerPosY<i*32+32){
return false;
}else if(ind==2 && playerPosY==i*32+32 && playerPosX>j*32-32 && playerPosX<j*32+32){
return false;
}else if(ind==3 && playerPosY==i*32-32 && playerPosX>j*32-32 && playerPosX<j*32+32){
return false;
}else{
return true;
}
}
}else{
return true;
}
}
}
var yass=false;
function exist(){
for(var i in map){
for( var j in map[i]){
if(map[i][j]==0){
yass=true;
break;
}
}
}
So, this works. But only for the first 0 in the map. My problem is that the return statements breaks the for-loop and function. So my character will not collide with any other blank tile but the first one.
I will have to rewrite this, but is there any smart solution to this?
Link to jsfiddle here (Character not visible)
You're on the right track, your loop only runs for one iteration because you always return something after an iteration. However, you should only call return when you know the final result, because - as you said - it will exit the function.
It is correct to call 'return false' right away after a collision is detected, because if the player collides with at least one block, then there is a collision. On the opposite, 'return true' should only be called when you are sure that there are no collisions at all on the entire board, and you need to test every block on the map before you can confirm this.
function collisioncheck(ind) {
for (var i in map) {
for (var j in map[i]) {
if (yass == true) {
if (map[i][j] == 0) {
if (ind == 0 && playerPosX == j * 32 + 32 && playerPosY > i * 32 - 32 && playerPosY < i * 32 + 32) {
return false;
} else if (ind == 1 && playerPosX == j * 32 - 32 && playerPosY > i * 32 - 32 && playerPosY < i * 32 + 32) {
return false;
} else if (ind == 2 && playerPosY == i * 32 + 32 && playerPosX > j * 32 - 32 && playerPosX < j * 32 + 32) {
return false;
} else if (ind == 3 && playerPosY == i * 32 - 32 && playerPosX > j * 32 - 32 && playerPosX < j * 32 + 32) {
return false;
}
// else: do nothing. (i.e. let the loop run for the next block)
}
} else {
return true;
}
}
}
return true;
}
What we do here is go through all the blocks, if we find a collision we return false and exit the function. We only reach the 'return true' statement if we went through all the blocks without finding any collision, which is exactly what you want.
You need to use continue instead of return in the last else of your main if/else block on line 15

JavaScript: What is the opposite of the logical operator `A && B`?

In the following code, what is the opposite of the condition (ran1 <= 63 && ran2 <= 18), which should fit in the else portion of the if statement?
Is it both (ran1 <= 63 || ran2 <= 18) and (! (ran1 <= 63 && ran2 <= 18))?
Logically, I suppose that the opposite of A and B is both A or B and neither A nor B. But I'm not sure how to express the neither A nor B bit in JavaScript.
var ran1 = 1 + Math.floor(Math.random() * 100);
var ran2 = 1 + Math.floor(Math.random() * 100);
if (ran1 <= 63 && ran2 <= 18) {
// code
} else {
// code
}
The mathematical negation of A && B is !A || !B, so in your case, it would be
ran1 > 63 || ran2 > 18

Updating the random number within a variable?

How can a variable with a random number be updated. I'm using three.js. Here is my code. It works the first time it's called generating a sprite to a random location but then it just keeps going back to the same location. I thought that by calling the variables before they were used I would be updating them but it's not working.
var locX = Math.floor((Math.random()*450)+1);
locX *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
var locY = Math.floor((Math.random()*250)+1);
locY *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
var locZ = Math.floor((Math.random()*350)+1);
locZ *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
function spriteAI1() {
//console.log(c2Sprite.position.x);
//console.log(ranLocX);
//console.log(ranTen);
if (c2Sprite.position.x > 30 && c2Sprite.position.x <= 450) {
c2Sprite.translateX( -10 );
} else if (c2Sprite.position.x < -31 && c2Sprite.position.x >= -450) {
c2Sprite.translateX( 10 );
} else if (c2Sprite.position.z < 31 && c2Sprite.position.x < 31 && c2Sprite.position.z > -29 && c2Sprite.position.x > -29) {
locX;
locY;
locZ;
//c2Sprite.delete;
//scene.remove(c2Sprite);
//console.log("AI1");
c2Sprite.position.set( locX, locY, locZ );
//scene.add( c2Sprite );
//c2Sprite.clone;
}
}
If you want different values each call, declare the vars inside the function, not outside of it. As you currently have it, the vars are set once, and the function, however many times it's called, will reference those once-set values.

Error in JavaScript return code?

Here is the javascript code:
There is an error in code where nightSurcharges is added to total cost even if pickUptime is less than 20.
function TaxiFare() {
var baseFare = 2;
var costPerMile = 0.50;
var nightSurcharge = 0.50; // 8pm to 6am, every night //its flat 0.50 and not per mile
var milesTravelled = Number(document.getElementById("miles").value) || 0;
if ((milesTravelled < 1) || (milesTravelled > 200)) {
alert("You must enter 1 - 200 miles");
document.getElementById("miles").focus();
return false;
}
var pickupTime = Number(document.getElementById("putime").value) || 0;
if ((pickupTime == "") || (pickupTime < 0) || (pickupTime > 23)) {
alert("The time must be 0-23 hours");
document.getElementById("putime").focus();
return false;
}
var cost = baseFare + (costPerMile * milesTravelled);
// add the nightSurcharge to the cost if it is after
// 8pm or before 6am
if (pickupTime >= 20 || pickupTime < 6) {
cost += nightSurcharge;
}
alert("Your taxi fare is $" + cost.toFixed(2));
}
I want nightSurcharge to be added only when pickupTime is >=20, but that's not working right now.
Any help is appreciated. Thanks
This seems obvious to me.
if (pickupTime >= 20 || pickupTime < 6) {
cost += nightSurcharge;
}
This code right here adds nightSurcharge to the cost if pickupTime is greater than or equal to 20, OR less than 6. So of course it's added if it's less than 6.
if (pickupTime >= 20) {
cost += nightSurcharge;
}
Now it will only add to it if it's greater or equal to 20.
your code is:
if (pickupTime >= 20 || pickupTime < 6)
so if pickupTime is less then 6 it'll enter the if as well
http://jsfiddle.net/7rdzC/

Categories

Resources