Cash Register Challenge - Nested While Loop in For Loop?

Tell us what’s happening:
Hi Campers!

I’m struggling a bit with this one and would appreciate the help. I’ve tried to implement a similar solution to the Roman Numerals Calculator. I increment through all the denominations and start with the highest denomination I can give, loop through that denomination until I can’t give anymore, then push that value to an array and increment to the next unit.

It might be easier if you have a look at the comments I’ve made below. I’ve been working on this for a good few hours so maybe I’m a bit too close to the code to notice an obvious error or logic fail! Any advice would be much appreciated.

On another note, what is the convention for writing comments in the code? Should a comment be indented to the same level as the code it’s representing or should it have no indent?

Thank you in advance!

Emma

Your code so far


function checkCashRegister(price, cash, cid) {
  // ARRAY OF ALL DENOMINATIONS AND THEIR VALUES
  var units = [
    {name: 'ONE HUNDRED',  value: 100.00},
    {name: 'TWENTY',       value: 20.00},
    {name: 'TEN',          value: 10.00},
    {name: 'FIVE',         value: 5.00},
    {name: 'ONE',          value: 1.00},
    {name: 'QUARTER',      value: 0.25},
    {name: 'DIME',         value: 0.10},
    {name: 'NICKEL',       value: 0.05},
    {name: 'PENNY',        value: 0.01}
  ];

  let changeDue = cash - price;

  let checkCid = cid.reduce((acc, cur) => acc + cur[1], 0);

  // IF NOT ENOUGH CHANGE
  if(checkCid < changeDue){
    return {status: "INSUFFICIENT_FUNDS", change: []}; 
  } 

  // IF CHANGE DUE EXACTLY MATCHES TOTAL CID
  else if(checkCid === changeDue){
    let due = cid.sort((a, b) => {
      return b[1] - a[1];
    });
    return {status: "CLOSED", change: due};
  }

  
  else {
  //GET CID IN SAME ORDER AS 'UNITS' ARRAY TO ITERATE THROUGH BOTH AND SELECT VALUES USING 'i'
    cid = cid.reverse();
  // DEFINE EMPTY ARRAY TO PUSH BELOW DENOM ARRAY TO (IF DENOM NOT EMPTY)
    let result = [];

  // ITERATE THROUGH UNITS ARRAY
    for(let i = 0, len = units.length; i < len; i++){
  // DEFINE EMPTY ARRAY FOR EACH UNIT
      let denom = [];
  //ON A PARTICULAR UNIT, IF CHANGE DUE IS GREATER THAN OR EQUAL TO THE VALUE OF UNIT[i] AND THERE IS CHANGE AVAILABLE: 
      while(changeDue >= units[i].value &&  cid[i][1] >= changeDue){
        // IF FIRST ITERATION OF WHILE LOOP, DENOM WILL BE EMPTY
        if(denom.length === 0){
          denom.push(units[i].name);
          denom.push(units[i].value);
        // IF DENOM NOT EMPTY, INCREMENT THE DENOM BY THE UNIT VALUE
        } else{
          denom[1] += units[i].value;
        }
        // DECREMENT THE CHANGE DUE AND THE CID BY THE VALUE YOU'VE JUST ADDED TO DENOM
        changeDue -= units[i].value;
        cid[i][1] -= units[i].value;
      }
      // PROVIDING DENOM ISN'T STILL EMPTY(THE WHILE LOOP RAN), PUSH DENOM TO RESULT
      if(denom.length === 2){
        result.push(denom);
      }
    }
    // ENSURE THE HIGHEST VALUE IN THE 2D ARRAY IS FIRST
  result.sort((a,b) => {
    return b[1] - a[1];
  })

  return {status: "OPEN", change: result};
  }
}

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/68.0.3440.84 Safari/537.36.

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

If I have $60 worth of 20 and my changeDue is $93, should I give them twenties for change or not?

1 Like

Thanks for your response.

cid[i][1] >= changeDue

I see what you mean. If it’s got to the stage that I’m at $20, then it shouldn’t matter that the change due is over what I have for that denomination, I should just pay what I can and move on. I have changed to the below make sure the while loop only continues if there is still enough value in cid for that denomination:

while(changeDue >= units[i].value && cid[i][1] >= units[i].value)

Just one left to crack! Presumably JavaScript is affected by errors when trying to add floats? I’ve noticed on the price = 3.26, cash = 100 test that I end up with 0.03 as a penny and a 0.009… something as my remaining change. I’ve consulted a Stack Overflow post and it looks like a combination of parseFloat and toFixed would sort the issue but I’m not 100% on how to implement it . If you have any hints that would be much appreciated.

Thanks again!

Yes. JS does have huge floating point errors. SO you’ll have to do what you said in the last half your post.

Okay I managed to solve it using

Math.round((num1 + num2)/100)*100

But if you know of anything else that will help with this, that’d be great. This somehow seems a bit clunky!

Cheers.

Okay, thanks for your response. I’ll dig a little deeper.

This might help:

Number.parseFloat(someNumber.toFixed(2))

Might need to flip it the other way.

1 Like

Okay perfect. My code has gone now I’ve finished it but I’ll probably try this again completely in a couple of days with your tip.

Thanks again and have a good day!

1 Like