I need some serious guidance - Cash Register Exercise

Tell us what’s happening:
Hi all, I’m in need of some guidance with this final problem for the JavaScript section: the cash register problem. I have been struggling through this section, but pushing myself more than ever. I feel rather frustrated with this problem, because I can’t even begin to imagine where to start. I’m determined to not seek out others answers until I discover my own resolution for this problem, but not sure how to even brainstorm what needs to be done, on paper. Below I have some starter variables, and an array of objects that holds the value of each dollar/coin amount, like FCC suggests, and a tiny function to measure the sum of the “cash in drawer”, besides that I don’t know where to start. I’ve brainstormed many ways of looping through the cid argument, and the currency variable i created, but can’t determine how to get the values to make up the “change due”. I’ve been staring at this problem for almost a week now and can’t wrap my head behind the problem. Any direction is really appreciated. Thank you.

Your code so far


function checkCashRegister(price, cash, cid) {
    let currency = [
    { name : 'ONE HUNDRED', val : 100.00},
    { name : 'TWENTY', val : 20.00},
    { name : 'TEN', val : 10.00},
    { name : 'FIVE', val : 5.00},
    { name : 'ONE', val : 1.00},
    { name : 'QUARTER', val : 0.25},
    { name : 'DIME', val : 0.10},
    { name : 'NICKEL', val : 0.05},
    { name : 'PENNY', val : 0.01}
    ];

    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = 0;
    

    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
    }
    
    
    console.log(cashInDrawer);
    console.log(changeFromTransaction);
}



console.log(JSON.stringify(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]])));

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/cash-register

Think of how you’d make change in real life: You pick the largest denomination you have that’s less than or equal to the amount of change owed, you give back one of that denomination, subtracting it from the change owed. Repeat the process until the change owed is zero. If you can’t get the change to zero this way, you’re “out of change” (and in this fictional scenario, it aborts the whole transaction).

Now turn this into an algorithm, paying attention to every word in the sentences. Start by picking the largest denomination that’s equal to or less than the change owed. If you have one of that denomination, use it, otherwise go to the next lower denomination and use that. Give one of that denomination in change, i.e. subtract it from the change owed and its spot in the drawer. If the change owed is zero, you’re done. Otherwise repeat this process for the rest of the change you owe. If you cannot pick a denomination using this algorithm and there’s still change owed, then you are out of change.

2 Likes

This is insanely helpful, and I feel real close to gaining ground; however, I’m struggling to understand how I am supposed to target the “spot in the drawer” when I’m trying to subtract that denomination’s value from that denominations spot in the cash drawer. I conceptually understand that I see a quarter is 0.25 and need to subtract that from the quarter sub-array in the cid array, but I don’t understand how to target that quarter sub-array. I was thinking since both strings are “QUARTER” I could somehow use that to access the value, but I’m not sure that even makes any sense? Dang.

What you’d do is have an object like this:

let denoms = { HUNDRED: 100.00, FIFTY: 50.00, TWENTY: 20.00 } // etc

and so on down to PENNY at 0.01. Now notice the third argument you get to checkCashRegister, the cash in drawer, is in increasing order of denominations. So start at the end of the drawer, at “HUNDRED”, see if you have any, then look up its denomination in that denoms table. If it’s over the amount of change owed (or you don’t have any of that denomination), go to the next lower drawer, “FIFTY”, and repeat the process. Once you have an appropriate denomination for change, update that sub-array in the drawer.

One other hint: try to break things into separate functions, and test them out as you go. This problem is a lot harder if you try to solve it in one bite.

What I did when I solved this (years ago) was I reversed the cash-in-drawer array so I wouldn’t have to iterate through it backwards. I also multiplied all the quantities by 100 so I wouldn’t have to deal with floating point. I also recall this one took me a while to solve.

1 Like

This makes so much sense… But I am so disappointed that this shouldn’t be as hard as it is making out to be… I don’t understand how I am supposed to even target anything in the denoms object. My price is 15, my cash is 20. I loop through the cash in drawer (after reversing it), I land on [“FIVE”, 5.00], but how am I supposed to subtract the denomination’s value from that spot? I know I can access the value by, denoms.FIVE, but how do I know it’ll be five? If cid[3][0] === “FIVE”, I don’t see how I can’t do, denoms.cid[3][0]. I have a feeling I need to iterate through the object, to match the object’s property to the string name in the cid array… I’m feeling so stuck, haha…

