I'm trying to write a script for roulette system and I want the script to run until the bank variable reaches 0 or 11,000, and produce three pieces of data after each spin.
I have left parts of the code out for simplicity. The code in the if else statement is not the problem. Running the script until the variable reaches a certain point is where I'm stuck.
Would anyone be able to help me rewrite this script please? Thanks in advance.
(function() {
var bank = 10000;
var bet = 1;
function spin() {
var number = Math.floor(Math.random() * 36);
if ( number == 0 ) {
document.write("<p>The number " + number + " is neither high nor low.</p>");
// removed
}
else if ( number > 18 ) {
document.write("<p>The number " + number + " is a high number.</p>");
// removed
}
else {
document.write("<p>The number " + number + " is a low number.</p>");
// removed
}
};
spin();
document.write("<p>Total bank is now " + bank + ".</p>");
document.write("<p>The next bet is " + bet + ".</p>");
})();
If you're calling this loop within a page (i.e. you don't want the page to hang up for the duration, or want to display results) you should use requestAnimationFrame:
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
Then set up your loop to only call itself if the bank is within your accepted range:
function spinLoop() {
spin();
//perform your UI updates here
if (bank >= 0 && bank <= 11000) requestAnimFrame(spinLoop);
}
You will, of course, need to call this function initially to start the loop:
spinLoop();
Related
The game is WAR, or Get Your Neighbour, a traditional game utilising a standard deck of 52 cards, no jokers. Currently the code recognises when a card is above 10 and so the rules of the game are being followed, all that is great, I've designed a timer that takes the value of the card 2-14, subtracts 10, then uses that number for the round of turns the other player has to draw above 10 before you win. Still building the cooperative/multiplayer element but for now, I'd just like to get this bloody button working!
When I click it, it does nothing. Before, it would tell me that "'timerf' is not a function". I'm probably doing something very obvious like problems with the order that things are loaded/data is parsed, but I'm still learning so I'd appreciate any help! Any questions, let me know.
var card = null; // setem 160517
var timer = null; //
window.onload = function() {
function draw(min, max) { // draw a card between 2-14
card = document.getElementById("draw").innerHTML = Math.floor(Math.random()*((max - min)+1) + min); // min 2, max 14
if (card > 10) {
timer = card - 10;
timerf(timer);
} else if (card < 11 && timer > 0) {
timer = timerf(timer-1);
}
} // draw
//draw(2,14);
document.getElementById("clickMe").onclick = draw(2,14);
} // window.onload
function timerf(timer) { // print turns to win
if (timer > 0 && timer < 5 && timer != 1) { // print turns to win
console.log("you have " + timer + " turns to win!");
} else if (timer == 1) {
console.log("you have " + timer + " turn to win!");
}
}
<div id="draw"></div>
<button id="clickMe">WAR!</button>
The return value of the draw function is undefined because it has no return statement.
document.getElementById("clickMe").onclick = draw(2,14);
… so you are assigning undefined to the onclick property.
You have to assign the function you want to call.
I have a long loop that takes maybe 10 mins or more, and I want to set always a new time to avoid it to continue. But it dosen't works.
function problem3(){
var img = document.getElementById('p_3');
img.style.display = img.style.display === 'block' ? 'none' : 'block';
var number=600851475143;
var t = new Date();
for(var i=3;i*i<=number;i+=2){
if(isPrime(i) && number%i==0){
var maxPrime = i;
}
setInterval(function(){time(t)},5000);
}
document.getElementById("p3").innerHTML = 'Il più grande divisiore primo di <span>'+number+"</span> è <span>" + maxPrime+"</span>";
}
function time(t){
return console.log(Date() - t);
}
If I put console.log(Date() - t);in the problem3() function it works, but I can't do Date()-t every 5 seconds, something like setInterval(Date()-t,5000)
This is a case where you might consider using the workers API. Instead of freezing the browser, let the job be done in the background and call back to the main thread when it's done.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
JavaScript is not multithreaded. So we think of setInterval() as running a piece of code every n ms (5000 in your example). But that's not quite true. If there's already script running when the interval elapses, the best that can happen is the bit of code gets added to a queue to be executed - but nothing from that queue is going to run until the already-running script finishes.
So in rough terms that's why it's not working, but what to do? Well, if you want anything to happen before problem3() returns, then problem3() is going to have to make it happen in a synchronous way.
For example, you could create a lastOutputTime variable, initialize it to the current time, and on each iteration through the for loop compare the current time to the stored value. If 5 seconds have passed, output to console and update lastOutputTime.
Your algorithm should be improved to something like this:
function maxPrimeFactor(number) {
if (number == 0 || !Number.isInteger(number) ||
number > Number.MAX_SAFE_INTEGER) return NaN;
number = Math.abs(number);
while(number % 2 == 0) number /= 2;
for (var i = 3; i * i <= number; i += 2) {
while(number % i == 0) number /= i;
}
return number;
}
var number = 600851475143;
console.log('maxPrimeFactor(' + number + ') == ' + maxPrimeFactor(number));
If for some numbers you need too much time, then break the loop into smaller chunks and asynchronize. But never use setInterval for this, and especially never use setInterval inside a long loop. setInterval schedules some task to run every n milliseconds, so if you use it in a loop, after i iterations, the task will run i every n milliseconds! And setInterval is so problematic because it can freeze the browser if the task takes more than n milliseconds. You should use setTimeout instead.
However, this would be useless in this case. The algorithm above can detect that 304250263527209 (15 digits) is a prime almost instantly. Given that the maximum safe integer is 9007199254740991 (16 digits), I don't think you will have problems for any number.
If you say the algorithm takes so long, it may be because you are trying it with bigger numbers. But be aware JS numbers are 64-bit floating point numbers, and thus integers can't be represented accurately above Number.MAX_SAFE_INTEGER. You will get a wrong result anyways, so do not even try to calculate that.
In the case of the Project Euler #551, a brute-force approach would be
function sumOfDigits(n) {
var sum = 0;
while(n != 0) {
sum += n % 10;
n = Math.floor(n/10);
}
return sum;
}
function sumDigitsSeq(n) {
return new Promise(function(resolve) {
var i = 1;
var chunkSize = 1e5;
var sum = 1;
(function chunk() {
chunkSize = Math.min(chunkSize, n-i);
for (var j=0; j<chunkSize; ++j, ++i) {
sum += sumOfDigits(sum);
}
if (i >= n) return resolve(sum);
console.log('Please wait. sumDigitsSeq(' + i + ') == ' + sum);
setTimeout(chunk, 60);
})();
});
}
var number = 1e6;
sumDigitsSeq(number).then(function(result) {
console.log('Done! sumDigitsSeq(' + number + ') == ' + result);
});
Of course brute-force is not the appropriate way to solve the problem.
I'm trying to make a program where the user guesses a number from 1 to 100. You get 10 guesses and, the program should tell the user if his/hers guess is too high or too low along the way, however the program does not write on the document until all 10 guesses are used. How can I get around this?
Here is my code:
var a = Math.random();
var b = a * (101 - 1) + 1;
var c = Math.floor(b);
document.write(b + "<br>");
document.write(c + "<br>");
var d = 1;
while (gjett != c && d <= 10) {
var gjett = Number(prompt("Gjett på et tall fra 0 til 100"));
if (gjett < c) {
document.write("Tallet er høyere enn " + gjett + ".<br>");
}
if (gjett > c) {
document.write("Tallet er lavere enn " + gjett + ".<br>");
}
d = d + 1;
}
Pro-tip: don't use document.write.
Now, the reason you aren't seeing anything is, basically, the browser is either in JavaScript mode or rendering mode. As long as some JavaScript is running, the DOM is not going to be rendered. That way if you make multiple changes to the DOM, the browser doesn't waste resources on rendering all of the little changes in between.
A better way of handling this would be with a button and some kind of input.
// Wait for the user to click on the button
document.querySelector('button').addEventListener('click', function() {
// Get the value the user put in
var inputEl = document.querySelector('input');
// Make sure it's an integer
var value = parseInt(inputEl.value);
// Get the output element
var outputEl = document.getElementById('output');
// Tell the user what they guessed
outputEl.innerHTML = 'You guessed ' + value;
});
<input type="text" />
<button>Try</button>
<br />
<p id="output"></p>
You can figure out the actual logic of the guessing game yourself ;)
As others have suggested, you should avoid using document.write() in real-world applications, as there are more effective ways of adding elements to a page.
To answer your question: you don't see the page update while you're repeatedly submitting your guesses because the browser is still evaluating your while() loop, and deferring the re-rendering of the visible page until the while loop terminates.
The most direct way to achieve what you're asking, without changing much of your code, would be to substitute your while loop with an interval, such that your code executes asynchronously and doesn't block the browser from updating the rendered page. (Because of its blocking nature, confirm() (like other methods like alert()) is probably not the best choice for this interaction.)
var a = Math.random();
var b = a * (101 - 1) + 1;
var c = Math.floor(b);
document.write(b + "<br>");
document.write(c + "<br>");
var d = 1;
var interval = setInterval(function() {
if (gjett != c && d <= 10) {
var gjett = Number(prompt("Gjett på et tall fra 0 til 100"));
if (gjett < c) {
document.write("Tallet er høyere enn " + gjett + ".<br>");
}
if (gjett > c) {
document.write("Tallet er lavere enn " + gjett + ".<br>");
}
} else {
clearInterval(interval);
}
}, 0);
I didn't think this was possible until console.log(); shown me that whats happening is impossible.
I can't understand how this is possible it's like those variables are being modified before code execution finishes.
I got this JavaScript code with debugging in it.
It's wrapped in this.
$('#buyAmountInput').keyup(function () {
var buyAmount = parseFloat($(this).val());
var totalPrice = 0;
var max = $(this).attr("max");
var min = $(this).attr("min");
if (buyAmount != $(this).val()) {
if (isNaN(buyAmount)) {
buyAmount = 1;
$(this).val('');
} else {
$(this).val(buyAmount);
}
} else {
if (buyAmount > max) {
buyAmount = max;
$(this).val(buyAmount);
} else if (buyAmount < min) {
buyAmount = min;
//$(this).val(buyAmount);
}
}
totalPrice = buyAmount * unitPrice;
//lots of code trimmed off here.
largessAmount = Math.round(buyAmount * largessRule.rebate) / 100;
////
console.log("Buy amount " + buyAmount + " LargessRebate " + largessRule.rebate);
console.log("Total Price " + totalPrice);
console.log("Largess Amount " + largessAmount);
console.log("New rate " + Number(totalPrice / (buyAmount + largessAmount)).moneyFormat());
console.log("No .moneyFormat() New rate " + Number(totalPrice / (buyAmount + largessAmount)));
console.log("( " + totalPrice + " / ( " + buyAmount + " + " + largessAmount + " ))");
////
$('#unitPrice').html(Number(totalPrice / (buyAmount + largessAmount)).moneyFormat());
});
Debug looks like this
Buy amount 5000 LargessRebate 20
Total Price 4250
Largess Amount 1000
New rate 0.71
No .moneyFormat() New rate 0.7083333333333334
( 4250 / (5000 + 1000))
function fastKeyListener content_script.js:208
Buy amount 5000 LargessRebate 20
Total Price 4250
Largess Amount 1000
New rate 0.00 //<- What happened here
No .moneyFormat() New rate 0.00008499830003399932 //<- What happened here
( 4250 / (5000 + 1000)) //<- Third line executed this will give good rate..
Even if the variables are global and this code is in a keypress up jQuery callback function.
The variables are printed before they are executed by console.log() and they are correct but the answer is dead wrong.
Here is the moneyFormat() which I don't think could be the problem could it?
var effective_bit = -2;
Number.prototype.moneyFormat = function () {
var num = this;
sign = (num == (num = Math.abs(num)));
num = Math.floor(num * Math.pow(10, -effective_bit) + 0.50000000001);
cents = num % Math.pow(10, -effective_bit);
num = Math.floor(num / Math.pow(10, -effective_bit)).toString();
for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
num = num.substring(0, num.length - (4 * i + 3)) + ', ' + num.substring(num.length - (4 * i + 3));
if (effective_bit < 0) {
if (cents < 10 && effective_bit == '-2') cents = "0" + cents;
money = (((sign) ? '' : '-') + num + '.' + cents);
} else {
money = (((sign) ? '' : '-') + num);
}
return money;
};
I didn't post the whole code as it's very large, but you can see it live here
Just put into the Unit to buy of 4999, then scroll to 5000 it's all good.. try putting like 5001 or 50000 it will reset it to 5000 and give wrong answer in the process.
EDIT:
could of simplified the question to why does the console.log() functions evaluate incorrect answer if the same equation generated with the same variables just 1 line after in execution after gives correct answer, even on calculator.
Like some quantum going on here, bear with me there is nothing I could have done from 1 line to another line during that code-execution no breakpoints were set nothing plus those callbacks are functions generated in their own sandbox I believe so they are like ajax threads all working to complete sooner or later they all work separately from each other, so nothing working together here to mess it up. What you think could possibly happen here? some temporarily corruption or something?
This occurs sometimes when doing claulations using string variables.
Try converting the buyAmount and any variable that came from HTML to number before any calculation.
You can use the Number() function or parseFloat().
http://jsfiddle.net/rcdmk/63qas2kw/1/
Below is the functions I use to run a function periodically. I use the function to change the background of the body. but it doesn't get fired for some reason. Please help me with this code.
setInterval(uiImageChanger(),1);
function uiImageChanger(){
var currentTime = new Date().getHours();
var images = ['image1.jpg','image2.jpg'];
if( currentTime > 00 && currentTime <= 12){
$('body').css('background-image', "url(" + randomImagePicker(images ,'breakfast') + ")");
}else if( currentTime > 12 && currentTime <= 16){
$('body').css('background-image', "url(" + randomImagePicker(images ,'lunch') + ")");
}else if( currentTime > 16 && currentTime <= 00){
$('body').css('background-image', "url(" + randomImagePicker(images ,'dinner') + ")");
}
}
function randomImagePicker(imgArray,time){
if(time == 'breakfast'){
return "../images/main_image/breakfast/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}else if(time == 'lunch'){
return "../images/main_image/lunch/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}else if(time == 'dinner'){
return "../images/main_image/dinner/" + imgArray[Math.floor(Math.random() * imgArray.length)];
}
}
Thank you.
Remove parens from the setInterval function argument. Now, this will invoke the function and set the return value of the function as the reference to setInterval which here is undefined as you don't return anything. So basically you are setting interval on nothing, so nothing happens except the first execution while setting up the setInterval.
Change
setInterval(uiImageChanger(),1); // This will invoke the function immediately.
to
setInterval(uiImageChanger,1); // You want to set the reference of the function to setInterval.
You have to pass a pointer to a function and not execute the function.
setInterval(uiImageChanger,1);
There are multiple ways of defining the function to be executed using setInterval.
One of the method is using the function reference for which the example is given by #mohkhan.
However you can do the following as well
setInterval(function(){
// code comes here.
}, time_in_mills);
Also I see that you have mentioned the value for the function execution as 1. This means every 1 millisecond the function will be executed, which is not a good practice at all. Give a realistic time in millisecond so that you have given sufficient time for the code to execute.
You've gotten several answers about the setInterval() problem. I'd like to point out a couple of other problems in the code.
First, this test will always fail:
else if( currentTime > 16 && currentTime <= 00)
After all, if a number is > 16 it cannot also be <= 0.
Also, you may get a warning about 00 being an octal constant which is deprecated. Of course, octal zero is the same value as decimal zero, but watch out for inadvertent octal constants: avoid using a leading zero.
And there is a lot of repetition in the code. You can easily remove all of this repetition to make the code more maintainable. Consider this approach:
// Return a random integer >= 0 and < n
function randomInt( n ) {
return Math.floor( Math.random() * n );
}
// Return a random element from an array
function randomElement( array ) {
return array[ randomInt(array.length) ];
}
function uiImageChanger(){
var hour = new Date().getHours();
var meal =
hour <= 12 ? 'breakfast' :
hour <= 16 ? 'lunch' :
'dinner';
var images = [ 'image1.jpg', 'image2.jpg' ];
$('body').css(
'background-image',
'url(../images/main_image/' + meal +
'/' + randomElement(images) + ')'
);
}