Welcome to my first post ever in Dev!
If you are also taking FreeCodeCamp's Javascript Algorithms and Data Structures certification, this post may be of interest to you.
I am going to go through the thought process behind my solution for the last challenge of the certification, the Cash Register. I found it quite complex and took around 3 days to complete.
The goal of this guide is to meet other developers and share the best approaches to this challenge as I am sure I can greatly improve the code. So be sure to leave a comment and connect!
So first, the problem
The challenge gives you a function CheckCashResgister with three parameters: price (prices of the purchase), cash(payment received for the purchase), and cid(cash-in-drawer available at the moment).
function checkCashRegister(price, cash, cid) {
}
checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]);
The last parameter, cid consists of a 2D array with the number of different coins and notes in the drawer.
The main goal of the function is to return an object with two properties: status and change. These properties’ values will change depending on the cid available and the change we need to give back. There can be three cases:
Our cash-in-drawer is less than the change, meaning we don’t have enough money to return the change, OR we cannot return the exact change. This means if we need to return $0.5 but only have a $1 note, we won’t return the change.
In that case the values to return will be: {status: "INSUFFICIENT_FUNDS", change: []}Our cash-in-drawer and change are equal. In that case, our cid will be the value for the key change: {status: "CLOSED", change: [cid]}.
The cash-in-drawer is higher than the change. In that case, the value of change will be an array containing the different notes and coins to return sorted from highest to lowest.
Breaking up the solution
The first step is to define what we will need to give back, creating the variable difference to calculate de margin between the cash given and the price to pay.
function checkCashRegister(price, cash, cid) {
var difference = cash - price;
const originalDiff = difference;
var objectReturn = {
status: '',
change: []
}
let arrCurrency = [
["ONE HUNDRED", 100],
["TWENTY", 20],
["TEN", 10],
["FIVE", 5],
["ONE", 1],
["QUARTER", 0.25],
["DIME", 0.1],
["NICKEL", 0.05],
["PENNY", 0.01]
]
This variable will change further in the code. That’s why we create a Const orginalDiff to store the original difference. We will need this variable further in the code to define the three possible outcomes.
We also create the object to return called objectReturn with the two properties. For now, the status will be set to an empty string, and the change will be set to an empty array.
We will also create the variable arrCurrency copying the different currency values from the statement in an array. We are going to use this array later to calculate the availability of each currency.
After that, our first action is to reverse the original cid array. The cid is given in ascendent order but we reverse it to be able to compare each sub-array with the correspondent one in the arrCurrency array.
Then, we create a variable cidSum and use a for loop to sum all the money in our drawer. Comparing the cidSum to originalDiff, we will be able to create the three possible returns.
cid.reverse();
var cidSum = 0;
for(let i = 0; i<cid.length; i++){
cidSum += cid[i][1];
}
Now it gets to the complicated part. We need to find a way to return the change with the appropriate currency.
To do that we will use a for loop that will iterate through the different currencies of our array arrCurrency.
To begin with, we create a new array with the name result where we copy all the exact values of arrCurrency with the spread operator. In each iteration, we will change the value of each currency in the result array to the number needed for the change.
var result = [...arrCurrency];
for(let i = 0; i<arrCurrency.length; i++){
let returnMoney = 0;
let bill = cid[i][1]/arrCurrency[i][1]
bill.toFixed(2);
while(difference.toFixed(2)>=arrCurrency[i][1] && bill>=1){
difference -= arrCurrency[i][1];
returnMoney += arrCurrency[i][1];
bill--;
}
if(returnMoney>0){
if(returnMoney - Math.floor(returnMoney) !== 0){result[i][1]= returnMoney.toFixed(2)
result[i][1] = parseFloat(result[i][1])}else{
result[i][1]= returnMoney;
}
}else{
result[i][1]= returnMoney;
}
}
Inside the for loop:
We create a variable returnMoney where we will store the value of each coin calculated for the change.
We will also need to know if we have money available from each currency. For that, we create a variable bill and divide each currency of our cash-in-drawer for its counterpart in the arrCurrency, and we round the number to two decimals. If bill is greater or equal than 1, it will mean we will have currency available.
We create a while loop. As long as the difference is greater than the currency we are iterating at at the moment, and bill is greater or equal than 1, the loop will keep subtracting the currency value to our difference and adding that same currency to our variable returnMoney.
Once the difference goes under the currency value or we run out of money, we go on to the if statement. If the returnMoney is greater than 0, meaning we will return change in that note or coin, we will have to evaluate if the number needs rounding or not.
One of the problems I encountered was JavaScript’s floating point number precision. The second if statement looks if a number is decimal or not by substracting its largest integer with the Math.floor method. (Ex = 5.05 – Math.floor(5.05) = 0.05). If the result is greater than 0 it will round the number to two decimals. As the method toFixed returns a string, we will need to convert it to a number again to pass the tests.
In all cases, we will end up changing the original value of the currency in our result array with that of returnMoney.
Before going to the last part of the challenge, we will need to calculate if we will be able to return the exact change.
For that, we create another for loop that will sum all the values stored in our array result to the variable sumResult. As we have calculated in the previous for loop, our change to give back according to the currencies available will mean that if the sum of all these values is less than our original difference, we won’t be able to give back the exact change.
let sumResult = 0;
for(let i = 0; i<cid.length; i++){
sumResult += result[i][1];
}
sumResult = sumResult.toFixed(2);
Our last if statement defines the three outcomes possible:
if(cidSum < originalDiff || sumResult < originalDiff){
objectReturn.status = 'INSUFFICIENT_FUNDS';
}else if(cidSum == originalDiff){
objectReturn.status = 'CLOSED';
objectReturn.change = cid
}else{
let resultFiltered =[];
for(let a = 0; a<result.length; a++){
if(result[a][1]!==0){
resultFiltered.push(result[a]);
}
}
objectReturn.status = 'OPEN';
objectReturn.change = resultFiltered;
}
return objectReturn;
}
If the sum of our cash-in drawer, or the sum of the currency available, is less than the difference to give back it will change the property status of our object to ‘INSUFFICIENT_FUNDS’.
If the sum of our cash-in drawer is the same as our difference it will change both properties of the object.
Finally, if the sum of our cash-in drawer is greater than the difference, it will create a filtered array of our result array, without all the coins with a value of 0, and change the properties to their correspondent values.
In the end, we will return the object.
I am sure you are happy-crying now as you realize this long-ass article has finally come to an end. Hopefully, you will have been able to understand it, as concision and storytelling have never been my strongest skills.
Either way, let me know in the comments what do you think about the code and please do give suggestions for improvements, they will be greatly appreciated!
You can also check out the full solution in my Github
Top comments (14)
Thank u so much <3
THANKS
I still don't understand how to solve it but at least now I have something plain and understandable to read and try to figure it out :)
Don't give up 💪
In the end, what I learned most completing this project is to carefully read the problem and try to break it into smaller tasks that you can start working on separately. Hopefully, you will get it soon!😊
i have a question with this code, what if difference = 6, while we have one 0.25 and six 1left, when the code run for 0.25, (difference.toFixed(2)>=arrCurrency[i][1] && bill>=1)=true, so we will add 0.25to return money, but after that, we cannot make 0.35 out of 6*0.1,
Just amazing, awesome storytelling!
When i redo these steps, the last test fails, 'CLOSED' doesn't resolve.
for the 'CLOSED' case, i figured after doing a console.log(), that the change array was being provided in the wrong order, so I just appended .reverse to the case, and it worked.
A beautiful story
Thank you for your brief explanation
Thank you for sharing your solution in this step-by-step format! Very beneficial!