Conditional If Statement with change in method - javascript

I have this function that is supposed to loop through these additional functions while they won't take the totals up past 100. However, the iteration stops and I need it to finish up with the hunger and danger value either being 100 or 0 depending on which. The numbers that pass through are first: (50,50) second: (0, 100). I can't seem to figure out how to change the addition/subtractions amount when the if condition is no longer met. My consoles are all displaying the last iteration before going over the conditional values.
The problem is:
Create a function called frodo. frodo will take in two parameters:
startingHungerValue (Number) and startingDangerValue (Number).
frodo will need to store those values on internal variables.
frodo will then return an object with two methods:
The first method will be called dinnerOverFire.
dinnerOverFire will decrease hunger by 25 and will increase danger by 40.
The second method will be called hidingInBush.
hidingInBush will increase hunger by 35 and decrease danger by 20.
Both methods need to return an object structured like this:
{
hunger: (modified hunger value),
danger: (modified danger value)
}
NOTE: Neither hunger nor danger should be able to exceed 100 or drop below 0.
function frodo(startingHungerValue, startingDangerValue) {
var shv = startingHungerValue;
var sdv = startingDangerValue;
console.log('startingHungerValue:', shv, 'startingDANGERvalue:', sdv)
return {
dinnerOverFire: () => {
if ((shv >= 0 && shv < 101) && (sdv >= 0 && sdv < 101)) {
return {
hunger: shv - 25,
danger: sdv + 40
}
}
},
hidingInBush: () => {
if ((shv >= 0 && shv < 101) && (sdv >= 0 && sdv < 101)) {
return {
hunger: shv + 35,
danger: sdv - 20
}
}
}
}
}

Not directly what you asked for, but I have a feeling you want to do something like below. It creates a class Frodo that you can call methods on like eat or hide.
You can see it in action here: jsfiddle
function Frodo(startingHungerValue, startingDangerValue) {
var self = this; //this could change per scope, self keeps a reference to the basic of the class
//store levels
self.hunger = startingHungerValue;
self.danger = startingDangerValue;
//show levels method
self.showLevels = function(){
console.log('My hungerlevel: '+ self.hunger);
console.log('My dangerlevel: '+ self.danger);
console.log('------');
}
//dinner method
self.dinnerOverFire = function() {
var newHunger = self.hunger - 25;
var newDanger = self.danger + 40;
if (newHunger<0) {
newHunger = 0; //no negatives
}
if (self.hunger==0) {
console.log('I\'m not hungry! No dinner!');
console.log('------');
return;
}
if (newDanger>100) {
console.log('Eating now would kill me! No dinner!');
console.log('------');
return;
}
self.hunger = newHunger;
self.danger = newDanger;
console.log('Thanks for dinner!');
self.showLevels();
}
//hiding method
self.hideInBush = function() {
var newHunger = self.hunger + 35;
var newDanger = self.danger - 20;
if (newDanger<0) {
newDanger = 0; //no negatives
}
if (newHunger>100) {
console.log('Hiding now would kill me! No hiding!');
console.log('------');
return;
}
if (self.danger==0) {
console.log('I\'m not scared at all! No hiding!');
console.log('------');
return;
}
self.hunger = newHunger;
self.danger = newDanger;
console.log('Thanks, I feel safer already!');
self.showLevels();
}
//initial message
console.log('Hi, i\'m frodo!');
self.showLevels();
}
//run your frodo
var frodo = new Frodo(50,50);
frodo.dinnerOverFire();
frodo.hideInBush();
frodo.dinnerOverFire();
frodo.hideInBush();
frodo.dinnerOverFire();
frodo.hideInBush();
frodo.dinnerOverFire();
This would output:
Hi, i'm frodo!
My hungerlevel: 50
My dangerlevel: 50
------
Thanks for dinner!
My hungerlevel: 25
My dangerlevel: 90
------
Thanks, I feel safer already!
My hungerlevel: 60
My dangerlevel: 70
------
Eating now would kill me! No dinner!
------
Thanks, I feel safer already!
My hungerlevel: 95
My dangerlevel: 50
------
Thanks for dinner!
My hungerlevel: 70
My dangerlevel: 90
------
Hiding now would kill me! No hiding!
------
Eating now would kill me! No dinner!
------
Which already shows a problem with the current way. At the end he's to scared to eat and to hungry to hide.

