While loop ignores initial condition and the browser crashes - javascript

So long story short - I'm trying to build a simple tennis match simulation (code below). Unfortunately, something is wrong with my code, because the while loop I created ignores the condition put in brackets and starts to make infinite number of itinerations (browser crashes). Could you please have a look at my code and tell me where the error lies?
var gamesPlayerOne = Math.floor(Math.random() * 8);
var gamesPlayerTwo = Math.floor(Math.random() * 8);
var tiebreak = Math.floor(Math.random() * 10);
var setsPlayerOne = 0;
var setsPlayerTwo = 0;
var scoreline = [];
function playTheGame(g1, g2) {
while (setsPlayerOne < 2 && setsPlayerTwo < 2) {
if (g1 === 6 && g2 < 5) {
var result = g1.toString() + ":" + g2.toString();
setsPlayerOne += 1;
scoreline.push(result);
} else if (g1 < 5 && g2 === 6) {
var result = g1.toString() + ":" + g2.toString();
setsPlayerTwo += 1;
scoreline.push(result);
} else if (g1 === 6 && g2 === 7) {
var result = g1.toString() + ":" + g2.toString() + "(" + tiebreak + ")";
setsPlayerTwo += 1;
scoreline.push(result);
} else if (g1 === 7 && g2 === 6) {
var result = g1.toString() + ":" + g2.toString() + "(" + tiebreak + ")";
setsPlayerTwo += 1;
scoreline.push(result);
}
}
}
playTheGame(gamesPlayerOne,gamesPlayerTwo);
console.log(scoreline);

If the random numbers that you pass into your function don't match any of the if or else if conditions then none of your variables is ever updated so the while loop's condition remains true forever.
If you are trying to simulate the entire tennis match, it would make more sense not to pass the function any arguments, and instead on each iteration of the while loop decide randomly which player just won the current game and then test if either player has won a set yet, perhaps something like this:
function playTheGame() {
var g1 = 0;
var g2 = 0;
var setsPlayerOne = 0;
var setsPlayerTwo = 0;
var scoreline = [];
while (setsPlayerOne < 2 && setsPlayerTwo < 2) {
// determine a random winner for the current game
if (Math.random() < 0.5)
g1++;
else
g2++;
// has one of the players just won a set?
if (g1 >= 6 && g2 < g1 - 1) {
var result = g1 + ":" + g2;
setsPlayerOne += 1;
scoreline.push(result);
g1 = g2 = 0;
} else if (g1 < g2 - 1 && g2 >= 6) {
var result = g1 + ":" + g2;
setsPlayerTwo += 1;
scoreline.push(result);
g1 = g2 = 0;
}
}
return scoreline;
}
console.log(playTheGame());
Note that you don't need to call .toString() on g1 and g2, because concatenating them with the string ":" implicitly converts the numbers to strings.
You could extend this to make one or the other player more likely to win (simulating different skill levels) by changing if (Math.random() < 0.5) to use a variable instead of hardcoding 0.5.
P.S. I couldn't be bothered to look up the rules for tennis to confirm how you win a set, but my vague recollection is that you have to get at least 6 games and be at least two games ahead of the other player, so that's what the code I've shown tries to implement...

For example... you didn't specify any condition to increase setsPlayer[One/Two] when g1 is equals to 0 and g2 is equals to 7.
So you should add some condition to check it.

Related

variable input becoming nullified and breaking .charAt[]

