JS concatenating object property values (numeric) instead of adding - javascript

In an intersect function, that checks if two objects intersect on the canvas, I need to add the obj.x and obj.width property to get the obj.right(side). Somehow the properties are concatenated instead of added. It probably has something to do with reference-type but I don't see how I can capture the values in primitive types.
function intersects(obj1, obj2) { // checks if 2 shapes intersect
var ob2x = obj2.x;
var ob2width = obj2.width;
if (obj1.x > +obj2.x + 70 || obj2.x > +obj1.x + 70) {
console.log('false : obj1.x=' + obj1.x + ' obj2.right=' + parseInt(ob2x) + parseInt(ob2width));
return false;
}
if (obj1.y > +obj2.y + +obj2.height || obj2.y > +obj1.y + +obj1.height) {
console.log('false');
return false;
}
console.log('false');
return true;
}
I have already tried to get the number value of the object property, as you can see. Didn't work
Also tried parseInt(), which didn't work.
I suppose I can put the values seperately as parameters in the fuctions but I was hoping to keep it as short as possible, because kids need to use it.

You need to add a grouping operator:
... + (parseInt(ob2x) + parseInt(ob2width)) + ...
to isolate that part of the expression so that + is seen as addition. Otherwise, the full expression keeps it as concatenation, even though you convert those to values to numbers (because if a string is anywhere in the expression being evaluated, + means concat).
E.g.
var x = 5;
var y = 6;
console.log('Sum: ' + x + y); // 56
console.log('Sum: ' + (x + y)); // 11

Related

adding values that could contain a null/undefined value

I'm sorry to ask, but I just can't find the info.
My script needs to add 12 items together but some of them may have null/undefined values
ie
1 + null + 3 + 4 + null + null + 7
How do I add these together?
$scope.wepweight = ($scope.selectedWeapon1Ship1.Vars.weight) +($scope.selectedWeapon2Ship1.Vars.weight)
At the moment, the values will add together once all the ng-models are populated (because of the null/undefined values), but I need to keep a running total.
https://jsfiddle.net/wayneker/3u6ob98d/2/
(search for "//calculate weight for hull" within the JS section to see the relevant section of code)
You could take the Nullish coalescing operator ?? which checks if the value is null or undefined, then it takes the right hand side value.
const sum = 1 + (null ?? 0) + 2 + (undefined ?? 0);
console.log(sum);
You can use the || operator to check if the value is null or undefined, and if it is, add 0 to it:
console.log(1 + (null || 0) + 3 + 4 + (undefined || 0) + 7) // 15
You didn't specify where you got your values from, but either they are stored in an array or you can put them in an array.
Once you have them in an array, it's elegant with reduce:
// assuming weight is your array
weight.reduce((a,b) => typeof b === 'number' ? a + b : a, 0);
What this code does is that it starts with 0 and adds every element that is a number (which null is not)
i think this one can help you
$scope.wepweight = calcSumValue();
function calcSumValue() {
let ans = 0;
for(let i = 1; i <= 12; i++) {
const value = $scope[`selectedWeapon${i}Ship1`].Vars.weight
if (value)
ans += value;
}
return ans;
}

Highcharts/HighcharteR Tooltip: access all y-values within a series, print the difference

