how to spawn 1 to 3 objects randomly many times Javascript - javascript

I am trying to spawn 1 to 3 monsters randomly many times in Javascript, this is the code i have for now but this only makes it randomly spawn when i refresh and then it keeps spawning the same amount of monsters the whole time.
function spawnMonster(){
setInterval(function(){
for(var i = 0; i < randomMonster; i++){
monsterDiv.innerHTML += monsterPic;
outputDiv.innerHTML = "monstrene angriper.</br>" + outputDiv.innerHTML;
}
}, Math.floor(Math.random()* 3000) + 1000);
}

I'm assuming randomMonster is the random value between 1-3.
When the variable is set, it (obviously) doesn't change as you did describe.
Just make sure you calculate a new randomMonster -value inside the setInterval function:
function spawnMonster(){
setInterval(function(){
const randomMonster = Math.floor(Math.random() * 3) + 1;
for(var i = 0; i < randomMonster; i++){
monsterDiv.innerHTML += monsterPic;
outputDiv.innerHTML = "monstrene angriper.</br>" + outputDiv.innerHTML;
}
}, Math.floor(Math.random() * 3000) + 1000);
}

Related

Why is precomputing sin(x) *slower* than using Math.sin() in Javascript?

I've found what appears to be an interesting anomaly in JavaScript. Which centres upon my attempts to speed up trigonometric transformation calculations by precomputing sin(x) and cos(x), and simply referencing the precomputed values.
Intuitively, one would expect pre-computation to be faster than evaluating the Math.sin() and Math.cos() functions each time. Especially if your application design is going to use only a restricted set of values for the argument of the trig functions (in my case, integer degrees in the interval [0°, 360°), which is sufficient for my purposes here).
So, I ran a little test. After pre-computing the values of sin(x) and cos(x), storing them in 360-element arrays, I wrote a short test function, activated by a button in a simple test HTML page, to compare the speed of the two approaches. One loop simply multiplies a value by the pre-computed array element value, whilst the other loop multiplies a value by Math.sin().
My expectation was that the pre-computed loop would be noticeably faster than the loop involving a function call to a trig function. To my surprise, the pre-computed loop was slower.
Here's the test function I wrote:
function MyTest()
{
var ITERATION_COUNT = 1000000;
var angle = Math.floor(Math.random() * 360);
var test1 = 200 * sinArray[angle];
var test2 = 200 * cosArray[angle];
var ref = document.getElementById("Output1");
var outData = "Test 1 : " + test1.toString().trim() + "<br><br>";
outData += "Test 2 : "+test2.toString().trim() + "<br><br>";
var time1 = new Date(); //Time at the start of the test
for (var i=0; i<ITERATION_COUNT; i++)
{
var angle = Math.floor(Math.random() * 360);
var test3 = (200 * sinArray[angle]);
//End i loop
}
var time2 = new Date();
//This somewhat unwieldy procedure is how we find out the elapsed time ...
var msec1 = (time1.getUTCSeconds() * 1000) + time1.getUTCMilliseconds();
var msec2 = (time2.getUTCSeconds() * 1000) + time2.getUTCMilliseconds();
var elapsed1 = msec2 - msec1;
outData += "Test 3 : Elapsed time is " + elapsed1.toString().trim() + " milliseconds<br><br>";
//Now comparison test with the same number of sin() calls ...
var time1 = new Date();
for (var i=0; i<ITERATION_COUNT; i++)
{
var angle = Math.floor(Math.random() * 360);
var test3 = (200 * Math.sin((Math.PI * angle) / 180));
//End i loop
}
var time2 = new Date();
var msec1 = (time1.getUTCSeconds() * 1000) + time1.getUTCMilliseconds();
var msec2 = (time2.getUTCSeconds() * 1000) + time2.getUTCMilliseconds();
var elapsed2 = msec2 - msec1;
outData += "Test 4 : Elapsed time is " + elapsed2.toString().trim() + " milliseconds<br><br>";
ref.innerHTML = outData;
//End function
}
My motivation for the above, was that multiplying by a pre-computed value fetched from an array would be faster than invoking a function call to a trig function, but the results I obtain are interestingly anomalous.
Some sample runs yield the following results (Test 3 is the pre-computed elapsed time, Test 4 the Math.sin() elapsed time):
Run 1:
Test 3 : Elapsed time is 153 milliseconds
Test 4 : Elapsed time is 67 milliseconds
Run 2:
Test 3 : Elapsed time is 167 milliseconds
Test 4 : Elapsed time is 69 milliseconds
Run 3 :
Test 3 : Elapsed time is 265 milliseconds
Test 4 : Elapsed time is 107 milliseconds
Run 4:
Test 3 : Elapsed time is 162 milliseconds
Test 4 : Elapsed time is 69 milliseconds
Why is invoking a trig function twice as fast as referencing a precomputed value from an array, when the precomputed approach, intuitively at least, should be the faster by an appreciable margin? All the more so because I'm using integer arguments to index the array in the precomputed loop, whilst the function call loop also includes an extra calculation to convert from degrees to radians?
There's something interesting happening here, but at the moment, I'm not sure what. Usually, array accesses to precomputed data are a lot faster than calling intricate trig functions (or at least, they were back in the days when I coded similar code in assembler!), but JavaScript seems to turn this on its head. The only reason I can think of, is that JavaScript adds a lot of overhead to array accesses behind the scenes, but if this were so, this would impact upon a lot of other code, that appears to run at perfectly reasonable speed.
So, what exactly is going on here?
I'm running this code in Google Chrome:
Version 60.0.3112.101 (Official Build) (64-bit)
running on Windows 7 64-bit. I haven't yet tried it in Firefox, to see if the same anomalous results appear there, but that's next on the to-do list.
Anyone with a deep understanding of the inner workings of JavaScript engines, please help!
Optimiser has skewed the results.
Two identical test functions, well almost.
Run them in a benchmark and the results are surprising.
{
func : function (){
var i,a,b;
D2R = 180 / Math.PI
b = 0;
for (i = 0; i < count; i++ ) {
// single test start
a = (Math.random() * 360) | 0;
b += Math.sin(a * D2R);
// single test end
}
},
name : "summed",
},{
func : function (){
var i,a,b;
D2R = 180 / Math.PI;
b = 0;
for (i = 0; i < count; i++ ) {
// single test start
a = (Math.random() * 360) | 0;
b = Math.sin(a * D2R);
// single test end
}
},
name : "unsummed",
},
The results
=======================================
Performance test. : Optimiser check.
Use strict....... : false
Duplicates....... : 4
Samples per cycle : 100
Tests per Sample. : 10000
---------------------------------------------
Test : 'summed'
Calibrated Mean : 173µs ±1µs (*1) 11160 samples 57,803,468 TPS
---------------------------------------------
Test : 'unsummed'
Calibrated Mean : 0µs ±1µs (*1) 11063 samples Invalid TPS
----------------------------------------
Calibration zero : 140µs ±0µs (*)
(*) Error rate approximation does not represent the variance.
(*1) For calibrated results Error rate is Test Error + Calibration Error.
TPS is Tests per second as a calculated value not actual test per second.
The benchmarker barely picked up any time for the un-summed test (Had to force it to complete).
The optimiser knows that only the last result of the loop for the unsummed test is needed. It only does for the last iteration all the other results are not used so why do them.
Benchmarking in javascript is full of catches. Use a quality benchmarker, and know what the optimiser can do.
Sin and lookup test.
Testing array and sin. To be fair to sin I do not do a deg to radians conversion.
tests : [{
func : function (){
var i,a,b;
b=0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += a;
}
},
name : "Calibration",
},{
func : function (){
var i,a,b;
b = 0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += array[a];
}
},
name : "lookup",
},{
func : function (){
var i,a,b;
b = 0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += Math.sin(a);
}
},
name : "Sin",
}
],
And the results
=======================================
Performance test. : Lookup compare to calculate sin.
Use strict....... : false
Data view........ : false
Duplicates....... : 4
Cycles........... : 1055
Samples per cycle : 100
Tests per Sample. : 10000
---------------------------------------------
Test : 'Calibration'
Calibrator Mean : 107µs ±1µs (*) 34921 samples
---------------------------------------------
Test : 'lookup'
Calibrated Mean : 6µs ±1µs (*1) 35342 samples 1,666,666,667TPS
---------------------------------------------
Test : 'Sin'
Calibrated Mean : 169µs ±1µs (*1) 35237 samples 59,171,598TPS
-All ----------------------------------------
Mean : 0.166ms Totals time : 17481.165ms 105500 samples
Calibration zero : 107µs ±1µs (*);
(*) Error rate approximation does not represent the variance.
(*1) For calibrated results Error rate is Test Error + Calibration Error.
TPS is Tests per second as a calculated value not actual test per second.
Again had the force completions as the lookup was too close to the error rate. But the calibrated lookup is almost a perfect match to the clock speed ??? coincidence.. I am not sure.
I believe this to be a benchmark issue on your side.
var countElement = document.getElementById('count');
var result1Element = document.getElementById('result1');
var result2Element = document.getElementById('result2');
var result3Element = document.getElementById('result3');
var floatArray = new Array(360);
var typedArray = new Float64Array(360);
var typedArray2 = new Float32Array(360);
function init() {
for (var i = 0; i < 360; i++) {
floatArray[i] = typedArray[i] = Math.sin(i * Math.PI / 180);
}
countElement.addEventListener('change', reset);
document.querySelector('form').addEventListener('submit', run);
}
function test1(count) {
var start = Date.now();
var sum = 0;
for (var i = 0; i < count; i++) {
for (var j = 0; j < 360; j++) {
sum += Math.sin(j * Math.PI / 180);
}
}
var end = Date.now();
var result1 = "sum=" + sum + "; time=" + (end - start);
result1Element.textContent = result1;
}
function test2(count) {
var start = Date.now();
var sum = 0;
for (var i = 0; i < count; i++) {
for (var j = 0; j < 360; j++) {
sum += floatArray[j];
}
}
var end = Date.now();
var result2 = "sum=" + sum + "; time=" + (end - start);
result2Element.textContent = result2;
}
function test3(count) {
var start = Date.now();
var sum = 0;
for (var i = 0; i < count; i++) {
for (var j = 0; j < 360; j++) {
sum += typedArray[j];
}
}
var end = Date.now();
var result3 = "sum=" + sum + "; time=" + (end - start);
result3Element.textContent = result3;
}
function reset() {
result1Element.textContent = '';
result2Element.textContent = '';
result3Element.textContent = '';
}
function run(ev) {
ev.preventDefault();
reset();
var count = countElement.valueAsNumber;
setTimeout(test1, 0, count);
setTimeout(test2, 0, count);
setTimeout(test3, 0, count);
}
init();
<form>
<input id="count" type="number" min="1" value="100000">
<input id="run" type="submit" value="Run">
</form>
<dl>
<dt><tt>Math.sin()</tt></dt>
<dd>Result: <span id="result1"></span></dd>
<dt><tt>Array()</tt></dt>
<dd>Result: <span id="result2"></span></dd>
<dt><tt>Float64Array()</tt></dt>
<dd>Result: <span id="result3"></span></dd>
</dl>
In my testing, an array is unquestionably faster than an uncached loop, and a typed array is marginally faster than that. Typed arrays avoid the need for boxing and unboxing the number between the array and the computation. The results I see are:
Math.sin(): 652ms
Array(): 41ms
Float64Array(): 37ms
Note that I am summing and including the results, to prevent the JIT from optimizing out the unused pure function. Also, Date.now() instead of creating seconds+millis yourself.
I agree with that the issue may be down to how you have initialised the pre-computed array
Jsbench shows the precomputed array to be 13% faster than using Math.sin()
Precomputed array: 86% (fastest 1480 ms)
Math.sin(): 100% (1718 ms)
Precomputed Typed Array: 87% (1493 ms)
Hope this helps!