Are the property names in the denoms object supposed to be strings… let denoms = {“HUNDRED” : 100.00} or exactly the way you typed it out?

In objects, keys (eg. { key: value }) don’t need to be wrapped in quotation marks if they’re only one word, so { HUNDRED: 100 } is fine.

As for targeting properties in the denoms object, recall that you can use dot or bracket notation to access properties:

denoms.HUNDRED or denoms["HUNDRED"] would give you the value.

Also, you can iterate through an object using for…in. The FCC lesson is here.

The syntax looks like:

for (let property in denoms) {
  ...code...
}

I completed the Cash Register project last week, and it took me two days to figure it out, so don’t feel bad or exasperated if it’s taking a while.

1 Like

I’m so stuck right now… I am not sure if I’m even headed in the right direction… In this test the cost is 14, and the cash provided is 20. The bottom chunk of code subtracts 5 from the “FIVE” sub-array in the cid parameter, and subtracts 5 from the changeFromTransaction variable which is 20 - 14, which equals 6. So after that math runs my fives drawer goes from 55 to 50 ( 55 - 5 ) and my expected change goes from 6 to 1 ( 6 - 5 ). But I still have one dollar I need to return and don’t know if my code is looping into the ones denomination to return that… This actually is starting to feel impossible… lmao.

function checkCashRegister(price, cash, cid) {
    let currency = {
        "ONE HUNDRED" : 100.00,
        "TWENTY" : 20.00,
        "TEN" : 10.00,
        "FIVE" : 5.00,
        "ONE" : 1.00,
        "QUARTER" : 0.25,
        "DIME" : 0.10,
        "NICKEL" : 0.05,
        "PENNY" : 0.01
    };

    let newCid = cid.reverse();
    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = [];

    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
    }

    if (cashInDrawer < changeFromTransaction){
        return {status: "INSUFFICIENT_FUNDS", change: []};
    }

    for (let c = 0; c <= cid.length; c++){
        if (cid[c][1] > 0 && currency[cid[c][0]] <= changeFromTransaction){
            while(changeFromTransaction > 0){
                cid[c][1] - currency[cid[c][0]];
                changeFromTransaction - currency[cid[c][0]];
        }
    }
    }
}



console.log(JSON.stringify(checkCashRegister(14, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]])));

Remember you can always get at an object’s properties with bracket notation when the property is variable. In other words:

let five = cid[3][0]
let amount = denoms[five]
1 Like

Okay, so revisions were made. I don’t know what the code is supposed to look like, and this sure looks ugly, but it looks close to what it should look like… I think?

The expected change is 8 dollars ( 20 - 12 ), and it’s returning 5, but not the other 3 through three individual 1’s. Which is telling me my loop isn’t switching over to the other denomination when it exhausts the current one… I believe?

When I run this I get: {"status":"OPEN","change":[["FIVE",5]]} when I think it should return: {"status":"OPEN","change":[["FIVE",5], ["ONE",3]]}

function checkCashRegister(price, cash, cid) {
    let currency = {
        "ONE HUNDRED" : 100.00,
        "TWENTY" : 20.00,
        "TEN" : 10.00,
        "FIVE" : 5.00,
        "ONE" : 1.00,
        "QUARTER" : 0.25,
        "DIME" : 0.10,
        "NICKEL" : 0.05,
        "PENNY" : 0.01
    };

    let newCid = cid.reverse();
    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = [];

    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
    }

    if (cashInDrawer < changeFromTransaction){
        return {status: "INSUFFICIENT_FUNDS", change: []};
    }

    for (let c = 0; c <= cid.length; c++){
        if (cid[c][1] > 0 && currency[cid[c][0]] <= changeFromTransaction){
            while(changeFromTransaction > 0){
                cid[c][1] - currency[cid[c][0]];
                changeFromTransaction - currency[cid[c][0]];
                changeDue.push(cid[c][0]);
                changeDue.push(currency[cid[c][0]]);
                return {status: "OPEN", change: [changeDue]}; 
                
            }
    }
}
}


console.log(JSON.stringify(checkCashRegister(12, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]])));

