If / else in a javascript function - javascript

I'm trying to write an if/else function for a simple game but I'm new to coding.
Chapters = 0;
Books = 0;
Pens = 1;
WarehouseRoom = 50;
function ChaptersUp(number) {
if (Pens > 0) {
if ((Chapters + number) <= 9) {
Chapters = Chapters + number;
document.getElementById("Chapters").innerHTML = Chapters;
}
else {
ChaptersOver = (Chapters + number - 10);
if (Books < WarehouseRoom) {
if (ChaptersOver <= 9) {
Books = Books + 1;
Chapters = ChaptersOver;
document.getElementById("Chapters").innerHTML = Chapters;
document.getElementById("Books").innerHTML = Books;
}
else {
BooksOver = Math.floor(ChaptersOver / 10);
Books = Books + BooksOver + 1;
Chapters = (ChaptersOver - (BooksOver * 10));
document.getElementById("Chapters").innerHTML = Chapters;
document.getElementById("Books").innerHTML = Books;
}
}
}
}
}`
I want the function to run up to the point where the Warehouse is full. Currently, if I add 11 Books (110 Chapters) at a time, the function will stop operating at 55 books, but I've already went over the limit.
Question : How can I make it stop at exactly the amount equal to WarehouseRoom?

You should try a for statment.
for(int i = 1; i > warehouseFull; i++)
{
}
i is used to for the repeat and the loop will repeat till it is equal to warehouseFull. The i++ on the end is there so that once the loop is done it adds 1 to i. You could do the same backwards if you lose x amount of books. also you don't have to declare i inside the for statesmen but if you are going to use many for statement then it will make it easier so you don't have to switch letters or declare i = 0;.

Related

Optimizing updating many elements continuously with react

This is my first time working with react, and i tried to create an animated background. I did this by creating a large amount of divs, and updating their position every time a timer ticks.
moveCircles() {
let tempCircles = this.state.bgCircles;
for (let i = 0; i < amount; i++) {
tempCircles[i].left = this.state.bgCircles[i].left + Math.cos(this.state.bgCircles[i].angle) * 2;
tempCircles[i].top = this.state.bgCircles[i].top + Math.sin(this.state.bgCircles[i].angle) * 2;
if (tempCircles[i].top < (0 - tempCircles[i].radius)) {
tempCircles[i].top = totalHeight;
} else if(tempCircles[i].top > totalHeight) {
tempCircles[i].top = 0 - tempCircles[i].radius
}
if (tempCircles[i].left < (0 - tempCircles[i].radius)) {
tempCircles[i].left = totalWidth;
} else if (tempCircles[i].left > totalWidth) {
tempCircles[i].left = 0 - tempCircles[i].radius;
}
}
this.setState({
bgCircles: tempCircles,
initialized: true
});
}
However, this is (unsurprisingly) not very optimized, and can get a bit laggy.
My latest try looks like this: https://codepen.io/Miasha/pen/XWqZVeV
Is there a more optimized way of achieving this?

Translating C++ program to JavaScript/asm.js does not produce the same sequence of numbers

I took the mother of all random number generators from Agner Fog's library and attempted to make a JavaScript version of this. I expect the bit pattern to be identical but this doesn't seem to be the case and I wonder why or if I made a mistake?
The C++ code I use can be found here. It's from Agner Fog's website.
Here's my TypeScript version of this code
const u = (function () {
const b = new ArrayBuffer(8)
return {
u32: new Uint32Array(b),
u64: new BigUint64Array(b),
}
})()
export class Random {
state = new Uint32Array(5)
constructor(seed?: number) {
this.seed(seed ?? +new Date())
}
b() {
const { state: x } = this
u.u64[0] =
2111111111n * BigInt(x[3]) +
1492n * BigInt(x[2]) +
1776n * BigInt(x[1]) +
5115n * BigInt(x[0]) +
BigInt(x[4])
console.debug(u.u64[0])
x[3] = x[2]
x[2] = x[1]
x[1] = x[0]
x[4] = u.u32[1]
x[0] = u.u32[0]
return x[0]
}
next() {
return (1 / 4_294_967_296) * this.b()
}
seed(seed: number) {
const { state: x } = this
let s = seed >>> 0
// make random numbers and put them into the buffer
for (let i = 0; i < 5; i++) {
s = s * 29943829 - 1
x[i] = s
}
console.debug(x)
// randomize some more
for (let i = 0; i < 19; i++) {
this.b()
}
}
}
I managed to get it down to the the state initialization but I cannot understand why the output from the C++ program is 4294967295, 4265023466, 1627457073, 3925469700, 2226377299 but the TypeScript program is giving me 4294967295, 4265023466, 1627457073, 3925868544, 0. Only the first 3 numbers get computed exactly the same. Any help trying to understand this is much appreciated.
Ah, I figured it out. I have to use Math.imul to get correct results. Can't do C-like integer multiplication without it.
So, this:
for (let i = 0; i < 5; i++) {
s = s * 29943829 - 1
x[i] = s
}
...changes into:
for (let i = 0; i < 5; i++) {
s = Math.imul(s, 29943829) - 1
x[i] = s
}
I tried stuff like (s * 29943829) >>> 0 but this is not enough to force C style integer multiplication.

How to reduce number of computations during d3.js transition?

So right now, I'm trying to implement a search bar function into my d3.js plot. Right now it doesn't do anything, but that's not the issue at the moment. The problem is that when I type/delete something from the bar, there's visible lag/choppiness in the characters appearing/disappearing. I believe the issue is stemming from my plot. I have 140+ dots moving around the screen, and their position is being interpolated. So from the beginning to the end of the transition, my code has to compute 140 positions thousands of times over.
I've looked into trying to reduce the cardinality of the d3.interpolateNumber function, but it appears that there isn't a third argument to change the number of terms like in a linspace command. Right now I have an array of 1000 numbers for my function to run through, but I don't know how to pass the array to my other functions.
Below are the pertinent functions for this issue. The commented line in tweenPatch is the original code I had that made my code run, but gave my plot computational issues. Variables arr, curr, and step were my attempt to fix the situation, but I haven't been able to figure out how to pass the array into displayPatch().
function tweenPatch() {
var patch = d3.interpolateNumber(1, 26);
var arr = [];
var curr = 1;
var step = (26 - 1) / (1000 - 1);
for (var i = 0; i < 1000; i++) {
arr.push(curr + (step * i));
}
return arr.forEach(function(d) {
console.log(arr[d]);
displayPatch(arr[d]);
});
//return function(t) { displayPatch(t); };
}
function displayPatch(patch) {
dots.data(interpolateData(patch), function(d) { return d.name; }).call(position).sort(order);
var inter = Math.floor(patch);
var seas = 8;
var patc = 1;
if (inter > 24) {
seas = 9;
patc = inter - 24;
} else {
patc = inter;
}
label.text("Patch " + seas + "." + patc);
}
function interpolateValues(values, number) {
old = Math.floor(number);
upd = Math.ceil(number);
var old_data = values.filter(function(d) {return d.internal == old;});
var new_data = values.filter(function(d) {return d.internal == upd;});
var oobj = old_data[0];
var nobj = new_data[0];
var onum = oobj[Object.keys(oobj)[4]];
var nnum = nobj[Object.keys(nobj)[4]];
var difint = number - old;
var difdis = 0;
var newnum = nnum;
if (nnum > onum) {
difdis = nnum - onum;
newnum = ((difint) * difdis) + onum;
} else if (onum > nnum) {
difdis = onum - nnum;
newnum = onum - ((difint) * difdis);
}
return newnum;
}
I believe switching my SVG to a canvas may help things, but since I have no knowledge of canvas I'd rather leave that as a last resort.

Vue.js timing calculations are not matching plain JavaScript version

I'm trying to create a 'beats per minute' (BPM) calculator, identical (for now) to the one you can find here. But for some reason, when I use the BPM calculator at that link on a test song, it gets within 1 BPM of the actual value of 85.94 within of 7 keypresses and just gets more accurate from there, ending within 0.05 of the actual BPM, whereas with my (essentially identically-coded) Vue.js version, it starts much higher (182-->126-->110) and goes down from there, but even after 60 keypresses it's still off by ~2 BPM, and after a full song, it was still off by about 0.37 BPM.
Here's the code for the plain-JavaScript version at that link:
var count = 0;
var msecsFirst = 0;
var msecsPrevious = 0;
function ResetCount()
{
count = 0;
document.TAP_DISPLAY.T_AVG.value = "";
document.TAP_DISPLAY.T_TAP.value = "";
document.TAP_DISPLAY.T_RESET.blur();
}
function TapForBPM(e)
{
document.TAP_DISPLAY.T_WAIT.blur();
timeSeconds = new Date;
msecs = timeSeconds.getTime();
if ((msecs - msecsPrevious) > 1000 * document.TAP_DISPLAY.T_WAIT.value)
{
count = 0;
}
if (count == 0)
{
document.TAP_DISPLAY.T_AVG.value = "First Beat";
document.TAP_DISPLAY.T_TAP.value = "First Beat";
msecsFirst = msecs;
count = 1;
}
else
{
bpmAvg = 60000 * count / (msecs - msecsFirst);
document.TAP_DISPLAY.T_AVG.value = Math.round(bpmAvg * 100) / 100;
document.TAP_DISPLAY.T_WHOLE.value = Math.round(bpmAvg);
count++;
document.TAP_DISPLAY.T_TAP.value = count;
}
msecsPrevious = msecs;
return true;
}
document.onkeypress = TapForBPM;
// End -->
And here's my version:
computed: {
tappedOutBpm: function() {
let totalElapsedSeconds = (this.timeOfLastBpmKeypress - this.timeOfFirstBpmKeypress) / 1000.0
let bpm = (this.numberOfTapsForBpm / totalElapsedSeconds) * 60.0
return Math.round(100*bpm)/100;
},
},
methods: {
tapForBPM: function() {
let now = new Date;
now = now.getTime();
// let now = window.performance.now()
if (this.timeOfFirstBpmKeypress === 0 || now - this.timeOfLastBpmKeypress > 5000) {
this.timeOfFirstBpmKeypress = now
this.timeOfLastBpmKeypress = now
this.numberOfTapsForBpm = 1
} else {
this.timeOfLastBpmKeypress = now
this.numberOfTapsForBpm++
}
}
}
I figured it out by stepping through both of our code.
The problem was that I was setting the number of taps to 1 as soon as the user tapped the key the first time, when in reality it's not taps that I want to count, but beats, and the first beat requires not one tap, but two: the start and the end of that beat. So what I should do is rename the variable to numberOfTappedOutBeats and set it to 0 after the first tap rather than 1.

Angular.js doesn't start my function twice or something like this

I wrote a function that takes the number (amount) of songs, the object of songs and makes a new object, which includes new amount of songs chosen randomly.
The problem is that when I start it with number of 3, for example, it works correctly, but then I start this function with less number and it shows me the previous result with 3 songs instead of 2. If then I start it with number 5 I want to see 5 new song, but instead I get my previous 3 songs and 2 new. Why It doesn't choose randomly again?
$scope.getRandom = function(max) {
return Math.floor(Math.random() * (max + 1));
};
$scope.chooseSongs = function(hide) {
if (hide) {
$scope.hideDiv();
}
if ($scope.number > songs.length) {
$scope.number = songs.length;
}
while ($scope.newSongs.length < $scope.number) {
$scope.rand = $scope.getRandom(songs.length - 1);
$scope.songName = songs[$scope.rand].name;
if ($scope.newSongs.indexOf($scope.songName) == -1) {
$scope.newSongs.push($scope.songName);
}
}
$scope.number = 1;
};
When you use .push on an array, it does what it says: it "pushes" the new data in the back of the array, ignoring the fact if there already is data or not.
So you never clear your array, and keep "pushing" new data to the back.
An easy solution for this is adding $scope.newSongs = [] $scope.newSongs.length = 0; at the start of your function:
$scope.getRandom = function(max) {
return Math.floor(Math.random() * (max + 1));
};
$scope.chooseSongs = function(hide) {
$scope.newSongs.length = 0; //$scope.newSongs = [];
if (hide) {
$scope.hideDiv();
}
if ($scope.number > songs.length) {
$scope.number = songs.length;
}
while ($scope.newSongs.length < $scope.number) {
$scope.rand = $scope.getRandom(songs.length - 1);
$scope.songName = songs[$scope.rand].name;
if ($scope.newSongs.indexOf($scope.songName) == -1) {
$scope.newSongs.push($scope.songName);
}
}
$scope.number = 1;
};
Edit: Updated after an interesting comment from Deblaton Jean-Philippe. If you just reassign $scope.newSongs, AngularJs won't automatically update the view, if you instead clear the length, it will.

Categories

Resources