Add random number at Random time intervals

The thing is I want to add random number to a variable which is initially 0 which has to happen after a random timeout until the variable reaches 100.
$scope.var1 = 0;
do{
$timeout(function(){
$scope.var1 += Math.floor(Math.random() * 100 +1);
},Math.floor(Math.random() * 100 +1));
console.log($scope.var1);
}while($scope.var1<100)
$scope.var1 always stays 0, hence it goes to an infinite loop;
You get inifinity loop since $timeout function, that you use, is async, but your loop is sync. You have to use recursion:
$scope.var1 = 0;
function recursiveTimeout(){
$timeout(function(){
if($scope.var1 < 100){
$scope.var1 += Math.floor(Math.random() * 10 + 1);
console.log($scope.var1);
recursiveTimeout()
}
}, Math.floor(Math.random() * 1000 + 1));
}
recursiveTimeout()
http://jsfiddle.net/dwypcx1f/3/
Math.random is a JS function, so it has to be Math.floor(Math.random() * 100 +1); instead of Math.floor(Math.random * 100 +1);
I didn't checked the rest of your code.
You start a new loop on every loop iteration. I am not sure about the correct AngularJS syntax since I prefer Angular2, but something like this should work...
$scope.var1 = 0;
var repeatFunc = function repeatFunc() {
var num = Math.floor(Math.random() * 100 +1);
$scope.var1 += num;
console.log("num: ", num);
if ($scope.var1 < 100)
$timeout(repeatFunc, num);
}
repeatFunc();