Unfortunately it’s not quite that simple. What if you needed to make three dollars in change, but only had a twenty and a ten in the drawer? Think back to the algorithm I described which models how you’d make change in real life – you have to skip over any denominations larger than the amount of change you’re giving back.

1 Like

I see, I figured out how to code that part in now properly, but have erased my code several times as I can’t get it to flow the proper way. Here is my current set up, it is a bit sloppy, and has console.log()'s all over the place, but I want to explain my confusion. In my for...in loop, I managed to get the denominator value to subtract from the difference between the cost of the item, and the cash provided. So, the cost is 14, and 20 is provided, so the difference is 6. It loops through and hits 5, and subtracts 5 from the 6, so I’m left with 1, but that’s all that I’m left with, I don’t know why it won’t loop back around to the next value? It should loop to 1 and subtract 1 from 1, but it just stops at 1?

function checkCashRegister(price, cash, cid) {
    let currency = {
        "ONE HUNDRED" : 100.00,
        "TWENTY" : 20.00,
        "TEN" : 10.00,
        "FIVE" : 5.00,
        "ONE" : 1.00,
        "QUARTER" : 0.25,
        "DIME" : 0.10,
        "NICKEL" : 0.05,
        "PENNY" : 0.01
    };

    cid.reverse();
    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = [];
   
    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
    
        for (let x in currency){
            if (cid[i][1] && currency[x] <= changeFromTransaction && cid[i][0] === x){
                while (currency[x] <= changeFromTransaction && changeFromTransaction > 0){
                console.log(changeFromTransaction)
                changeFromTransaction = changeFromTransaction - currency[x]     
                console.log(changeFromTransaction)
                changeDue.push(x);
                changeDue.push(currency[x]);
                }
                    return changeDue;
        }
    }
   }
    

  
}


console.log(JSON.stringify(checkCashRegister(14, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]])));

How’s your progress on this project?

When I was conceptualizing my solution, it helped to break down the function into several “steps”. Sometimes it’s difficult to figure this out ahead of time, but by conceptualizing step by step, you get closer to solving the full problem. Then there’s less and less to figure out, and those steps you’ve taken can give you ideas on how to conceptualize more steps.

You don’t have to get too technical during the brainstorming phase. I find that writing things down in everyday language is more helpful anyway. You can figure out the specific types of methods, loops, or whatever later.

My solution is not pretty, and probably not optimal, but I’ll give you the first few steps I decided on. I think you’ve gotten about that far anyway, so it shouldn’t be giving too much away:

  1. Create variables to store the values of money denominations (let’s call it cashVal), the difference between cash and price (cashDiff), and the change object to be returned by the function (change)
  2. Determine a way to associate the variable storing the money values (cashVal) with the cash-in-drawer (cid)
  3. Loop through cid or cashVal, and in this loop, determine whether each successive money denomination can provide part of cashDiff; if it can, it should provide as many of itself as it can and append that to the change object; cashDiff should also be updated to reflect how much change is left

Once you’ve gotten that part figured out, with cashDiff and change being updated to reflect how much change can be given and what’s left over at the end of the process, you can move on to the next phase of the function, which determines the final value of the change object to be returned from the function.

1 Like

Hey, thanks so much for the guidance. Yesterday I ended up with the code linked below. It does what I need it to do, with all values. It provides my all of the currency that is used, and subtracts it from the cash in drawer, to make sure I have enough of that denomination to use. I’m aware that the return statement isn’t complete, according to what FCC expects, but I wan’t to perfect the function itself, before worrying about the precision of the return statement. My current code returns:
[["TWENTY",20],["TWENTY",20],["TWENTY",20],["TEN",10],["TEN",10],["FIVE",5],["FIVE",5],["FIVE",5],["ONE",1],["QUARTER",0.25],["QUARTER",0.25],["DIME",0.1],["DIME",0.1],["PENNY",0.01],["PENNY",0.01],["PENNY",0.01],["PENNY",0.01]] when provided 100 in cash, for an item that costs 3.26.

All is good there, but my trouble is that all of the currency is separate - not added together like FCC expects. So instead of ["TWENTY",60], I’m left with ["TWENTY",20], ["TWENTY",20], ["TWENTY",20].

