issues with this program - javascript

I came across this program from a You Don't Know JS books book on github:
const SPENDING_THRESHOLD = 200;
const TAX_RATE = 0.08;
const PHONE_PRICE = 99.99;
const ACCESSORY_PRICE = 9.99;
var bank_balance = 303.91;
var amount = 0;
function calculateTax(amount) {
return amount * TAX_RATE;
}
function formatAmount(amount) {
return "$" + amount.toFixed( 2 );
}
// keep buying phones while you still have money
while (amount < bank_balance) {
// buy a new phone!
amount = amount + PHONE_PRICE;
// can we afford the accessory?
if (amount < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
}
// don't forget to pay the government, too
amount = amount + calculateTax( amount );
console.log(
"Your purchase: " + formatAmount( amount )
);
// Your purchase: $334.76
// can you actually afford this purchase?
if (amount > bank_balance) {
console.log(
"You can't afford this purchase. :("
);
}
// You can't afford this purchase. :(
My issue is that it does not matter if I change the value of bank_balance to a higher value, but it keeps printing : You can't afford this purchase.
I have try to make it so it does not print : You can't afford this purchase.
I can't make it work. I'm starting to think that the program is wrong, but I think is just me.
I know the solution is simple but I cant see it nor find it.

It comes from your while(amount < bank_balance). You increase amount until it's bigger than bank_balance. So obviously, it's bigger than bank_balance after that.
Also, you can use the developer tools available in every modern browser (F12 for Chrome or Firefox will open them), where you can put break points and follow your code's flow.

I don't know what the program is meant to do but it doesn't seem to make much sense to me.
It "buys" phones as long as you have money, but doesn't check if you have enough money for an additional phone.
So in the end of the while loop you have spend exactly your whole money on phones or (much more likely) spend more money than you have.
On top of this there are accessorizes and taxes. So in the end, you won't ever be able to afford your purchase.
And no matter how high you raise you balance, the program is written to exceed it.
The programm would work probably better with the line
while (amount + PHONE_PRICE + calculateTax(amount + PHONE_PRICE) <= bank_balance)
or even
while (amount + PHONE_PRICE + ACCESSORY_PRICE + calculateTax(amount + PHONE_PRICE + ACCESSORY_PRICE)<= bank_balance)
Although I have to admit that I'm not sure what the purpose of the SPENDING_THRESHOLD is.

You keep adding new phones and accessories until it reaches the total amount. I guess total cost becomes very close to the amount hence when you add the tax on top of that it crosses the limit and you see that message. I would suggest you to compare(in the while loop) the phone price along with the tax. Something like:
while (amount + PHONE_PRICE + calculateTax( PHONE_PRICE ) < bank_balance) {
// buy a new phone!
amount = amount + PHONE_PRICE + calculateTax( PHONE_PRICE );
// can we afford the accessory?
if (amount < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
}
Refer https://jsfiddle.net/Lxwscbbq/
Open the browser console to see the messages.

Program is not wrong it is simple:
var bank_balance = 303.91;
which is global. Suppose you provided
amount = 200;
amount = amount + calculateTax( amount );
amount = 200 + calculateTax(200);
if you check condition and you can see amount is grater than entered amount. Thats why you are getting "You can't afford purchase"
if (amount > bank_balance) {
console.log(
"You can't afford this purchase. :("
);
}

Related

Making a high score (best time) localStorage in JavaScript

I'm having a little bit of trouble wrapping my head around using a localStorage for a high score. I have saved the variable for the high score but now getting it to refresh with a new high score has become the issue.
So I have reverted back to the start and I have just these lines:
localStorage.setItem('score', timeDiff.toFixed(3));
parseFloat(document.getElementById("best_score").innerHTML = "My best time is " + localStorage.getItem('score') + " s");
My plan is then, if that user scores a better time than all their other attempts, this is saved as their best time.
I realise I need to do an "if" statement. So, the best I can come up with at the moment is human speak not JavaScript.
If score is nothing, then just print the new score.
If the score is better than the current printed score, then print that one instead.
If the score isn't as good as the current score, then don't do anything at all.
And that is it!
Be grateful for anyone to push me in the right direction of how to write those if statements.
There's no reason for the parseFloat in your example, but you will probably want parseFloat as part of this solution.
The update would look something like this:
// Get the previous high score if any, or `NaN` if none
// `localStorage.score` will be `undefined` if you've never stored a high score
// at all (or a string otherwise). `parseFloat` will return `NaN` if you pass it
// `undefined`, so we check that later.
const lastHighScore = parseFloat(localStorage.score);
// Get the string version of this score
const scoreString = timeDiff.toFixed(3);
let message;
if (isNaN(lastHighScore) || timeDiff > lastHighScore) { // ** Perhaps < ? Hard to tell from the question
// New high score
message = "Your new best time is " + scoreString;
// Store the new score
localStorage.score = scoreString;
} else {
// Not a new high score
message = "Your time was " + scoreString + "; your best time was " + localStorage.score;
}
document.getElementById("best_score").textContent = message;
Given the starting point seems to have a value in timeDiff, I couldn't see how a score could be "nothing."
(If you want to use getItem() and setItem() instead, note that getItem() will return null [not undefined] if the item doesn't exist. But parseFloat(null) also gives you NaN, so...)
Okay, based on what you wrote in the comment, your problem is not actually the if statements, but how to structure it so it gets updated properly.
The answer to this is creating a function that does all of this for you.
Let's call it updateHighscore.
This function will take a new score, then see if it's a high score and if it is, update everything accordingly.
Whenever a game is finished now, you just call this method.
E.g. See the following:
function updateHighscore(newScore) {
// get current highscore
const oldHighscore = parseFloat(localStorage.getItem('score'))
if (oldHighscore == null // if it doesn't exist yet
|| oldHighscore < newScore) { // or if it's smaller than the new score (I assume bigger means better here)
// current highscore needs to be updated
localStorage.setItem('score', newScore)
// html needs to be updated
document.getElementById("best_score").innerHTML = "My best time is " + localStorage.getItem('score') + " s"
}
}
Now, whenever the game is finished and you have a new score, just call this method with the score and it should update everything accordingly.
You have to write it like this when user gets a new highscore:
localStorage.setItem('score', timeDiff.toFixed(3));
document.getElementById("best_score").innerHTML = "My best time is " + parseFloat(localStorage.getItem('score')) + " s";
to check the highscore, do like this:
var highScore = parseFloat(localStorage.getItem('score'));
highScore = highScore > currentScore ? highScore : currentScore;
localStorage.setItem('score', highScore);

Wrong results calculating EMA (exponential moving average) using Javascript, Nodejs

I'm trying to calculate the EMA with this script.
But it does not give me the correct EMA.
This could be of many reasons, but i'm not sure what it is.
I've tried different formulas for the EMA without any better results, I'm really not a professional coder nor mathematician and thus i can't see what I'm doing wrong.
How Is the EMA value calculated over time? For the first value I calculate the first EMA using the SMA, i guess that should work - right?
My EMA value = 0.033144798412698406
Real EMA value = 0.033084
Close = last closing price
Period = 20;
Multiplier = (2 / (period + 1));
function calculateEMA() {
if (EMA == 0) {
EMA = (Close - SMA) * multiplier + SMA;
calculateEMA();
} else {
for (a = 0; a < period; a++) {
EMA = (Close - previous_ema) * multiplier + previous_ema;
console.log(EMA + " ema");
previous_ema = EMA;
}
}
}
// UPDATE Added my whole script (which can be runned)- https://pastebin.com/91GEuATM
You need Nodejs and the binance node api installed (npm install node-binance-api --save) ; Keep in mind that this is just my "test script" hence all the weird variable names etc.
//UPDATE 2 Ticks sample data https://pastebin.com/AFzf7GwQ

Var won't exceed billion

EDIT
I tested something out, and apparently, this:
if(info.max.value == "") {maxdesiredvalue = 999999999999999999999}
Returns in the chrome console:
> maxdesiredvalue
< 999999999
So I believe the problem really comes from there... is there a maximum number of digits we can attribute to a variable?
I'm into javascript for a few months now, and I've made a program that generates random weapons for a tabletop rpg.
Every weapon generated has a price relative to it's attributes. My problem today is that this price won't exceed 9 digits (cannot reach billion), even though it can.
In my generator, it is possible to choose certain properties before generating the weapon. If I intentionally try to generate something worth over a billion gold, it will crash instantly. On the other hand, if there is any way the weapon can be generated without exceeding the billion, it will do so.
For example, the most expansive metal is the "Residuum". The only 2 weapons that can be generated in Residuum are the dart and the shuriken, since they only use 1/16 of an Ingot. Therefore if I set the metal to be Residuum, they will be the only 2 possible generated weapons. From this point, if I try to specify I want a Residuum Sword, it will simply crash as explained earlier.
In my generation options, I also have a text input for the user to choose a minimum value and/or a maximum value for the weapon. I set the default max value to Infinity, so it should'nt be a problem.
function desiredvalue(){
if(info.max.value == "") {maxdesiredvalue = Infinity}
else {maxdesiredvalue = parseInt(info.max.value)}
if(info.min.value == "") {mindesiredvalue = 0}
else {mindesiredvalue = parseInt(info.min.value)}
}
In my html:
Min price: <input type="text" name="min" value="" onchange="desiredvalue()">
Max price: <input type="text" name="max" value="" onchange="desiredvalue()">
I already tried to deactivate this function to see if it was the problem, but even without a specific max value, weapons still won't be generated if their value exceeds 9 digits.
Maybe the problem sets inside the value formula, so here it is, even though it might not be a big help since it is all made up from variables.
WeapValue = ((((IngotValue * Ingots) + CraftTime + (actualEnchantTime * 3) + (LS * 0.02) + (R * 0.05) + BS + (FTH * 0.03)) * (((BPArace + BPAstatus + BPAlevel + ((BPAcrit1 + 1) * BPAcrit2)) / 100) + 1)) + PAenchant + PAaugment1 + PAaugment2 + PAaugment3)
Also the value is modified afterwards to fit in gold, silver or copper...
WeapValue.toLocaleString('en-US', {minimumFractionDigits: 0});
WeapValue = WeapValue.toFixed(2);
if (WeapValue >= 2) {WeapValue2 = Math.ceil(WeapValue); goldtype = " GP"}
else if (WeapValue < 2 && WeapValue >= 1) {WeapValue2 = WeapValue * 10; goldtype = " SP"}
else if (WeapValue < 1 && WeapValue >= 0) {WeapValue2 = WeapValue * 100; goldtype = " CP"}
Nothing else in the script really change the value, and all the variables affecting it are defined earlier, and I don't really think they are the problem, since they actually seem to work (they simply make the price exceed 9 digits).
If you have any questions related to the script, I'm here to answer, but I can't put the full script since it is very, very long (2543 lines)...
If anyone has an idea of how I can deal with my problem, it would be so appreciated! Again, I'm not a javascript expert, but I did my best and looked a lot on the Internet for help, but I still can't get rid of this problem...
Thank you!

Javascript: How do you enter in unknown variables?

I'm making a game where the player can pick 3 different characters. However I am running into a glaring problem, that being, when I create a function (like a attack function), it is linked to only 1 specific character.
I would rather have my code be written where when the person picks their character, all can use the same attack skill without me having to write 3 different ones. Also, the attack skills are linked to a button, so it must be diverse.
I can't have a designated attack button for X player. So how do I make my code so it can add all characters instead of just 1 specified character?
Example: Looking at my function below for the strike attack. I can set it to dwarf & angel which is fine. However what if the player picks a ELF character instead? Then the function will not work because it believes the character is a dwarf, fighting a angel. How can I fix this?
New=Object.create;
actor = {
primaryStats: function (level, hp, hpcap, balance, balancecap, exp){
this.level = level;
this.hp = hp;
this.hpcap = hpcap;
this.balance = balance;
this.balancecap = balancecap;
this.exp = exp;
},
player = New (actor),
monster = New (actor),
dwarf = New(player),
human = New(player),
elf = New(player),
angel = New(monster),
demon = New(monster),
dragon = New(monster);
//ATTACK SKILL ONE
dom.el("strike").onclick = function strike() {
playerHitCalc(dwarf, angel);
};
playerHitCalc = function(character, boss){
roll = Math.floor(Math.random() * character.accuracy + 1);
if (roll > boss.agility){
var hit = true;
}
else {
hit = false;
logMessage(boss.ID + " " + "has evaded your attack!")
}
playerDamCalc = function(){
if (hit == true){ //If you score a successful hit
var damage = Math.floor(Math.random() * character.strength + 1);
var totalDamage = damage - boss.armor; // Subtract Damage from Bosses Armor
if(totalDamage <= 0)totalDamage += boss.armor; // Add boss armor to prevent Negative Numbers
boss.hp -= totalDamage; // Subtract bosses HP from damage.
character.exp += totalDamage * 0.25; // Gain 1 exp point per 4 damage done
dom.setText("bosshealthcounter", boss.hp) // Update Bosses Health
logMessage("You hit " + boss.ID + " for " + totalDamage + " damage!");
}
You can use data attributes to link a dom element to particular characters. For example -
<button class="attack-btn" data-attacker="dwarf" data-target="angel">Attack</button>
Then in the on click handler, you can extract that particular element's attributes attacker and target instead of hardcoding the values.
Hope that helps!
One thing you are doing is creating Player and Monster from Actor and then specific player class from Player and the same for monster.
Problem lies in that now you have a specific handle for each type of player and each type of monster.
If we would want to edit current code, you would have to add currentPlayer and currentMonster variables that you would make equal to the Player and Monster you want to fight. Then you could avoid referencing specific player and specific monster and just use
playerHitCalc(currentPlayer, currentMonster);
But I would suggest changing things a little bit and create objects in a little different way.

Car loan calculator in Javascript displays nothing

I hope someone can help with this:
I am currently working on a motor dealership website. On this website is a car loan calculator that calculates your monthly repayments. I have successfully created a basic calculator that calculates the correct amount.
The client isn't happy with that. They want a more advanced calculator that calculates the monthly repayments with balloon considerations and a deposit and initiation and admin fees.
I altered the code to reflect that, but now the thing won't work anymore. I can't find any error in my code.
Here's the Javascript that's supposed to do the calculation:
function calculate() {
// Get the user's input from the form. Assume it is all valid.
// Convert interest from a percentage to a decimal, and convert from
// an annual rate to a monthly rate. Convert payment period in years
// to the number of monthly payments.
var principal = document.loandata.principal.value;
var lessDeposit = document.loandata.deposit.value;
var adminFee = document.loandata.admin.value;
var initiationFee = document.loandata.initiation.value;
var interest = document.loandata.interest.value / 100 / 12;
var payments = document.loandata.years.value * 12;
var balloonPercent = document.loandata.balloon.value / 100;
// Now compute the monthly payment figure, using esoteric math.
var balloonFinal = (principal * balloonPercent);
var totalPrincipal = (principal + initiationFee + balloonfinal - lessDeposit);
var x = Math.pow(1 + interest, payments);
var monthly = (totalPrincipal*x*interest)/(x-1);
// Check that the result is a finite number. If so, display the results
if (!isNaN(monthly) &&
(monthly != Number.POSITIVE_INFINITY) &&
(monthly != Number.NEGATIVE_INFINITY)) {
document.loandata.payment.value = round(monthly + adminFee);
document.loandata.total.value = round(monthly * payments);
document.loandata.totalinterest.value =
round((monthly * payments) - principal);
}
// Otherwise, the user's input was probably invalid, so don't
// display anything.
else {
document.loandata.payment.value = "";
document.loandata.total.value = "";
document.loandata.totalinterest.value = "";
}
}
// This simple method rounds a number to two decimal places.
function round(x) {
return Math.round(x*100)/100;
}
Also, if possible, there needs to be some validation. Like purchase price, interest rate and payment period are required fields. But the rest are not. So if someone fills in the required fields but not the rest, the calculator still needs to work, but if someone does NOT complete one of the required fields, they need to be prompted to do so.
For those who don't know what a balloon payment is, here's an example;
Purchase Price is R117 000
You decide on a balloon payment of 30%. On the initial purchase price, the 30% amounts to R35 100. This amount is then subtracted from your initial purchase price so that means your purchase is now R81 900. After that comes the deposit, which is subtracted, and the extras and the admin and initiation fees. So the monthly repayments are calculated using this new purchase price of R81 900 + extras - deposit (if any). For interest sake, after your contract ends, you have to pay the balloon amount in full or re-finance the vehicle.
PS: I'm a complete newbie when it comes to JavaScript. So any help would be greatly appreciated.
If the result is nothing, one of these three conditions is likely triggering the else statement:
if (!isNaN(monthly) &&
(monthly != Number.POSITIVE_INFINITY) &&
(monthly != Number.NEGATIVE_INFINITY)) {
You have a typo in the JS, you need to change balloonfinal to be balloonFinal with a capital F in the var totalPrincipal = line of code.
The principal, lessDeposit, adminFee, initiationFee may also need to be typecast as an integer/float.

Categories

Resources