Cash Register OBO Error

Tell us what’s happening:

I’ve been banging my head against this one for a while now. I have coded what appears to be a satisfactory solution for counting down change, and it works in all cases except those where it needs pennies, in which case I always get an Off By One error for some reason that doesn’t affect the other denominations. Also in cases where there are many pennies I get a rounding error, but I don’t think that’s related as the trailing zeros don’t show up for small amounts.

I’ve tried changing many parts of the loops in the code to get it to work, but nothing seems to help. I’ve been at this for a few hours now so I’m going to bed, hopefully to solve it in the morning, but I thought I might as well post it so maybe a more experienced pair of eyes might spot what I don’t see.

I haven’t touched the part of the challenge that requires me to set the status, as I want to solve the change part of the challenge first, so I have the status set to “OPEN” just so when I run the test I can see if it passes.

Thanks in advance for any help! I feel like it’s got to be something that will be obvious tomorrow but I can’t allow it to keep me up any longer than this.

Your code so far


function checkCashRegister(price, cash, cid) {
  //set up variables 
  let chk = [100, 20, 10, 5, 1, .25, .1, .05, .01]
  let owe = cash - price;
  let pos = 0;
  let ret = {status: "OPEN", change: []}
  //begin loop until change owed is 0
  for (let i = 0; owe > 0; i++) {
    for (let j = 0; j < chk.length; j++) {
      //set an easy reference for the position of the bill/coin in the cid array
      let pos = (cid.length - 1 - j)
      //make sure the loop doesn't end earlier than the change runs out
      for (let k = 0; cid[pos][1] > 0 && owe >= chk[j]; k++) {
        //if what is owed is greater than the bill/coin value, subtract it
        if (owe > 0) {
          //if the change array is empty, push this as the first value
          if (ret.change.length == 0) {
            ret.change.push([cid[pos][0], chk[j]]);
            cid[pos][1] -= chk[j];
            owe -= chk[j]
          }
          //if this value doesn't exist in the change array, push it in;
          else if (ret.change[ret.change.length - 1][0] != cid[pos][0]) {
            ret.change.push([cid[pos][0], chk[j]]);
            cid[pos][1] -= chk[j];
            owe -= chk[j]
          }
          //if a spot already exists, simply add to the value in change
          else {
            ret.change[ret.change.length - 1][1] += chk[j];
            cid[pos][1] -= chk[j];
            owe -= chk[j]
          } 
        }
      }
    }
  }
 return ret;
}

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]])));

Your browser information:

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

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

jeez man are you sure you used enough for loops?

Honestly I’ve not been able to wrap my head around the alternatives like .map and the like very well. I’ve used them once or twice but it took a lot of fiddling to get right.

Alright at the suggestion of a friend I learned and used the .reduce method, which I have found some success with for the rest of the problem. But I am still having a problem specifically with the problem to make change for $3.26 out of 100. But this time, instead of an apparent off by one error, it’s returning insufficient funds and refusing to do change for some reason.

function checkCashRegister(price, cash, cid) {
  //set up variables 
  let values = [{name: 'ONE HUNDRED', amt: 100}, {name: 'TWENTY', amt: 20}, {name: 'TEN', amt: 10}, {name: 'FIVE', amt: 5}, {name: 'ONE', amt: 1},,{name: 'QUARTER', amt: 0.25}, {name: 'DIME', amt: 0.1}, {name: 'NICKEL', amt: 0.05}, {name: 'PENNY', amt: 0.01}
];
  let owed = cash - price;
  let ret = {status: "OPEN", change: []};
  
  //calculate the total contents of the cid
  let ava = cid.reduce(function(prev, next) {
    prev[next[0]] = next[1];
    prev.tot += next[1];
    return prev;
  }, {tot: 0});

  //check to see if change is going to be exact, change "OPEN" to "CLOSED"
  if (ava.tot === owed) {
    ret.status = 'CLOSED';
    ret.change = cid;
    return ret;
  }

  //use reduce function to test against values array
  let changeMake = values.reduce(function(prev, next) {
    let value = 0;
    while (ava[next.name] > 0 && owed >= next.amt) {
      value += next.amt;
      owed -= next.amt;
      ava[next.name] -= next.amt;
    }
    if (value > 0) {
        prev.push([next.name, value]);
    }
    return prev;
  }, []); 


  //second check type for insufficient funds
  if (changeMake.length < 1 || owed > 0) {
    ret.status = 'INSUFFICIENT_FUNDS';
    return ret;
  }

  //run the functions and return the result
  ret.change = changeMake;
  return ret;
}

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]])));

Not really super sure where to go from here, I can’t really get to the bottom of why it would do that specifically on this one.

Ah, typically I figured out the problem that had been plaguing me for 30 minutes within 5 minutes of asking for help. I added

owed = parseFloat(owed.toFixed(2);

below the line where I subtracted the amount of change from the amount owed to fix any floating point rounding errors and the whole program started working again. Sorry to ask so many questions about this one I’ve spent far too many hours on it now.