Javascript - few intervals in right order

In my code I have three intervals which should be executed random times one after the another.
var times = Math.floor((Math.random() * 3) + 2);
var turn = 0;
var schemaInterval1 = setInterval(function(){
console.log('first');
turn++;
if(turn == times)
{
times = Math.floor((Math.random() * 3) + 2);
turn = 0;
clearInterval(schemaInterval1);
}
},1000);
var schemaInterval2 = setInterval(function(){
console.log('second');
turn++;
if(turn == times)
{
times = Math.floor((Math.random() * 3) + 2);
turn = 0;
clearInterval(schemaInterval2);
}
},1000);
var schemaInterval3 = setInterval(function(){
console.log('third');
turn++;
if(turn == times)
{
times = Math.floor((Math.random() * 3) + 2);
turn = 0;
clearInterval(schemaInterval3);
}
},1000);
After each execution of the code within interval, I add 1 to the turn value. When turn and times values are equal I reset both of them. Leave currently working interval and skip to another one. But unfortunately they don't work in correct order and in my console I get that message:
first
second
third
first
second
first
(4)second
How can I rewrite my code to put those intervals in proper order and don't allow others work until first finish it's task?
You start your intervals all at the same time. If you want to run them in series, you have to start one when you clear the previous one.
This code should do what you are looking for:
var times = Math.floor((Math.random() * 3) + 2);
var turn = 0;
var intervalNumber = 1;
var intervalTime = 1000;
var numberOfIntervals = 3;
function instantiateInterval() {
if (intervalNumber <= numberOfIntervals) {
console.log('Timer number: ' + intervalNumber);
var interval = setInterval(function() {
turn++;
if(turn === times) {
times = Math.floor((Math.random() * 3) + 2);
turn = 0;
clearInterval(interval);
instantiateInterval();
}
}, intervalTime);
intervalNumber++;
}
}
instantiateInterval();