[EDIT] I ended up solving it as I was writing this question, so see below for the answer.
I have a graph that has time periods on the x-axis, and scores on the y-axis, and at each point I'd like the tooltip to give the difference in y values between the current point and the previous one (within the same series).
Reproducible example:
library(highcharter)
hchart(df,
type="line",
hcaes(x = period, y = value, group = group)
) %>%
hc_tooltip(pointFormat = "Score: {point.y} ({previous.point.y})")
Ideally, on hovering for example over the second point for series B, I'd like it to say Score: 5 (+1). This will probably require some formatter=JS() JavaScript instead of just pointFormat, but not sure how to do that.
Courtesy of this related answer, I managed to access all y values, after which I figured out that using this.point.x allows us to hone in on specific y values. Here's the JS:
function () {
if (this.point.x == 0) { // there's no previous point, so set to '0'
var thisDiff = 0;
} else { // use 'this.point.x' to get current position, and do '-1' to get previous position
var thisDiff = ( this.series.points[this.point.x].y - this.series.points[this.point.x - 1].y );
if (thisDiff > 0) {
thisDiff = '+' + thisDiff; // pretty print a '+' sign if difference is positive
}
}
var s = '<b>Series ' + this.series.name + ', period ' + this.point.name + ': </b>';
s += 'mean score ' + this.point.y + ' (' + thisDiff + ')';
return(s);
}
To get it to work in highcharteR we just need to wrap this in quotation marks and pass to hc_tooltip(formatter = JS()

Typescript : Trying the addition of two variables but get the concatenation of the two

I have three variable in my Typescript class :
A:number;
B:number;
C:number;
in another part of the class i try to make the addition of the two variable A and B :
this.C = this.A+this.B; // A =20 and B = 50;
and I display C in the html template
<span>{{C}}</span>
My problem is, instead of getting the addition of the TWO variable (20+50=70) i get the concatenation (2050)!!
Can someone help me please ?
UPDATE :
Here is the exact code portion that cause problem :
goTo(page:number,type:script) {
//
this.pageFirstLineNumber = page;
this.pageLastLineNumber = page + this.LINE_OFFSET; //concatenation!!
}
Notice that pageLastNumber is declared as number type, LINE_OFFSET is olso number type, i have found a solution to this issue but the typescript compiler output an error (forbidden eval):
////
....
this.pageFirstLineNumber = eval(page.toString()); // now It works !!
this.pageLastLineNumber = page + this.LINE_OFFSET; //concatenation!!
UPDATE
Here is the declaration of the LINE_OFFSET variable :
private _calculateOffset(fontSize: number) {
let linesDiff = (fontSize * 27) / 14;
let lines:number = 27 - (linesDiff - 27);
this.LINE_OFFSET = Math.floor(lines);
if (fontSize >= 17 && fontSize <= 20) {
this.LINE_OFFSET += (Math.floor(fontSize / 3) - 2);
}
if (fontSize > 20 && fontSize <= 23) {
this.LINE_OFFSET += (Math.floor(fontSize / 2) - 2);
}
if (fontSize > 23 && fontSize <= 25) {
this.LINE_OFFSET += (Math.floor(fontSize / 2));}
if (fontSize > 25 && fontSize <= 27) {
this.LINE_OFFSET += (Math.floor(fontSize / 2) + 1);
}
if (fontSize > 27 && fontSize <= 30) {
this.LINE_OFFSET += (Math.floor(fontSize / 2) + 4);
}
}
prepend the numbers with +:
let a = +b + +c;
ref
When you declare in an interface that a property is a number then it stays as a declaration only, it won't be translated into javascript.
For example:
interface Response {
a: number;
b: number;
}
let jsonString = '{"a":"1","b":"2"}';
let response1 = JSON.parse(jsonString) as Response;
console.log(typeof response1.a); // string
console.log(typeof response1.b); // string
console.log(response1.a + response1.b); // 12
As you can see, the json has the a and b as strings and not as numbers and declaring them as numbers in the interface has no effect on the runtime result.
If what you get from your server is encoded as strings instead of numbers then you'll need to convert them, for example:
let response2 = {
a: Number(response1.a),
b: Number(response1.b)
} as Response;
console.log(typeof response2.a); // number
console.log(typeof response2.b); // number
console.log(response2.a + response2.b); // 3
(entire code in playground)
Problem is variable typecasting not done.
You need to do in following way.
A : parseInt(number);
B : parseInt(number);
then you will get sum C= A+b instead of concatenation.
I ran into similar problem , was able to solve as below :
C:number =0;
A:number=12;
B:number=0.4;
C= Number.parseInt(A.toString()) + Number.parseFloat(B.toString());
console.log("C=" + C );
seems stupid , to convert a number to string and parse again to number , but this is how I solved my problem.
Finnaly i find what cause the error, i get the page variable from the html template (its an input value), it is defined as number type in the function parameter, but in reality is a string and typescript cant check the type of variable from html template, so when a try parseInt(page) static typping highlight an error ! i have soved the issue by giving the page variable an "" type, then applying parseInt to the page variable.
That means there are string values in either A or B variables. Check your code for unsafe parts, I mean casting to <any>, and casting server responses to interfaces. That could cause to have string values in number variables.
const value = Number(stringOrNum)+1;

How to prevent a new object of robots from going to the same location as previous robots?

Things you need to know about my Program
I have created a program in JavaScript that executes Robot instruction that you give. per Robot Object.
The robot is inside a rectangle shaped area. It moves with (x,y) points. Such that (0 <= x <= 50) and (0 <= y <= 50)
The instructions are in Strings of continuous of three repeated letters - There are Three letter that represent the movement of the robot
The program runs each letter and moves the robot according to the letter.
If the program finds out the the robot is out of the surface. Then the robot is lost and the coordinates of that particular robot is kept in array of lists called Lost_Robot
My Question:
I don't know how to prevent a new robot from going to the same coordinates that a previous robot got lost (because of out of Rectangle surface).
How can I achieve from preventing another new robot (when I say new Robot, I mean new Robot Object) from jumping to the same location that a previous robot went and got lost.
I have an array of (x,y) of robots that got lost. But how can I use this array from letting a new robot going to this point?
I tried to use for loop that runs the array to see the coordinates, but doesn't do anything.
Also
While your working on my problem, can you also give me few hints on how can I simplify my code yet doing the same functionality, but more efficiently.
=
var orientation = ["N", "E", "S", "W"];
var instruction = ["L", "R", "F"];
var lost_Robot_Scent = [];
// function created for assigning coordinates and an orientation
function Robot_Coordinatation(x, y, orientation) {
// coordinate (x,y) must be located at (0,0) at the initial state of the program
this.x = 0;
this.y = 0;
// orientation assigned
this.orientation = orientation;
// this is printed for the purpose of tidiness
document.write("============================" + "<br />");
// | ( x,y) | e.g(S)
document.write("| ( " + x + ", " + y + " ) | " + orientation + "<br />");
// We have a nested function here that will determine the movement/instruction of the robot
this.Robot_Instruction = function(instruct_The_Robot) {
// We are making sure here that the length of the instruction is less than 100
if (instruct_The_Robot.length <= 100) {
// if...statement - if x & y is bigger than or equal to 0 and smaller than or equal to 50 -> If its true then go inside the if statment.
// Essentiallly, what this statement is actually doing is that its creating the rectangular grid.
if ((x <= 50 && x >= 0) && (y <= 50 && y >= 0)) {
// itterate the array of the instruct_The_Robot
for (var i = 0; i < instruct_The_Robot.length; i++) {
// if any value of instruct_The_Robot is strictly equal to "L", then go inside this if statement. refer to line: 10
if (instruct_The_Robot[i] === instruction[0]) {
// variable Left declared and instantiated with -90°
var Left = -90 + "&#176";
// variable result instantiated with value (x,y) & orientation
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Left + "<br />";
// however, if the if...statment at line: 33 is not true, then follow this : if the value of instruct_The_Robot is equal to "R"...
} else if (instruct_The_Robot[i] === instruction[1]) {
// variable Right instantiated with 90°
var Right = 90 + "&#176";
// variable result instantiated
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Right + "<br />";
// however, if the if...statment at line: 33 & elseif at line: 39 is not true, then if instruct_The_Robot is equal to "F"...
} else if (instruct_The_Robot[i] === instruction[2]) {
// variable y_Plus_One is instantiated with the current value of y and moves y one point forward
var y_Plus_One = y += 1;
// if the negation of x & y_Plus_One is smaller than 50 and bigger the 0, then...
if (!((x <= 50 && x >= 0) && (y_Plus_One <= 50 && y_Plus_One >= 0))) {
// then print " lost! "
document.write("LOST!" + "<br />");
// & keep the record of the x and y_Plus_One value to the lost_Robot_Scent array
lost_Robot_Scent.push([x, y]);
// and return false - this stops printing "Lost!" more than one times
return false;
// Otherwise, if the above doesn't satisfy, then...
} else {
// variable result instantiated with the updated coordinates (y_Plus_One)
var result = " | ( " + x + ", " + y_Plus_One + " ) " + " | " + orientation + " " + "<br />";
}
}
}
//print the result
document.write(result);
// if none of the if...statement above satisfy, then...
} else {
// variale lost instantiated with "Lost!" message
var lost = "LOST!" + "<br />";
// push the robot to the lost_Robot_Scent
lost_Robot_Scent.push("| ( " + x + ", " + y + " ) " + "<br />");
}
} else {
alert("There is alot of of instructions given. Please make sure that the instruction is less than 100 instructions");
}
}
}
// new Robot object initialised
var one = new Robot_Coordinatation(50, 50, orientation[1]);
one.Robot_Instruction("LRLRLRLRLRLLRRLRLRLLRLLRRLL");
var two = new Robot_Coordinatation(20, 30, orientation[3]);
two.Robot_Instruction("FFFLLFLRLFLRFLRLLLFRL");
var two = new Robot_Coordinatation(30, 7, orientation[3]);
two.Robot_Instruction("FFFFLRLFLRFLRL");
Maintaining lost_Robot_Scent
I can help you with keeping a collection of locations where your robots get lost (your lost_Robot_Scent array). I suggest using a Set instead on an Array. Sets provide O(1) insertion and O(1) lookup. This probably isn't a big deal in this situation, but it's good to know about Set anyway.
The main problem you'll run into is that array equality is pointer equality: for example, [1, 1] === [1, 1] returns false. One workaround is using toString() on the arrays and storing that in the Set. For example:
var lost_Robot_Scent = new Set();
lost_Robot_Scent.add( [1, 1].toString() );
lost_Robot_Scent.has( [1, 1].toString() ); // -> true
lost_Robot_Scent.has( [2, 2].toString() ); // -> false
I don't know if this is the cleanest solution, but it works. If you want to use an Array instead of a Set, just use push instead of add and includes (or indexOf) instead of has, e.g.
var lost_Robot_Scent = [];
lost_Robot_Scent.push( [1, 1].toString() );
lost_Robot_Scent.includes( [1, 1].toString() ); // -> true
lost_Robot_Scent.includes( [2, 2].toString() ); // -> false
If you are worried about performance, you can test these two methods against each other in specific contexts.
Improve The Code
One thing you can do to simplify your code is to lessen the nested if statements. For example, the first if in your Robot_Instruction function could be
if (instruct_The_Robot.length > 100) {
alert("Too many instructions! Please limit to 100."
return;
}
// continue...
Perhaps this is a bit off-topic, but you should only use comments for things are aren't obvious. For example, variable Left declared and instantiated with -90° is unnecessary.
One last thing: you can simplify the "instructions" loop using a switch statement instead of if/else blocks. Or, if you want to make is super-readable, you can use a JavaScript object like so:
var move = {
L: function() {
// turn left
},
R: function() {
// turn right
},
F: function() {
// move forward
},
};
// then, in the "instructions" loop, you can just do
for (var i = 0; i < instruct_The_Robot.length; i++) {
move[ instruct_The_Robot[i] ]();
}
That's a pretty neat trick.
How to prevent a new robots from getting lost in the same places as old robots
Assuming you've fixed your bugs, and robots are moving. When you determine that a robot is moving forward, you have to determine if the new coordinates are already in the lost_Robot_Scent array. You can do this using something like the following:
var robotLostAtSameLocation = false;
for (var i = 0; i < lost_Robot_Scent.length; i++) {
var lostRobotLocation = lost_Robot_Scent[i];
if(lostRobotLocation[0] === x && lostRobotLocation[1] === y) {
robotLostAtSameLocation = true;
break;
}
}
if (robotLostAtSameLocation) {
// whatever you want to do in this case
}
else {
// whatever you want to do in this case
}
Simple optimization
Note that you can get rid of this loop if you change the lost_Robot_Scent array from containing [x,y] to containing something like 'x:y'. So rather than an array that contains other arrays looking like this: [[39,51], [51,15], [-1,11]], it will be an array containing strings looking like: ['39:51', '51:15', '-1:11']. What this buys you is that you can then just say var robotLostAtSameLocation = lost_Robot_Scent.indexOf(x + ':" + y) > -1;
Recommendation
Change var instruction = ["L", "R", "F"]; into something more like var INSTRUCTIONS = {LEFT: 'L', RIGHT: 'R', FORWARD: 'F'};. This turns lines like instruct_The_Robot[i] === instruction[0] into instruct_The_Robot[i] === INSTRUCTIONS.LEFT, improving readability.
Bugs
You are never updating x, y, or orientation. Your robots are never moving. You are only outputting a string.
You are only checking if the y-coordinate is out of bounds. You are forgetting to check if the x-coordinate is out of bounds.
You are pushing [x,y] into the lost_Robot_Scent array on one line, then pushing "| ( " + x + ", " + y + " ) " + "<br />" into the same array on another line. Don't do that. It's hard to reason about a program when it is not consistent.
There may be other issues - I can't take the time to fully digest it at the moment.

Result of a while loop still happens even when the condition isn't met

I'm practising writing Javascript by making a Roguelike dungeon game but there is a problem when I want to create monsters. I have written a while loop such as:
this.getRandomCoordinatesInRoom = function(roomNumber) {
var validLocationFound = false;
while (!validLocationFound){
// Generate co-ords in room first
x = Math.floor(Math.random() * (this.roomList[roomNumber].width) + (this.roomList[roomNumber].posX));
y = Math.floor(Math.random() * (this.roomList[roomNumber].height) + (this.roomList[roomNumber].posY));
// Find location of (x,y) in Dungeon Array
//alert(arrayLocation);
var tmpX = ((this.roomList[roomNumber]).posX + x);
var tmpY = ((this.roomList[roomNumber]).posY + y);
var arrayLocation = ((tmpY * 80) + tmpX);
//var arrayLocation = ((this.roomList[roomNumber].posX + x) + (80 * (this.roomList[roomNumber].posY + y)));
if (this.dungeonArray[(tmpY + tmpX)] === "floor") {
validLocationFound = true;
};
if ((x<this.roomList[roomNumber].posX) || (x>(this.roomList[roomNumber].posX + this.roomList[roomNumber].width))){
alert("x out of bounds");
};
if ((y<this.roomList[roomNumber].posY) || (y>(this.roomList[roomNumber].posY + this.roomList[roomNumber].height))){
alert("y out of bounds");
};
writeToScreen("Room upper left corner = " + (this.roomList[roomNumber].posX).toString() + "," + (this.roomList[roomNumber].posY).toString(),10);
return [x,y];
if (!(getTileAt(arrayLocation) === "floor")){
alert("It messed up");
}
};
The code randomly generates an x,y coordinate and converts it to a single number (My dungeon array is one dimensional, 0-79 across and then 80 is a new row). however, even when the code generates a coordinate that isn't valid (!= "floor"), it still finishes the function as though it returned true. Why is this?
Your function returns [x,y] from inside the while loop. Declare the variables outside of the loop and then return the value from outside the loop. Or else, return is when validLocationFound is true.
var x, y ;
while(...) {
...
}
return [x, y];

Categories

Resources