Post your Cash Register solutions here! (Fall 2022)

Hey everyone.

Congratulations on making it to the end of the Fall 2022 cohort of the free JavaScript Bootcamp. It’s always bittersweet to make it here, but I am proud of each and every one of you for making it this far.

With that said, let’s post our solutions!

Here’s mine:

const DENOMINATIONS = {
  PENNY: 1,
  NICKEL: 5,
  DIME: 10,
  QUARTER: 25,
  ONE: 100,
  FIVE: 500,
  TEN: 1000,
  TWENTY: 2000,
  "ONE HUNDRED": 10000
}
function checkCashRegister(price, cash, cid) {
  // calculate amount of change due
  const changeDue = cash - price;
  let changeDueCents = changeDue * 100;

  const centsInCid = cid.reduce((acc, slot) => {
    return acc + slot[1] * 100;
  }, 0);
  
  if (centsInCid === changeDueCents) {
    return {status: "CLOSED", change: cid};
  }

  // cid like array 
  const changeInHand = cid.reverse().map(([name, valueInSlot]) => {
    // Start accumulating amount of money we'll give worth of that money type
    let total = 0;

    // Look up the denomination
    const denomination = DENOMINATIONS[name]

    // Get the value in the slot in cents
    let valueCents = valueInSlot * 100;

    // Loop: while the change due is worth more than the denomination, and while we still have money of that type in the drawer
    while(valueCents > 0 && denomination <= changeDueCents) {
      // Add one worth of that denomination to the total
      total += denomination;
      // Subtract that amount from the change Due
      changeDueCents -= denomination;
      // Subtract that amount from the amount in the slot
      valueCents -= denomination;
      //console.log({name, total, changeDueCents, valueCents})
    }
    return [name, total / 100]
  })
  .filter(([, value]) => value > 0);
  
  // If I still owe change, we don't have sufficient funds
  if (changeDueCents > 0) {
    return {status: "INSUFFICIENT_FUNDS", change: []}
  }

  return {status: "OPEN", change: changeInHand}
}

console.log(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]]));
10 Likes

OMG! This is really tasking for me, but I came through with it.

here is my solution:

// create an object and multiply it by 100, because it is easier to work with integers
const currencyUnit = {
"PENNY": 1,
"NICKEL": 5,
"DIME": 10,
"QUARTER": 25,
"ONE": 100,
"FIVE": 500,
"TEN": 1000,
"TWENTY": 2000,
"ONE HUNDRED": 10000
}
function checkCashRegister(price, cash, cid) {
  // calculate the difference between the cash and the accepted price 
  let myChange = cash * 100 - price * 100;
  let  myChangeCheck = myChange
  // initiate change to empty array and the status to empty string
  let change = [];
  let status = "";
  // initiate the cidSum to 0 and filtered the cid
  let cidSum = 0;
  let cidFiltered = cid.filter(elem => elem[1] !== 0).reverse(); 
// using forEach to iterate through cidFiltered
  cidFiltered.forEach(elem => {
    // initiate currency to the element(array) and currency sum and multiply it by 100, so to work with whole number
    let cur = elem[0];
    let curSum = elem[1] * 100;
    // add cidSum to currency sum
    cidSum += curSum;
    // initiate amount to 0
    let amount = 0;
    // loop through myChange and currency sum
    while (myChange >= currencyUnit[cur] && curSum > 0) {
      amount += currencyUnit[cur];
      myChange -= currencyUnit[cur];
      curSum -= currencyUnit[cur];
    }
    // if my amount is not equal to zero, then push change and divide amount with 100
    if (amount !== 0) {
      change.push([cur, amount / 100]);
      }
     });
  // if myChange is more than 0, then, return to "INSUFFICIENT_FUNDS" and change to empty array
   if (myChange > 0) {
     return {status: "INSUFFICIENT_FUNDS", change: []} 
   } else if (myChange === 0 && myChangeCheck === cidSum) {
     status = "CLOSED", change = cid
   } else {
     status = "OPEN"
   }
  //  return status and change
   return {"status": status, "change": change};
}

console.log(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]]));
5 Likes

I made it earlier and didn’t think about just multiplying everything with 100, so I used .toFixed(2) :melting_face:

function checkCashRegister(price, cash, cid) {
  
  function isEmpty(remainingFunds) {
    //checks whether every value in the object == 0
    for (let item in remainingFunds) {
      if (Number(remainingFunds[item].toFixed(2)) !== 0) {
        return false;
      }
    }
    return true;
  }

  function calculatePossibleChange(due, remainingFunds) {
    let change = [];
    const CURRENCY = [
      ["ONE HUNDRED", 100],
      ["TWENTY", 20],
      ["TEN", 10],
      ["FIVE", 5],
      ["ONE", 1],
      ["QUARTER", 0.25],
      ["DIME", 0.1],
      ["NICKEL", 2.05],
      ["PENNY", 0.01]
    ]

    CURRENCY.forEach(([unit, value]) => {
      let changeOfSlot = 0;
      while (due >= value && remainingFunds[unit]) {
        changeOfSlot += value;
        due -= value;
        due = due.toFixed(2);
        remainingFunds[unit] -= value;
      }
      if (changeOfSlot !== 0) {
        change.push([unit, changeOfSlot]);
      }
    })
    return [change, due];
  }


  //make an object with the available funds
  const remainingFunds = {};
  cid.forEach(([unit, amount]) => remainingFunds[unit] = amount);

  //calculate possible change
  let [change, due] = calculatePossibleChange(cash - price, remainingFunds);
  const finalChange = change.map(([_, value]) => [_, value]);

  if (due > 0) {  
    //not enough money or units don't fit
    return { status: "INSUFFICIENT_FUNDS", "change": [] };
  }
  else if (isEmpty(remainingFunds)) {  
    //enough money to give change out but no money remaining
    return { status: "CLOSED", "change": cid }
  }
  else {  
    //enough money with rest
    return { status: "OPEN", "change": finalChange }
  }
}
5 Likes

Nice one @Tzerio ,

Well done! I’ve never used

.toFixed

seems like a smart move. Pat Pat!:clap:

Happy coding!

1 Like

Hi Ramón and all!!!

This is the solution I submitted to get my certification, but I wanted to clean it up a bit, because it is too complex to read and also I know have to do better. It was my first solution.

I still didn’t have much time to get back to my projects, sorry. Anyway I hope it helps someone.