Do you mean, adding an else block to the if condition?
function frodo(startingHungerValue, startingDangerValue) {
var shv = startingHungerValue;
var sdv = startingDangerValue;
console.log('startingHungerValue:', shv, 'startingDANGERvalue:', sdv)
return {
dinnerOverFire: () => {
if ((shv === 50 && shv === 50)){
return {
hunger: shv - 50,
danger: sdv + 50
}
}
else if ((shv >= 0 && shv < 101) && (sdv >= 0 && sdv < 101)) {
return {
hunger: shv + 100,
danger: sdv - 100
}
}
},
hidingInBush: () => {
if ((shv === 50 && shv === 50)){
return {
hunger: shv - 50,
danger: sdv + 50
}
}
else if ((shv >= 0 && shv < 101) && (sdv >= 0 && sdv < 101)) {
return {
hunger: shv + 100,
danger: sdv - 100
}
}
}
}
}
console.log(frodo(50, 50).dinnerOverFire()); // 0,100
console.log(frodo(0, 100).dinnerOverFire()); // 100,0
.as-console {
height: 100%;
}
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}

Related

If and if-else statement in Angular project

How do I write a if and if-else statement in Angular project? It's only the "else" that is returning, even though the initial conditions are true.
export class HomeComponent implements OnInit {
productWorth: number;
unit: number;
pricePerProduct:any = this.changepricePerProduct();
result: number;
constructor() {}
ngOnInit() {}
changepricePerProduct() {
if (this.productWorth >= 200 && (this.productWorth) <= 2000) {
return 150;
} else if (this.productWorth >= 2001 && (this.productWorth) <= 5000) {
return 450
} else if (this.productWorth >= 5001 && (this.productWorth) <= 10000) {
return 900
} else if (this.productWorth >= 10001 && (this.productWorth) <= 20000) {
return 1200
} else if (this.productWorth >= 20000) {
return 1500
} else {
return 0
}
}
multiply() {
this.result = this.pricePerProduct * this.unit;
}
}
Your code doesn't show any kind of change of the productWorth field. Hence we can just assume, that it keeps being undefined, which will always result into 0.
Please don't mind me giving you a recommendation along. Remove this horror if-else construct. Instead you can do this:
// must be sorted
var myPriceTable = {
200: 150,
2001: 450,
5001: 900,
10001: 1200,
20001: 1500
}
function changepricePerProduct(productWorth) {
if (typeof productWorth !== 'number') return 0;
var floorKey = Object.keys(myPriceTable).findLast(key => key < productWorth);
return floorKey ? myPriceTable[floorKey] : 0;
}
console.log(changepricePerProduct(undefined));
console.log(changepricePerProduct(5));
console.log(changepricePerProduct(222));
console.log(changepricePerProduct(5555));
console.log(changepricePerProduct(22222));
changepricePerProduct() {
return this.productWorth >= 200 && (this.productWorth) <= 2000 ? 150 :
(this.productWorth >= 2001 && (this.productWorth) <= 5000)?450:
(this.productWorth >= 5001 && (this.productWorth) <= 10000)?900:
(this.productWorth >= 10001 && (this.productWorth) <= 20000)?1200:
(this.productWorth >= 20000)?1500:0 }

How can i solve the Counting Cards exercice of freecodecamp with my code?