https://jsfiddle.net/2L4t9saq/180/ is my fiddle
most of the code is just useless, ill just post the stuff that matters
var baseConverter = function(r, e, n) {
var o = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (e <= 0 || e > o.length || n <= 0 || n > o.length) return console.log("Base unallowed"), null;
var l, t = 0;
if (10 != e) {
var a = r.length;
for (l = 0; l < a; l++) {
var u, f = -1;
for (u = 0; u < o.length; u++)
if (r[l] == o[u]) {
f = 1;
break
}
if (u >= e) return console.log("Symbol unallowed in baseform"), null;
if (-1 == f) return console.log("Symbol not found"), null;
var s = a - l - 1;
t += 0 == s ? u : u * Math.pow(e, s)
}
} else t = parseInt(r);
if (10 != n) {
for (var g = []; t > 0;) {
var i = t % n;
if (i < 0 || i >= o.length) return console.log("Out of bounds error"), null;
g.push(o[i]), t = parseInt(t / n)
}
return g.reverse().toString().replace(/,/g, "")
}
return t.toString()
}
var b36torgba = function(input) {
for (var i = 1; i < (input.length / 8) + 1; i++) {
var arr = input
var r = arr.charAt[0 + (i - 1) * 8] + "" + arr.charAt[1 + (i - 1) * 8]
var g = arr.charAt[2 + (i - 1) * 8] + "" + arr.charAt[3 + (i - 1) * 8]
console.log(g.charAt[2])
var b = arr.charAt[4 + (i - 1) * 8] + "" + arr.charAt[5 + (i - 1) * 8]
console.log(b)
var a = arr.charAt[6 + (i - 1) * 8] + "" + arr.charAt[7 + (i - 1) * 8]
console.log(a)
var rrgba = baseConverter(r, 36, 10)
var grgba = baseConverter(r, 36, 10)
var brgba = baseConverter(r, 36, 10)
var argba = baseConverter(r, 36, 10)
var bigMessOfAVariable = "rgba(" + rrgba + "," + grgba + "," + brgba + "," + argba + "),"
return bigMessOfAVariable;
}
}
you can ignore the top function, all it is is a base converter script, that takes in three inputs, an input, the base its in, and the base it should be converted to: eg baseConverter(73,36,10) will output 255.
now, the problem is with my b36torgba function.
it will take in a string, which is guaranteed to have a length that is either 0, 8, or a multiple of 8, this is just standardization to make sure everything runs smoothly, without having 700 indexOf[] functions.
it takes in the input, and divides it by 8, this tells the function how many bytes it has to go through, and how many it will spit out, so a string "[7300002S7300002S]" should (divided by 8) output 2, therefore the script runs 2 iterations.
currently, it should be taking in the string, and assigning each group of 2 characters (again standard) to a specific variable, this will allow it to all be put in the end and outputted as the same string but in base 10 rgba (hence 73 being use, 73 in base 36 is 255), but before it can do any of that, it breaks when it tries to find the characters in a string, saying this syntax error:
Uncaught TypeError: Cannot read property '0' of undefined
at b36torgba ((index):40)
at window.onload ((index):55)
why does it break as soon as it tries to feed the string into my charAt()'s?
ps: i do understand that the code in its current state, if it worked, it'd only output the rgba value of the last 8 characters
Easy mistake. You're using charAt (which is a function) by doing charAt[index] (using square brackets), rather than charAt(index) (using round brackets). Fixing that up should solve your issue.
Also - you're calling the function by doing b36torgba(["7300002S7300002S"]) in your JSFiddle, and trying to do string manipulation on it. Since ["7300002S7300002S"] is an array, not a string, .charAt() won't work on it. Try calling the function by doing b36torgba("7300002S7300002S") instead.

Take a 4 digit input and change order