function checkCashRegister(price, cash, cid) {

  const currencyInPenniesObj = {
    "ONE HUNDRED": 10000,
    "TWENTY": 2000,
    "TEN": 1000,
    "FIVE": 500,
    "ONE": 100,
    "QUARTER": 25,
    "DIME": 10,
    "NICKEL": 5,
    "PENNY": 1
  };

  let returnedCashArray = [];

  let cashDueInPennies = (cash - price) * 100;
 
  const totalChangeInDrawerInPennies = cid.filter(withoutChange => withoutChange[1])
    .map(currency => currency[1])
    .reduce((sum, money) => ((sum + money)), 0)
    .toFixed(2) * 100;
  
  const arrayOfCents = cid
    .filter(withoutChange => withoutChange[1])
    .map(cash => [cash[0], cash[1] * 100])
    .reverse();

  if (totalChangeInDrawerInPennies === cashDueInPennies) { return { status: "CLOSED", change: cid }; }

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

  for (let currency of arrayOfCents) {

    let count = 0;
    let cashName = currency[0];
    let cashInDrawerSubarr = currency[1];
    let currencyInPennies = currencyInPenniesObj[cashName];

    if (cashDueInPennies - currencyInPennies < 0) { continue; };

    while (cashDueInPennies - currencyInPennies >= 0 || currencyInPennies === 0) {
      count += currencyInPennies;

      cashInDrawerSubarr -= currencyInPennies;

      cashDueInPennies -= currencyInPennies;

      if (cashInDrawerSubarr === 0) { break; }

    }

    returnedCashArray.push([cashName, count / 100]);
  }

  if (cashDueInPennies > 0) { return { status: "INSUFFICIENT_FUNDS", change: [] } }

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

Keep the good work people!!!

1 Like

Well done Tzerio!!

It looks like you know what are you doing, eh? :wink:

Congrats, beautiful code too!!

Well I already had time to refactor :rofl:
and then I just came back to my solution and saw
const finalChange = change.map(([_, value]) => [_, value]);
and was like “wait wait wait was is this, isn’t this literally doing nothing relevant?”
But nobody else noticed, it’s fine, my past self surely had a reason for this :sweat_smile:

2 Likes

Hi @Tzerio

Ha ha ha, yeah I did not check yours, but I have something similar too, lol.

It means we are so good that we challenge ourself a bit more, just for fun. :wink: :rofl: :rofl: :rofl:

Happy coding!!

1 Like

My solution is un-optimized, but here it is. If I have time I will come back and change it and re-post hopefully! The need to round off gave me some trouble, I improvised initially when I wrote my solution.

Michael

function checkCashRegister(price, cash, cid) {
  let change = [];
  let totalDue = cash - price;
  let cidSum = cid.reduce((sum, elem) => sum + elem[1], 0);

  console.log(cidSum);

  // if cash < price OR not enough money in the drawer return insufficient funds message
  if (totalDue < 0 || totalDue > cidSum + 0.00001)
    return {
      status: 'INSUFFICIENT_FUNDS',
      change: [],
    };
  // if cash equals price no change is due
  else if (totalDue === 0)
    return {
      status: 'OPEN',
      change,
    };
  // if total change due is equal to the cash in drawer, close drawer
  else if (Math.abs(totalDue - cidSum) < 0.00001)
    return {
      status: 'CLOSED',
      change: cid,
    };

  // now we know the change due is less than the cash in the register so we will
  // try to make change
  const denominations = [100, 50, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];
  let denomIndex = 0;

  // holds the 2-item array to be pushed onto the change array
  let currentDenomChangeArr = [];

  while (totalDue !== 0 && denomIndex <= 9) {
    // check whether we can decrement the change still due by the denomination
    if (totalDue > denominations[denomIndex]) {
      //call first helper function that gets change array entry to be pushed
      currentDenomChangeArr = getBillsOrCoinsAmount(
        denominations[denomIndex],
        totalDue,
        cid
      );

      // push change entry
      if (currentDenomChangeArr[1] !== 0) change.push(currentDenomChangeArr);

      // subtract current amount out of the change still due
      totalDue -= currentDenomChangeArr[1];
    }
    denomIndex++;
  }

  // check whether we were able to make the correct change bringing
  // totalDue down to $0.00
  if (Math.abs(totalDue) < 0.01) {
    return { status: 'OPEN', change: change };
  } else {
    // otherwise return unsuccessful change making activity
    console.log(totalDue);
    return {
      status: 'INSUFFICIENT_FUNDS',
      change: [],
    };
  }
}

// returns how much change of particular bill or coin should be allocated to
// make change
function getBillsOrCoinsAmount(denomination, amtStillDue, cid) {
  let amount = 0;
  let amountAvailableEntry;
  let amountAvailable = 0;
  switch (denomination) {
    case 100:
      return calculateAmount(denomination, 'ONE HUNDRED', amtStillDue, cid);
      break;
    case 50:
      return calculateAmount(denomination, 'FIFTY', amtStillDue, cid);
      break;
    case 20:
      return calculateAmount(denomination, 'TWENTY', amtStillDue, cid);
      break;
    case 10:
      return calculateAmount(denomination, 'TEN', amtStillDue, cid);
      break;
    case 5:
      return calculateAmount(denomination, 'FIVE', amtStillDue, cid);
      break;
    case 1:
      return calculateAmount(denomination, 'ONE', amtStillDue, cid);
      break;
    case 0.25:
      return calculateAmount(denomination, 'QUARTER', amtStillDue, cid);
      break;
    case 0.1:
      return calculateAmount(denomination, 'DIME', amtStillDue, cid);
      break;
    case 0.05:
      return calculateAmount(denomination, 'NICKEL', amtStillDue, cid);
      break;
    case 0.01:
      return calculateAmount(denomination, 'PENNY', amtStillDue + 0.00001, cid);
      break;
    default:
      return 'ERROR';
      break;
  }
}

function calculateAmount(denomination, denomString, amtStillDue, cid) {
  let amount = 0;
  let amountAvailableEntry;
  let amountAvailable = 0;

  amount = Math.floor(amtStillDue / denomination) * denomination;
  amountAvailableEntry = cid.filter((e) => e[0] === denomString);
  if (amountAvailableEntry.length > 0) {
    amountAvailable = amountAvailableEntry[0][1];
    amount = Math.min(amount, amountAvailable);
    return [denomString, amount];
  }
  return [denomString, 0];
}

console.log(
  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],
  ])
);
1 Like

Hi again Michael

Remember that if you select all your code and hit the </> button on the top menu, it will improve the readability of your post. Thank you and good work!!

You are on fire!! :sweat_smile: :ok_hand:

Well, I go there… eventually and with a code that probably owes more to Ramon than it does to me, but I managed it. I have just spent, oh… I guess about three hours trying to figure out why my INSUFFICIENT FUNDS bit wouldn’t work for me and then I realised that what was required was INSUFFICIENT_FUNDS. Oh well, such is life!

//MONEYVALS is an oject giving the value of the various denominations in cents
const MONEYVALS={
  "ONE HUNDRED": 10000,
  TWENTY: 2000,
  TEN: 1000,
  FIVE: 500,
  ONE: 100,
  QUARTER: 25,
  DIME: 10,
  NICKEL: 5,
  PENNY: 1
}