problem statement is here: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/counting-cards
the problem comes when i tried to get 0 Hold in the return by the Cards Sequence 7, 8, 9 ,but i can't. I know that there are better options for solving this problem, but i wanna do it this way, someone can help?
function cc(card) {
// Only change code below this line
if (card = ( 2 || 3 || 4 || 5 || 6 )) {
count += 1;
}
else if (card = ( 7 || 8 || 9 )) {
count += 0;
}
else if (card = ( 10 || "J" || "Q"|| "K" || "A" )) {
count -= 1;
}
if (count <= 0) {
return count + " Hold";
}
else if (count > 0) {
return count + " Bet";
}
// Only change code above this line
}
cc(2); cc(3); cc(7); cc('K'); cc('A');```
Keeping the same gist of your function:
function cc(card) {
if ("23456".indexOf(card) >= 0) count++;
if ("10JQKA".indexOf(card) >= 0) count--;
return count + (count <= 0 ? " Hold" : " Bet");
}

Array is not assigning to the first occurrence but completes task for all other rows. "Exception" error

I am getting the following error for a specific task I am trying to accomplish:
Exception: The parameters (null,number) don't match the method signature for SpreadsheetApp.Sheet.getRange.
at printAppleCount(Code:84:19)
at assignNumbers(Code:24:9)
function onInstall(e) {
onOpen(e);
}
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Invite Automation')
.addItem('Assign Numbers to Zeroes (Max. 50)', 'assignNumbers')
.addToUi();
}
function assignNumbers() {
const sheet = SpreadsheetApp.getActiveSheet();
var colC = sheet.getRange("C:C");
var colCValues = colC.getValues();
var appleCount = 0; // to store the apple count
var appleLineAddress = []; // to store the row-no of Apple 0's
// get the total count and and its row-no
for (let i = 0; i < colCValues.length; i++) {
if (colCValues[i][0] == "") continue;
if (colCValues[i][0] == 'Apple 0') { // Target only "Apple 0" -- not "Apple 00" or "Apple 01" etc.
appleCount++; //++
appleLineAddress.push(i+1);
}
}
// Check apple count and divide
if (appleCount < 50) {
printAppleCount(1, appleCount, appleLineAddress);
} else if (appleCount > 50 && appleCount <= 100) {
printAppleCount(2, appleCount, appleLineAddress);
} else if (appleCount > 100 && appleCount <= 150) {
printAppleCount(3, appleCount, appleLineAddress);
} else if (appleCount > 150 && appleCount <= 200) {
printAppleCount(4, appleCount, appleLineAddress);
} else if (appleCount > 200 && appleCount <= 250) {
printAppleCount(5, appleCount, appleLineAddress);
} else if (appleCount > 250 && appleCount <= 300) {
printAppleCount(6, appleCount, appleLineAddress);
} else if (appleCount > 300 && appleCount <= 350) {
printAppleCount(7, appleCount, appleLineAddress);
}
}
function printAppleCount(caseNo, appleCount, appleLineAddress) {
const sheet = SpreadsheetApp.getActiveSheet();
var splitInteger = function numParts(num, parts) {
var val;
var mod = num % parts;
if (mod == 0) {
val = num / parts;
retData = Array(parts).fill(val);
} else {
val = (num - mod) / parts;
retData = Array(parts).fill(val);
for (i = 0; i < mod; i++) {
retData[i] = retData[i] + 1;
}
retData.reverse()
//Comment the above line to unreverse the result.
}
return retData;
}
console.log("Case No: " + caseNo);
console.log("AppleCount : " + appleCount);
var equalSplits = splitInteger(appleCount, caseNo);
console.log(equalSplits);
// for the applecount: 113(suppose), the var equalSplits will log [37,38,38].
// You can print the data now with the equalSplits and appleLineAddress
var k = 0;
for (var i = 0; i < equalSplits.length; i++) {
for (var j = 0; j < equalSplits[i]; j++) {
console.log('Print Apple ' + (i + 1) + ' at ' + appleLineAddress[k++]);
sheet.getRange(appleLineAddress[k], 3).setValue('Apple ' + (i + 1));
}
}
}
What this does is assigns "1" "2" "3" etc. at a maximum of 50 per number when targeting a list and replace only "Apple 0" (replacing the 0 with the respect 1, 2 or 3, etc.)
Even more specifically, if there are more than 50 (so two batches if there are 75 "Apple 0") it splits them equally, assigning 37 "Apple 1" and 38 "Apple 2".
The issue comes when running the script. It does the correct actions but skips the first occurrence of "Apple 0" and does not consider assigning it a value in the loop.
Example table:
row
values
1
Orange
2
Orange
3
Apple 0
4
Orange
5
Apple 0
6
Apple 0
7
Apple 0
8
Apple 0
9
Apple 0
10
Apple 0
11
Apple 0
12
Apple 0
13
Apple 0
14
Apple 0
15
Orange
16
Apple 0
17
Apple 0
18
Apple 0
19
Apple 0
20
Apple 0
It ends up replacing "Apple 0" for only the 2nd occurrence of "Apple 0" (row 5) and beyond. But the first one (row 3) does not replace and is ignored even in the equal split calculation.
Note also that console log is logging "Print Apple 1 at 3" - so it's considering it. In the assigning/setting value process, it's not doing it.
This specifically started happening when I fixed another error by adding a +1 here:
appleLineAddress.push(i+1);
Thank you!
Issue:
You are using the increment operator k++ before setting the value, so the first occurrence (k=0) is getting skipped, and in the last iteration appleLineAddress[k] doesn't exist, the array not being that large.
Solution:
Increment k after setting the value.
Replace this:
console.log('Print Apple ' + (i + 1) + ' at ' + appleLineAddress[k++]);
sheet.getRange(appleLineAddress[k], 3).setValue('Apple ' + (i + 1));
With this:
sheet.getRange(appleLineAddress[k], 3).setValue('Apple ' + (i + 1));
console.log('Print Apple ' + (i + 1) + ' at ' + appleLineAddress[k++]);
Or this (I would not use the increment operator in console.log):
sheet.getRange(appleLineAddress[k], 3).setValue('Apple ' + (i + 1));
k++;
console.log('Print Apple ' + (i + 1) + ' at ' + appleLineAddress[k]);
Reference:
Increment (++)

How can I write this function without a bunch of if else statements?

I basically just can't figure this one out and don't want to hack it.
It will look so messy if I do this for 52 weeks in a year.
Any tips?
Update
This question is not about getting the year's current week.
This question is about getting weeks elapsed since a date defined.
I want the next week's workout to show up on 6th day of the current week ;)
Example
My days since start are 99: 2018-05-30 18:39:29.
Some of your examples are showing me on week 15.
My code however shows week 16, which is right. See the caveat?
calculateUsersCurrentWorkoutWeek: function(timestamp) {
let daysSinceSignup = moment().diff(timestamp, "days");
if (daysSinceSignup <= 6) {
return 1;
} else if (daysSinceSignup > 6 && daysSinceSignup <= 13) {
return 2;
} else if (daysSinceSignup > 13 && daysSinceSignup <= 20) {
return 3;
} else if (daysSinceSignup > 20 && daysSinceSignup <= 27) {
return 4;
} else if (daysSinceSignup > 27 && daysSinceSignup <= 34) {
return 5;
} else if (daysSinceSignup > 34 && daysSinceSignup <= 41) {
return 6;
} else if (daysSinceSignup > 41 && daysSinceSignup <= 48) {
return 7;
} else if (daysSinceSignup > 48 && daysSinceSignup <= 55) {
return 8;
} else if (daysSinceSignup > 55 && daysSinceSignup <= 62) {
return 9;
} else if (daysSinceSignup > 55 && daysSinceSignup <= 62) {
return 10;
} else if (daysSinceSignup > 62 && daysSinceSignup <= 69) {
return 11;
} else if (daysSinceSignup > 69 && daysSinceSignup <= 76) {
return 12;
} else if (daysSinceSignup > 76 && daysSinceSignup <= 83) {
return 13;
} else if (daysSinceSignup > 83 && daysSinceSignup <= 90) {
return 14;
} else if (daysSinceSignup > 90 && daysSinceSignup <= 97) {
return 15;
} else {
return 16;
}
}
Divide by 7 and ceil?
const daysSinceSignup = moment().diff(timestamp, "days");
return Math.ceil(daysSinceSignup / 7);
Did you miss out on coffee this morning? ;-)
Note: The function above will tell you "the number of the week since timestamp" which is what I understand from your text, but your code sample does not reflect it.
To get the same result of your code sample, you'll need to .floor() and add 1 instead of .ceil():
const daysSinceSignup = moment().diff(timestamp, "days");
return Math.floor(daysSinceSignup / 7) + 1;
As #Michel said, divide by 7 and floor + 1
calculateUsersCurrentWorkoutWeek: function(timestamp) {
let daysSinceSignup = moment().diff(timestamp, "days");
return Math.floor(daysSinceSignup / 7) + 1;
}
What you are looking for is
return Math.ceil((daysSinceStartup + 1) / 7);
This will give the same results as your code for any real number between -1 and 62 (because around 62 you forgot to replace the copied ranges). It returns 1 for 6 days, and 2 for 6.01 days, just as the original code.
The easy way could also be to create a integer array in ascending order so that the values contain the upper limit of the comparison. Then for each values of daysSinceSignup you can find the index and add 1 to it since you require the return values as 1, 2, 3, ... and so on. This will be useful if you do not have uniform interval, like currently the interval is always 7 so the division and ceil approach could also work but if the interval is not uniform then this approach could be really useful.
var indexArray = [6,13,20,27,34,41,48,55,62,69,76,83,90,97];
function calculateUsersCurrentWorkoutWeek() {
let daysSinceSignup = 14;
var elemIndex = indexArray.findIndex((item)=> item > daysSinceSignup);
return elemIndex+1;
}
console.log(calculateUsersCurrentWorkoutWeek());
You can put your datas in array and use array.find:
var datas = [
{ min: -Infinity, max: 6, ret: 1 },
{ min: 6, max: 13, ret: 2 },
{ min: 13, max: 20, ret: 3 },
{ min: 20, max: 27, ret: 4 }
];
function calculateUsersCurrentWorkoutWeek(daysSinceSignup) {
return datas.find(({min, max}) =>
daysSinceSignup > min && daysSinceSignup <= max
).ret;
}
console.log(calculateUsersCurrentWorkoutWeek(5));
console.log(calculateUsersCurrentWorkoutWeek(7));
console.log(calculateUsersCurrentWorkoutWeek(14));

How to format numbers similar to Stack Overflow reputation format

I want to convert a number into a string representation with a format similar to Stack Overflow reputation display.
e.g.
999 == '999'
1000 == '1,000'
9999 == '9,999'
10000 == '10k'
10100 == '10.1k'
Another approach that produces exactly the desired output:
function getRepString (rep) {
rep = rep+''; // coerce to string
if (rep < 1000) {
return rep; // return the same number
}
if (rep < 10000) { // place a comma between
return rep.charAt(0) + ',' + rep.substring(1);
}
// divide and format
return (rep/1000).toFixed(rep % 1000 != 0)+'k';
}
Check the output results here.
UPDATE:
CMS got the check and provides a superior answer. Send any more votes his way.
// formats a number similar to the way stack exchange sites
// format reputation. e.g.
// for numbers< 10000 the output is '9,999'
// for numbers > 10000 the output is '10k' with one decimal place when needed
function getRepString(rep)
{
var repString;
if (rep < 1000)
{
repString = rep;
}
else if (rep < 10000)
{
// removed my rube goldberg contraption and lifted
// CMS version of this segment
repString = rep.charAt(0) + ',' + rep.substring(1);
}
else
{
repString = (Math.round((rep / 1000) * 10) / 10) + "k"
}
return repString.toString();
}
Output:
getRepString(999) == '999'
getRepString(1000) == '1,000'
getRepString(9999) == '9,999'
getRepString(10000) == '10k'
getRepString(10100) == '10.1k'
Here is a function in PHP which is part of iZend - http://www.izend.org/en/manual/library/countformat:
function count_format($n, $point='.', $sep=',') {
if ($n < 0) {
return 0;
}
if ($n < 10000) {
return number_format($n, 0, $point, $sep);
}
$d = $n < 1000000 ? 1000 : 1000000;
$f = round($n / $d, 1);
return number_format($f, $f - intval($f) ? 1 : 0, $point, $sep) . ($d == 1000 ? 'k' : 'M');
}
Here is CMS's version in PHP (in case someone needed it, like I did):
function getRepString($rep) {
$rep = intval($rep);
if ($rep < 1000) {
return (string)$rep;
}
if ($rep < 10000) {
return number_format($rep);
}
return number_format(($rep / 1000), ($rep % 1000 != 0)) . 'k';
}
// TEST
var_dump(getRepString(999));
var_dump(getRepString(1000));
var_dump(getRepString(9999));
var_dump(getRepString(10000));
var_dump(getRepString(10100));
Output:
string(3) "999"
string(5) "1,000"
string(5) "9,999"
string(3) "10k"
string(5) "10.1k"
Handlebars.registerHelper("classNameHere",function(rep) {
var repString;
if (rep < 1000)
{
repString = rep;
}
else if (rep < 10000)
{
rep = String(rep);
r = rep.charAt(0);
s = rep.substring(1);
repString = r + ',' + s;
}
else
{
repDecimal = Math.round(rep / 100) / 10;
repString = repDecimal + "k";
}
return repString.toString();
});
divide by 1000 then if result is greater than 1 round the number and concantenate a "k" on the end.
If the result is less than 1 just output the actual result!
// Shortens a number and attaches K, M, B, etc. accordingly
function number_shorten($number, $precision = 3, $divisors = null) {
// Setup default $divisors if not provided
if (!isset($divisors)) {
$divisors = array(
pow(1000, 0) => '', // 1000^0 == 1
pow(1000, 1) => 'K', // Thousand
pow(1000, 2) => 'M', // Million
pow(1000, 3) => 'B', // Billion
pow(1000, 4) => 'T', // Trillion
pow(1000, 5) => 'Qa', // Quadrillion
pow(1000, 6) => 'Qi', // Quintillion
);
}
// Loop through each $divisor and find the
// lowest amount that matches
foreach ($divisors as $divisor => $shorthand) {
if (abs($number) < ($divisor * 1000)) {
// We found a match!
break;
}
}
// We found our match, or there were no matches.
// Either way, use the last defined value for $divisor.
return number_format($number / $divisor, $precision) . $shorthand;
}
This worked for me. I hope, this will help you. Thanks for asking this question.
I created an npm (and bower) module to do this:
npm install --save approximate-number
Usage:
var approx = require('approximate-number');
approx(123456); // "123k"

Categories