I am trying to prompt user for a 4 digit number. Then, replace each
digit by (the sum of that digit plus 7) modulus 10. Then swap the first digit with the third, and swap the second digit with the fourth. Then output the encrypted digits.
So, if i enter in 1234 it should encrypt it to 0189 or enter in 5948 and it encrypt it to 1526
The problem is i get 9810 and 6251. So, its reading it backwards. I am close but its in the wrong order.
<script type="text/javascript">
var temp;
var number;
var first;
var second;
var third;
var fourth;
var fifth;
//prompt for first number
do {
inputNumber = window.prompt("Enter only a 4 digit number");
if ((isNaN(inputNumber) || !(inputNumber.length == 4)))
window.alert("please enter a number or length of 4");
} while ((isNaN(inputNumber)) || !(inputNumber.length == 4));
//temp = inputNumber;
temp = parseInt(inputNumber);
first = temp % 10; //process each number one by one
temp = temp / 10;
second = temp % 10;
temp = temp / 10;
third = temp % 10;
temp = temp / 10;
fourth = temp % 10;
swap = first;
first = third;
third = swap;
swap = second;
second = fourth;
fourth = swap;
first = parseInt(first);
second = parseInt(second);
third = parseInt(third);
fifth = parseInt(fifth);
fourth = parseInt(fourth);
first = (first + 7) % 10
second = (second + 7) % 10
third = (third + 7) % 10
fourth = (fourth + 7) % 10
var incrypted = first * 1000 + second * 100 + third * 10 + fourth * 1;
//var incrypted = first * 1000 + second + third * 10 + fourth * 1;
document.writeln("<h1>The number " + inputNumber + " is encrypted as " + incrypted + ".</h1><br />");
</script>
You may be better off handling your numbers individually.
var digits = inputNumber.split("");
digits[0] = (+digits[0]+7)%10;
digits[1] = (+digits[1]+7)%10;
digits[2] = (+digits[2]+7)%10;
digits[3] = (+digits[3]+7)%10;
digits.push(digits.shift());
digits.push(digits.shift());
// rotating by two results in 1234 becoming 3412, same result just more efficient!
var result = digits.join("");
try
var num = "1234"
var digits = num.split("");
var out = [];
for(var i=0; i<digits.length; i++){
digits[i] = (parseInt(digits[i])+7)%10;
}
var end = [digits[2],digits[3],digits[0],digits[1]].join("");
console.log(end.join(""));
A shuffle function:
function shuffle(val){
val = val + "";
function transform(num) { return (+num + 7) % 10 + ""; }
return transform(val[2]) +
transform(val[3]) +
transform(val[0]) +
transform(val[1]);
}
and with some validation:
function shuffle(val){
val = val + "";
if(isNaN(val)) throw "a valid number is required";
if(val.length != 4) throw "a four-digit number is required";
function transform(num) { return (+num + 7) % 10 + ""; }
return transform(val[2]) +
transform(val[3]) +
transform(val[0]) +
transform(val[1]);
}
This comes down to a fundamental misunderstanding of how the % operator works.
The MDN reference states this about the % operator:
The modulo function is the integer remainder of dividing var1 by var2.
For example, 12 % 5 returns 2.
Taking your example, with the input 1234, you are first finding the modulo 10 of 1234 in this code:
first = temp % 10;
The modulo of 1234 is 4 because 1230 is divisible by 10, leaving 4 as the remainder. Thus your logic reversus things. You could just change things at the beginning of your code to be reversed a bit:
fourth = temp % 10; //process each number one by one
temp = temp / 10;.
third = temp % 10;.
temp = temp / 10;
second = temp % 10;
temp = temp / 10;
first = temp % 10;
There is still a problem, when fixed as above you code will output 189 as the answer because you are combing the numbers back together with addition arithmetic rather than string concatenation, as in 0 + 1 + 8 + 9 = 189. Change that last line to look like this and you are fixed:
var incrypted = first + '' + second + '' + third + '' + fourth;
This worked for me;
<script>
var vec = new Array("1","2","3","4");
for(var i = 0; i<4; ++i){
vec[i] = (+vec[i] + 7) % 10;
}
var tmp = vec[1];
vec[1] = vec[3];
vec[3] = tmp;
vec = vec.reverse();
tmp = Number(vec.splice(0,1));
vec.push(tmp);
console.log("vec:", vec);
</script>
logs vec: [0, 1, 8, 9]

Add two timestamps of format "HH+:MM:SS"