function checkCashRegister(price, cash, cid) {
//these lines are used by the whole function
// work out the amount of change required in cents
  let change = (cash - price) * 100;
//reverse cid so as to have it in the same order as MONEYVALS
  const REVARR = cid.reverse();
//find out how much money is in the till both in total and in each denomination
  let tillAmount = REVARR.reduce((acc, money) => {
    return acc + money[1] * 100
  },0);



//this is the final part although it appears at the beginning

  if (tillAmount === change) {

//reverse cid again so that the required format for the question is realised

    cid.reverse()
    return {status: "CLOSED", change: cid}; 
  }

//this part only works with the insufficient funds and the open categories

//work out the amount of change due in each denomination
//by mapping the name and amount from REVARR

  const changeDue = REVARR.map(([name,amount])=>{

//Set up a variable total to hold the amount of change required

    let total=0

//nameValue holds each value in turn from the MONEYVALS array

    let nameValue = MONEYVALS[name];

//amountCents multiplies the amount in the map function by 100 (note that this cannot be done within the function

    let amountCents = amount*100

//we now need a while loop to calculate how much we can take out of each denomination starting at 100 and working down
//for the while loop to be triggered we need the amountCents variable to be greater than 0 and name value to be <= the 
//value of change

    while (amountCents > 0 && nameValue <= change){

//we then add our nameValue to the total

      total += nameValue;

//subtract it from change and

      change -= nameValue;

//subtract it from the amountCents variable until the while loop is no longer triggered

      amountCents -= nameValue;
      
    }
    return [name,total/100]; //we then return the name of the denomination and the amount in dollars and cents


//We run a filter to take away any denomination and amount that is 0 to satisfy the answer requirements

  }).filter(([,amount]) => amount > 0);


//if our change at the end of the above process has not reached zero we are unable to give change and so
//we return insufficient funds

  if (change > 0) {
    return {status:"INSUFFICIENT_FUNDS",change:[]};

//but if it has reached zero we are able to open the cash register and give the required amount of change

  }
    return {status:"OPEN",change: changeDue}  


}
checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]);

Ramon, thanks for the course buddy.

I am now working on web development learning HTML and CSS.

Cheers everybody,

Bill

2 Likes

Well done William!!

Keep the good work. Nicely done :ok_hand:

Thank you Carlos, I just boxed my code like you suggested. You were such a valuable resource to everyone in this course Carlos! Pat pat

Michael

1 Like

Pat pat Michael!! Thank you very much. :blush:

1 Like

Thank you so much Carlos, good luck to you in your future!

1 Like

And, here is my solution.
Not really efficient but seems to serve the purpose. Thanks, Ramon, for the guidance and the encouragement!

function checkCashRegister(price, cash, cid) {

  //Declaring denomination object to take care of different currency denominations
  const denomination = {
    'PENNY':  1,
    'NICKEL': 5,
    'DIME':   10,
    'QUARTER':  25,
    'ONE': 100,
    'FIVE': 500,
    'TEN':  1000,
    'TWENTY': 2000,
    'ONE HUNDRED':  10000
  };

  //Initializing temp variables
  let status = '';
  let change = [];
  
  //Calculating change to be returned
  let changeToBeReturned = cash - price;
  let changeToBeReturnedInCents = changeToBeReturned * 100;
  
  //Calculating cash available in drawer
  let availableCashInCents = 0;
  for (let k of cid){
    availableCashInCents += k[1] * 100;
  }

  //CLOSED case: Cash available in drawer is equal to the cash to be returned
  if (changeToBeReturnedInCents === availableCashInCents){
    status = 'CLOSED';
    change.length = 0;
    change = [...cid];

  //OPEN case: More cash is available in drawer than is required to be returned  
  }else {
    const cidReversed = [...cid].reverse();

    while (changeToBeReturnedInCents > 0){
      for (let j in cidReversed){
        let key = cidReversed[j][0];
        if(denomination[key] <= changeToBeReturnedInCents){
          let noOfCoins = Math.min(Math.floor(changeToBeReturnedInCents/denomination[key]), (cidReversed[j][1] * 100)/denomination[key]);
          changeToBeReturnedInCents -= (noOfCoins * denomination[key]);
          const arrTemp = [];
          arrTemp.push(key, noOfCoins * (denomination[key]/100));
          status ='OPEN';
          change.push(arrTemp);
        }
      }

      //INSUFFICIENT FUNDS case: Not enough cash is available in the drawer    
      if (changeToBeReturnedInCents > 0){
        status ='INSUFFICIENT_FUNDS';
        change.length = 0;
      }
      break;
    }
  }

  //Collecting and returning result
  const resultObj = {
    status: status,
    change: change
  };

  return resultObj;
}

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