Cash Register Problem to finish JS Cert

My solution here is a little convoluted. I used a method similar / building off of a method I found online to do the Roman Numeral Conversion. My ‘table’ is a reference table.
leftInRegisterObj and changeDue are initially objects that I convert to arrays for purpose of the output.

A little explanation:

  • quantity: number of coins/bills needed
  • diff: the sum value of change due to the customer (used for calculations)
  • amount: the same value as diff, only used in the end for a condition
  • leftInRegisterObj: object with the value of each denomination remaining in register
  • changeDue: object of change in each denomination, taken out of register to be given to customer

In VSCode I am getting the correct output for:

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 expected output being:

{ status: 'OPEN', change: [ [ 'QUARTER', 0.5 ] ] }

which is an object. However, the FCC interpreter is not recognising this as either an object nor the correct output.
Please Help!!

function checkCashRegister(price, cash, cid) {
  let table = {
    'ONE HUNDRED': 100,
    TWENTY: 20,
    TEN: 10,
    FIVE: 5,
    ONE: 1,
    QUARTER: 0.25,
    DIME: 0.1,
    NICKEL: 0.05,
    PENNY: 0.01
  }

  // variable declaration
  cid = cid.reverse();
  let diff = cash - price;          // diff and amount are same value. diff is used for calculations, and is changed
  let amount = cash - price;
  let leftInRegisterObj = Object.fromEntries(cid.map(([a, b]) => [a, b]));
  let changeDue = {};
  let registerInitialSum = cid.reduce((sum,val) => sum + val[1] ,0);

  // helper func to make obj into arrays for output         USEFUL FUNCTION
  const objectToArray = (obj = {}) => {
    const res = [];
    const keys = Object.keys(obj);
    for(key of keys){
        res.push([
          key, obj[key]
        ]);
    };
    return res;
  };

  // conditions to check if CID is enough for required change
  if (registerInitialSum < diff) {
    return {status: "INSUFFICIENT_FUNDS", change: []};
  } else {
    while (diff > 0) {
      for (let i of Object.keys(table)) {
        let quantity = Math.floor(diff/table[i]);

        let val = quantity * table[i];
        leftInRegisterObj[i] -= val;
        diff -= val;
        if (quantity != 0) {
          changeDue[i] = val;
        };
      };
    };
  };

  // sum values of leftInRegisterObj before next conditions
  let registerFinalSum = Object.values(leftInRegisterObj).reduce((a, b) => a + b, 0);

  // Convert changeDue and leftInRegisterObj objects into 2D arrays for returning
  changeDue = objectToArray(changeDue);
  leftInRegisterObj = objectToArray(leftInRegisterObj);
  //console.log('left in register', leftInRegisterObj, '\n change returned', changeDue);

  if (amount == registerFinalSum){
    return {status: "CLOSED", change: [...leftInRegisterObj]};
  } else if (amount < registerFinalSum) {
    return {status: "OPEN", change: [...changeDue]};
  };
};

Well it seems the reason is that there is a error being produced by the code (not sure why VSCode doesn’t see it) here:

You never declared key.

Once you fix that, there are still errors with the output though.

Edit: I put in a lot of console.logs and I can see for eg. that for this case:

checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []} .

You are allowing the register to go into negatives. At one point you have this
res = ONE HUNDRED,0,TWENTY,0,TEN,0,FIVE,0,ONE,1,QUARTER,-0.5,DIME,0,NICKEL,0,PENNY,0.01
Notice the quarter field is -0.5 (I printed out the res from your objectToArray)
So I would add a lot more logging and start figuring this out, one test case at a time.

First of all, why are you adding semi-colons after every statement or line of code? Semi-colons are typically not put after function declarations or if/else statements. It makes your code too busy.

You definitely should look at your browser console for errors and do not rely on the FCC console which may or may not show you all the issues.

Once you fix the issue @hbar1st pointed out, you need to add some console.log statements inside the while loop as you have created an infinite loop there for one or more of the test cases.

2 Likes

I have made some rearrangements and cleaned up the code a bit. I haven’t yet console.logged anything or addressed infinite loops… Just updating here with what im currently working with:

@hbar1st thanks for your help on this so far
@RandellDawson good advice

function checkCashRegister(price, cash, cid) {
    let table = {
      'ONE HUNDRED': 100,
      TWENTY: 20,
      TEN: 10,
      FIVE: 5,
      ONE: 1,
      QUARTER: 0.25,
      DIME: 0.1,
      NICKEL: 0.05,
      PENNY: 0.01
    }
  
    // variable declaration
    cid = cid.reverse();
    let diff = cash - price;          // diff and amount are same value. diff is used for calculations, and is changed
    let amount = cash - price;
    let leftInRegisterObj = Object.fromEntries(cid.map(([a, b]) => [a, b]));
    let changeDue = {};
    let registerInitialSum = cid.reduce((sum,val) => sum + val[1] ,0);
  
    // helper func to make obj into arrays for output         USEFUL FUNCTION
    const objectToArray = (obj = {}) => {
      const res = [];
      const keys = Object.keys(obj);
      for(let key of keys){
          res.push([
            key, obj[key]
          ]);
      }
      return res;
    }
    
    while (diff > 0) {
        for (let i of Object.keys(table)) {
            let quantity = Math.floor(diff/table[i]);

            let val = quantity * table[i];
            leftInRegisterObj[i] -= val;
            diff -= val;
            if (quantity != 0) {
            changeDue[i] = val;
            }
        }
    }

    // sum values of leftInRegisterObj before next conditions
    let registerFinalSum = Object.values(leftInRegisterObj).reduce((a, b) => a + b, 0);
    let changeDueSum = Object.values(changeDue).reduce((a,b) => a+b,0);

    // Convert changeDue and leftInRegisterObj objects into 2D arrays for returning
    changeDue = objectToArray(changeDue);
    leftInRegisterObj = objectToArray(leftInRegisterObj);

    if (amount > registerInitialSum || (amount != changeDueSum && amount < registerFinalSum) ) {
        return {status: "INSUFFICIENT_FUNDS", change: []};
    } else if (amount == changeDueSum && registerFinalSum == 0){
        return {status: "CLOSED", change: [...leftInRegisterObj]};
    } else if (amount == changeDueSum || registerFinalSum > 0 ) {
        return {status: "OPEN", change: [...changeDue]};
    }
  }
1 Like

Rounding to nearest 100th seems to have solved the infinite loop as well as the negatives, I believe. What remains seems to be the conditional statement logic at the end.

Here is the updated while loop:

    while (diff > 0) {
        for (let i of Object.keys(table)) {
            let quantity = Math.floor(diff/table[i]);
            let val = quantity * table[i];
            val = Math.round(val/100)*100;

            leftInRegisterObj[i] -= val;
            diff -= val;
            diff = Math.round(diff/100)*100;

            if (quantity != 0) {
            changeDue[i] = val;
            }
        }
    }