So basically i have two strings of timestamps which i want to add:
a = "00:10:12";
aParts = a.split(/:/);
b = "00:30:34";
bParts = b.split(/:/);
time1 = 3600000 * parseInt(aParts[0]) + 60000 * parseInt(aParts[1]) + 1000 * parseInt(aParts[2]);
time2 = 3600000 * parseInt(bParts[0]) + 60000 * parseInt(bParts[1]) + 1000 * parseInt(bParts[2]);
dateTime = time1 + time2;
hours = parseInt(dateTime/3600000);
dateTime = parseInt(dateTime%3600000);
minutes = parseInt(dateTime/60000);
dateTime = parseInt(dateTime%60000);
seconds = parseInt(dateTime/1000);
newTime = addLeadingZeros(hours,2) + ':' + addLeadingZeros(minutes,2) + ':' + addLeadingZeros(seconds,2);
// returns correct "00:40:46"
function addLeadingZeros (n, length){
var str = (n > 0 ? n : -n) + "";
var zeros = "";
for (var i = length - str.length; i > 0; i--)
zeros += "0";
zeros += str;
return n >= 0 ? zeros : "-" + zeros;
}
While writing this question i managed to come up with the above code :-) that works somehow - is that a proper way of adding two string timestamps or is there a better approach?
Forgot to mention - i did try converting the two strings into Date objects and using .getTime() adding the two datetimes - but that gives me a wrong time in the date.
There is nothing notably wrong with your code, but be sure to set the radix when using parseInt
radix
An integer that represents the radix of the value to parse. Always
specify this parameter to eliminate reader confusion
and to guarantee predictable behavior. Different implementations
produce different results when a radix is not specified.
There is no standard method for performing the task that you have described.
Here is an example that I have used in the past.
Javascript
/*jslint maxerr: 50, indent: 4, browser: true, devel: true */
(function () {
"use strict";
function zeroPad(num) {
var str = num.toString();
if (num < 2) {
str = "0" + str;
}
return str;
}
function addTimes() {
if (!arguments.length) {
throw new SyntaxError("No arguments provided.");
}
var total = {
hours: 0,
minutes: 0,
seconds: 0
},
argIndex,
argLength,
time,
parts,
part,
partIndex,
temp;
for (argIndex = 0, argLength = arguments.length; argIndex < argLength; argIndex += 1) {
time = arguments[argIndex];
if (typeof time !== "string") {
throw new TypeError("Argument must be a string.");
}
parts = time.split(":");
if (parts.length !== 3) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
for (partIndex = 0; partIndex < 3; partIndex += 1) {
part = parts[partIndex];
if (partIndex < 2) {
if (part === "" || !/^\d*$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseInt(part, 10);
} else {
if (part === "" || !/^\d*\.?\d+$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseFloat(part);
}
}
temp = (parts[2] + total.seconds);
total.seconds = temp % 60;
temp = (parts[1] + total.minutes) + (temp - total.seconds) / 60;
total.minutes = temp % 60;
total.hours = (parts[0] + total.hours) + (temp - total.minutes) / 60;
}
return zeroPad(total.hours) + ":" + zeroPad(total.minutes) + ":" + zeroPad(total.seconds);
}
var a = "00:10:12",
b = "00:30:34",
c = "10:40:40";
console.log(addTimes(a, b, c));
}());
Output
11:21:26
On jsfiddle

JavaScript setTimeout not working with prompt box

Here is my code:
var t = setTimeout("increment();", 1000 * 3);
var st;
function increment() {
st = 1;
}
for (i = 0; i < 10; i++) {
cnt = i;
var no1 = Math.floor(Math.random() * 101);
var no2 = Math.floor(Math.random() * 101);
if ((i % 4) == 0) {
crct_ans[i] = no1 + no2;
quest[i] = no1 + " + " + no2;
}
else if ((i % 4) == 1) {
crct_ans[i] = no1 - no2;
quest[i] = no1 + " - " + no2;
}
else if ((i % 4) == 2) {
crct_ans[i] = no1 * no2;
quest[i] = no1 + " x " + no2;
}
else if ((i % 4) == 3) {
crct_ans[i] = no1 / no2;
quest[i] = no1 + " / " + no2;
}
ans[i] = prompt(quest[i], "");
if (st == 1) break;
}​
I want to stop the for loop if 3 seconds pass. But this is not working. For loop runs after the 3 seconds also. How can I do this?
Remove () and quotes like this:
var t = setTimeout(increment, 3000);
Removing () disables running of that function straright away/immediately whereas setTimeout expects callabck.
Removing quotes makes sure that eval isn't used behind the scenes.
BTW, it is good practice to declare all variables with single var keyword like this:
var t = setTimeout(increment, 3000), st;
If it suits your requirements, you can simply check how much time pass.
Example:
var start = new Date();
for(i = 0; i < 10; i++){
var end = new Date();
var elapsed = end.getTime() - start.getTime();
if (elapsed >= 3000)
break;
}​
Try formatting like so:
var t = setTimeout(function(){increment();}, 3000);

less than 10 add 0 to number [duplicate]

This question already has answers here:
How can I pad a value with leading zeros?
(76 answers)
Closed 4 years ago.
How can I modify this code to add a 0 before any digits lower than 10
$('#detect').html( toGeo(apX, screenX) + latT +', '+ toGeo(apY, screenY) + lonT );
function toGeo(d, max) {
var c = '';
var r = d/max * 180;
var deg = Math.floor(r);
c += deg + "° ";
r = (r - deg) * 60;
var min = Math.floor(r);
c += min + "′ ";
r = (r - min) * 60;
var sec = Math.floor(r);
c += sec + "″";
return c;
}
So the outpout would change from
4° 7′ 34″W, 168° 1′ 23″N
to
04° 07′ 34″W, 168° 01′ 23″N
Thanks for your time
You can always do
('0' + deg).slice(-2)
See slice():
You can also use negative numbers to select from the end of an array
Hence
('0' + 11).slice(-2) // '11'
('0' + 4).slice(-2) // '04'
For ease of access, you could of course extract it to a function, or even extend Number with it:
Number.prototype.pad = function(n) {
return new Array(n).join('0').slice((n || 2) * -1) + this;
}
Which will allow you to write:
c += deg.pad() + '° '; // "04° "
The above function pad accepts an argument specifying the length of the desired string. If no such argument is used, it defaults to 2. You could write:
deg.pad(4) // "0045"
Note the obvious drawback that the value of n cannot be higher than 11, as the string of 0's is currently just 10 characters long. This could of course be given a technical solution, but I did not want to introduce complexity in such a simple function. (Should you elect to, see alex's answer for an excellent approach to that).
Note also that you would not be able to write 2.pad(). It only works with variables. But then, if it's not a variable, you'll always know beforehand how many digits the number consists of.
Make a function that you can reuse:
function minTwoDigits(n) {
return (n < 10 ? '0' : '') + n;
}
Then use it in each part of the coordinates:
c += minTwoDigits(deg) + "° ";
and so on.
if(myNumber.toString().length < 2)
myNumber= "0"+myNumber;
or:
return (myNumber.toString().length < 2) ? "0"+myNumber : myNumber;
You can always do
('0' + deg).slice(-2)
If you use it very often, you may extend the object Number
Number.prototype.pad = function(n) {
if (n==undefined)
n = 2;
return (new Array(n).join('0') + this).slice(-n);
}
deg.pad(4) // "0045"
where you can set any pad size or leave the default 2.
You can write a generic function to do this...
var numberFormat = function(number, width) {
return new Array(+width + 1 - (number + '').length).join('0') + number;
}
jsFiddle.
That way, it's not a problem to deal with any arbitrarily width.
Hope, this help:
Number.prototype.zeroFill= function (n) {
var isNegative = this < 0;
var number = isNegative ? -1 * this : this;
for (var i = number.toString().length; i < n; i++) {
number = '0' + number;
}
return (isNegative ? '-' : '') + number;
}
Here is Genaric function for add any number of leading zeros for making any size of numeric string.
function add_zero(your_number, length) {
var num = '' + your_number;
while (num.length < length) {
num = '0' + num;
}
return num;
}
I was bored and playing around JSPerf trying to beat the currently selected answer prepending a zero no matter what and using slice(-2). It's a clever approach but the performance gets a lot worse as the string gets longer.
For numbers zero to ten (one and two character strings) I was able to beat by about ten percent, and the fastest approach was much better when dealing with longer strings by using charAt so it doesn't have to traverse the whole string.
This follow is not quit as simple as slice(-2) but is 86%-89% faster when used across mostly 3 digit numbers (3 character strings).
var prepended = ( 1 === string.length && string.charAt( 0 ) !== "0" ) ? '0' + string : string;
$('#detect').html( toGeo(apX, screenX) + latT +', '+ toGeo(apY, screenY) + lonT );
function toGeo(d, max) {
var c = '';
var r = d/max * 180;
var deg = Math.floor(r);
if(deg < 10) deg = '0' + deg;
c += deg + "° ";
r = (r - deg) * 60;
var min = Math.floor(r);
if(min < 10) min = '0' + min;
c += min + "′ ";
r = (r - min) * 60;
var sec = Math.floor(r);
if(sec < 10) sec = '0' + sec;
c += sec + "″";
return c;
}
A single regular expression replace should do it:
var stringWithSmallIntegers = "4° 7′ 34″W, 168° 1′ 23″N";
var paddedString = stringWithSmallIntegers.replace(
/\d+/g,
function pad(digits) {
return digits.length === 1 ? '0' + digits : digits;
});
alert(paddedString);
shows the expected output.

Categories

Resources