Ease time between firing specific number of timeouts in a specific period of time

It's kind of math problem. I want to fire specific number of setTimeout (the number is based on an array length) in a specific period of time (say, 5 seconds).
The first setTimeout should start at 0 sec. and the last at 5 sec.. All timeouts between should start with an ease-in effect, so that each timeout starts faster.
There's an example which ilustrates what I want to achieve exactly.
I'm struggling around this line:
next += timePeriod/3.52/(i+1);
which works almost perfect in demo example (for any timePeriod), but obviously it doesn't work for a different letters.length as I have used static number 3.52.
How do I calculate next?
var letters = [
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T'
];
var div = $('#container');
var timePeriod = 5000; // 5 seconds;
var perLetter = timePeriod/(letters.length-1); // it gives equal time between letters
var next = 0;
for(var i=0; i<letters.length; i++){
setTimeout(function(letter){
//div.append('<span class="letter">' + letter + '</span>');
// Used "|" instead of letter, For better redability:
div.append('<span class="letter">|</span>');
}, next, letters[i]);
// Can't find the logic here:
next += timePeriod/3.52/(i+1);
};
///////////////// FOR DEMO: ///////////////
var sec = timePeriod/1000;
var secondsInterval = setInterval(seconds, 1000);
var demoInterval = setInterval(function(){
sec >= 0 || clearInterval(demoInterval);
div.append('\'');
}, 30);
function seconds(){
sec || clearInterval(secondsInterval);
$('#sec').text(sec-- || 'DONE');
}
seconds();
.letter{
color : red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id=container></span>
<span id=sec class=letter></span>
var steps = letters.length;
var target = timePeriod;
function easeOutQuad(t, b, c, d) {
t /= d;
return -c * t*(t-2) + b;
};
var arrayOfTimeouts = new Array(steps);
var n;
var prev = 0;
for(var i = 1; i <= steps; i++){
n = easeOutQuad(i, 0.0, target, steps);
arrayOfTimeouts[i-1] = n-prev;
prev = n;
}
This one should work with any input value.
fiddle
Note that the graph appears to be slightly too fast but I believe that discrepancy to be a product of timing imperfections, as the sum of my array equals the timePeriod exactly.
more on easing equations
Here's a solution based on a geometric series. It's a bit goofy but it works. It generates an array with your timeout values.
Steps = size of your array.
Target = the total time.
var steps = 50;
var target = 5000;
var fraction = 1.5 + steps / 7;
var ratio = (fraction-1) / fraction;
var n = target / fraction;
var sum = 0;
var arrayOfTimeouts = new Array(steps);
for(var i = 0; i < steps; i++){
sum += n;
arrayOfTimeouts[i] = n;
n *= ratio;
}
console.log(arrayOfTimeouts, sum);

Howto run function every few seconds that has return values?

How can I run this every few second , without blocking the rest of the pagefrom loading.
function Create() {
var SomeArray = [];
for ( var i=0; i<=1 ; i ++) {
SomeArray[i] = (Math.random() * 10) + 1;
//alert(arr[0]);
}
return SomeArray;
}
var x = Create();
alert(x[0] + x[1]);
I was trying this var timer = setInterval(Create, 5000); it prevent loading rest of the page.
i want to get new values every few seconds
A basic example would be:
var counter = 0;
var timerRef;
var increment = function() {
counter += 1;
console.log(counter);
timerRef = setTimeout(increment, 1000);
}
setTimeout(increment, 1000);
// clearTimeout(timerRef);
Please avoid document.write refer the screencast for further details.
setInterval() can be configured to repeatedly call any function you designate at whatever time interval you request. But, you can't retrieve a return value from that function. Instead, you need to process the results from within the callback that you pass to setInterval() or call some other function and pass the results you generate inside the callback. This is how asynchronous functions work in JavaScript. I've provided several examples below of your options:
If you just want to generate two random decimal values between 1 and 10 (inclusive) every 5 seconds, you can do that like this:
var interval = setInterval(function() {
var rand1 = (Math.random() * 10) + 1;
var rand2 = (Math.random() * 10) + 1;
// now insert code here to do something with the two random numbers
}, 5000);
If you wanted the random values to be integers (which is more common), then you would do this:
var interval = setInterval(function() {
var rand1 = Math.floor(Math.random() * 10) + 1;
var rand2 = Math.floor(Math.random() * 10) + 1;
// now insert code here to do something with the two random numbers
}, 5000);
If you want to call a function and pass it those two random numbers, you can do this:
function processRandoms(r1, r2) {
// code here to do something with the two random numbers
}
var interval = setInterval(function() {
var rand1 = Math.floor(Math.random() * 10) + 1;
var rand2 = Math.floor(Math.random() * 10) + 1;
processRandoms(rand1, rand2);
}, 5000);
You can then stop the recurring interval at any time with this:
clearInterval(interval);

Categories

Resources