I’m aware this is because I’m pushing each value into a new array: changeDue. I am not sure if others solved it by pushing the values into a new array, which doesn’t seem like to cleanest way to accomplish this, but seems possible. I’m just not sure if I need to add all of the similar denominations BEFORE pushing them into the array, or AFTER. I’ve been attempting to add them after, and it’s quite a nightmare working with a for...loop. I have a great feeling there is a way to use .reduce();, .filter();,or.map(); to accomplish what I’m attempting to do… But I don’t have a full grasp of those higher order functions.

function checkCashRegister(price, cash, cid) {
    let currency = {
        "ONE HUNDRED" : 10000,
        "TWENTY" : 2000,
        "TEN" : 1000,
        "FIVE" : 500,
        "ONE" : 100,
        "QUARTER" : 25,
        "DIME" : 10,
        "NICKEL" : 5,
        "PENNY" : 1,
    };

    cid.reverse();
    price *= 100;
    cash *= 100;
    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = [];
    let finalChangeDue = [];


    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
      cid[i][1] *= 100;

        for (let x in currency){
            if (currency[x] <= changeFromTransaction && cid[i][0] === x){
            
                while(currency[x] <= changeFromTransaction && cid[i][1] > 0){     
                console.log(currency[x]);
                changeFromTransaction -= currency[x];
                cid[i][1] -= currency[x];
                changeDue.push([x, currency[x]/100]);   
                }
                if (changeFromTransaction !== 0){
                    continue;
                }

               
            } 
        }   
   }
   
 return changeDue;

}
console.log(JSON.stringify(checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]])));

Instead of just pushing the currency to the end of changeDue, check whether the denomination at the end of the array is the same, and if so, add it instead of pushing it.

1 Like

I had this exact thought process, I just couldn’t imagine that in my mind, if changeDue is an empty array to begin with, what will I be comparing to in the original iteration of the loop?

You’ll have to check for an empty array as a special case, then just push the value if the array is empty. Boundary conditions like that are always “fun” :upside_down_face:

When I did this, I used an object for the change due, then built the array at the end, using the denominations object to provide the proper order (creating yet another temporary array in the process). Given that you’ve done it thus far with an array, it’s probably easiest to stick with it though.

1 Like

While this is some ugly code… It’s finished. It passes the test. I know there is probably many, many ways to improve and consolidate this code… But I am beyond ecstatic that I figured this out, and I thank you and @dylanhamada so, so much, for your assistance. This puts a damn smile on my face. :^)

function checkCashRegister(price, cash, cid) {
    let currency = {
        "ONE HUNDRED" : 10000,
        "TWENTY" : 2000,
        "TEN" : 1000,
        "FIVE" : 500,
        "ONE" : 100,
        "QUARTER" : 25,
        "DIME" : 10,
        "NICKEL" : 5,
        "PENNY" : 1,
    };
    
    cid.reverse();
    price *= 100;
    cash *= 100;
    let changeFromTransaction = cash - price;
    let cashInDrawer = 0;
    let changeDue = [];
    let sumOfChangeDue = 0;

    for (let i = 0; i < cid.length; i++){
      cashInDrawer += cid[i][1];
      if (changeFromTransaction/100 === cashInDrawer){
        return {status: "CLOSED", change: cid.reverse()};
      } 

        cid[i][1] *= 100;
        for (let x in currency){
            if (currency[x] <= changeFromTransaction && cid[i][0] === x){
                while(currency[x] <= changeFromTransaction && cid[i][1] > 0){     
                changeFromTransaction -= currency[x];
                cid[i][1] -= currency[x];
                if (changeDue.length == 0 || x !== changeDue[changeDue.length - 1][0]){
                    changeDue.push([x, currency[x]/100]);
                } else if (x === changeDue[changeDue.length - 1][0]){
                    changeDue[changeDue.length - 1][1] += currency[x]/100;
                } else if (changeFromTransaction !== 0){
                    continue;
                } 
                }
            }
        } 

    }     
    
    if (cashInDrawer < changeFromTransaction){
        return {status: "INSUFFICIENT_FUNDS", change: []};
    } else 
    return {status: "OPEN", change: changeDue};
}
console.log(JSON.stringify(checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]])));
3 Likes

Glad you made it through, and happy to have helped :smile: