Post your Cash Register solutions here!

Hey JavaScripters!

Congratulations on finishing the final project of the JavaScript Algorithms and Data Structures certification!

What a journey this has been :purple_heart:

Let’s share our solutions here for the final project!

I’ll share mine shortly after the lesson has ended :slight_smile:

2 Likes

As promised, here’s mine:

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

function checkCashRegister(price, cash, cid) {
  const changeDue = (cash - price)
  let changeDueCents = changeDue * 100;
  const available = cid.reduce((acc, [, amount]) => {
    return acc + amount * 100
  }, 0.00);
  if (available === changeDueCents) {
    return {status: "CLOSED", change: cid};
  } 

  const change = cid.reverse().map(([name, amount]) => {
    let total = 0;
    let nameValue = LOOKUP[name];
    let amountCents = amount * 100;
    while (nameValue <= changeDueCents && amountCents > 0) {
        total += nameValue;
        changeDueCents -= nameValue;
        amountCents -= nameValue;
      }
    return [name, total / 100];
  })
  .filter(([, amount]) => amount > 0);

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

you twitter handle again

I’ll post it in a forum post!

Here is mine:

First Try:

I started with the thought that this is similar to the Roman Numerals project. So, I borrowed heavily on Ramón’s code for the Roman Numerals project

class Change {
  constructor(totalDue) {
    this.due = totalDue;
    this.change = [];
  }

  calcUnits(unit, unitValue, cidValue) {
    let due100 = this.due * 100;
    let unitValue100 = unitValue * 100;
    let cidValue100 = cidValue * 100;
    let unitTotal100 = 0;

    while (due100 >= unitValue100 && cidValue100 > 0) {
      unitTotal100 += unitValue100;
      cidValue100 -= unitValue100;
      due100 -= unitValue100;
    }
    
    if (unitTotal100 > 0) {
      this.change.push([unit, unitTotal100 / 100]);
      this.due = (Math.round(due100) / 100);
      
    };
  
  }
}

function checkCashRegister(price, cash, cid) {

  let changeDue = cash - price;
  let cidSum = 0;

  for (let i = 0; i < cid.length; i++) {cidSum += cid[i][1]};
	  if (changeDue === cidSum) {
	  return {status: "CLOSED", change: cid};
  }

  let change = new Change(changeDue);

  change.calcUnits("ONE HUNDRED", 100, cid[8][1]);
  change.calcUnits("TWENTY", 20, cid[7][1]);
  change.calcUnits("TEN", 10, cid[6][1]);
  change.calcUnits("FIVE", 5, cid[5][1]);
  change.calcUnits("ONE", 1, cid[4][1]);
  change.calcUnits("QUARTER", 0.25, cid[3][1]);
  change.calcUnits("DIME", .1, cid[2][1]);
  change.calcUnits("NICKEL", .05, cid[1][1]);
  change.calcUnits("PENNY", .01, cid[0][1]);

  if (change.due !== 0){
    return {status: "INSUFFICIENT_FUNDS", change: []}
  }

  else {
    return {status: "OPEN", change: change.change};
  }
  
}

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

Version Two:

After completing the first version I thought what if I approached it from a cid point of view. You could say the previous version had a change point of view.

What I should have done:

  • I wanted to use the reduce method but I could not get it to work, kept getting funny results. As I was running out of time, I used a for loop. In the class I realised I was not specifying the initial value. Can’t believe I forgot that.

  • I should have remembered about the spread and the destructuring stuff.

class Change {

  constructor(totalDue) {
    this.due = totalDue;
    this.change = [];
    this.currVals = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];
  }

  calcChange(cash) {

    let units = 0;
    let unitsVal = 0;
    let changeVal = 0;

    for (let i = 0; i < cash.length; i++) {

      if (this.currVals[i] < this.due){
        units = Math.trunc(this.due / this.currVals[i]);
        unitsVal = units * this.currVals[i];
        changeVal = unitsVal > cash[i][1] ? cash[i][1] : unitsVal;
        this.due = Math.round((this.due - changeVal) * 100) / 100;
        this.change.push([cash[i][0], changeVal]);
      }

    }
  }
}


function checkCashRegister(price, cash, cid) {

  let changeDue = cash - price;
  let cidSum = 0;

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

  if (changeDue === cidSum) {
    return {status: "CLOSED", change: cid};
  }

  let cidReverse = cid.reverse();

  let change = new Change(changeDue);

  change.calcChange(cidReverse);

  if (change.due !== 0) {
    return {status: "INSUFFICIENT_FUNDS", change: []}
  }

  else {
    return {status: "OPEN", change: change.change};
  }

}

console.log(checkCashRegister(19.5, 20, [["PENNY", .01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE",0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]));

3 Likes

Mine was kind of verbose this time :cactus:

const sumCID = (cid) =>{
  let sum = 0;
  for (let i = 0; i<cid.length; i++){
    sum += cid[i][1];
  }
  return parseFloat(sum.toFixed(2));
}

function checkCashRegister(price, cash, cid) {
  let changeCash = cash - price;
  let change = [];
  let cidCash = [...cid]; //Copy cid so we don't change it when no needed
  const cashName=[
            ["PENNY", 0.01], 
            ["NICKEL", 0.05], 
            ["DIME", 0.1], 
            ["QUARTER", 0.25], 
            ["ONE", 1], 
            ["FIVE", 5], 
            ["TEN", 10], 
            ["TWENTY", 20], 
            ["ONE HUNDRED", 100]
          ];
  if (changeCash > sumCID(cidCash)) {
    return {status: "INSUFFICIENT_FUNDS", change: []}
  }
  else if (changeCash == sumCID(cidCash)) {
    return {status: "CLOSED", change: cid}
  }
  else {
    for (let i = cidCash.length-1; i>=0; i--){
      let changeDeb = 0;
      
      while (changeCash.toFixed(2) >= cashName[i][1] && cid[i][1] >= cashName[i][1]){
        changeCash -= cashName[i][1];
        changeDeb += cashName[i][1];
        cid[i][1] -= cashName[i][1];
      }
      
      if (changeDeb != 0){
        change.push([cashName[i][0], changeDeb]);
      }
    }
    
    if (changeCash > 0){
      return {status: "INSUFFICIENT_FUNDS", change: []}
    } else {
      cid = cidCash;
      return {status: "OPEN", change: change};
    }
  }
}

let cid=[
          ["PENNY", 1.01],
          ["NICKEL", 2.05],
          ["DIME", 3.1],
          ["QUARTER", 4.25],
          ["ONE", 90],
          ["FIVE", 55],
          ["TEN", 20],
          ["TWENTY", 60],
          ["ONE HUNDRED", 100]
        ];

console.log(checkCashRegister(19.5, 20, cid));
1 Like

Here’s mine. It works but it’s a lot longer. I still have trouble thinking of applying js methods when thinking of solutions.
Kind of ‘meh’ pat pat :confused:

function checkCashRegister(price, cash, cid) {

  // create an object to keep track of the money
  // (subtracting how much is being given)
  const myCID = {
    "ONE HUNDRED": 0,
    "TWENTY": 0,
    "TEN": 0,
    "FIVE": 0,
    "ONE": 0,
    "QUARTER": 0,
    "DIME": 0,
    "NICKEL": 0,
    "PENNY": 0
  };

  // create an object to keep track of the money that is being given in change
  // (adding how much is being given of each coin)
  const openCID = {
    "ONE HUNDRED": 0,
    "TWENTY": 0,
    "TEN": 0,
    "FIVE": 0,
    "ONE": 0,
    "QUARTER": 0,
    "DIME": 0,
    "NICKEL": 0,
    "PENNY": 0
  };

  // convert the cid into the object
  // multiply by 100 to have ints instead of floats
  for (let i = 0; i < cid.length; i++) {
    myCID[cid[i][0]] = cid[i][1] * 100;
  }

  // calculate how much is owed, in cents (*100)
  let amountDue = (cash - price) * 100;

  // keep subtracting while there's money owed and there's money in the myCID
  // also, add the amount given to openCID
  while (amountDue >= 10000 && myCID["ONE HUNDRED"] > 0) {
    amountDue -= 10000;
    myCID["ONE HUNDRED"] -= 10000;
    openCID["ONE HUNDRED"] += 100;
  }

  while (amountDue >= 2000 && myCID["TWENTY"] > 0) {
    amountDue -= 2000;
    myCID["TWENTY"] -= 2000;
    openCID["TWENTY"] += 20;
  }

  while (amountDue >= 1000 && myCID["TEN"] > 0) {
    amountDue -= 1000;
    myCID["TEN"] -= 1000;
    openCID["TEN"] += 10;
  }

  while (amountDue >= 500 && myCID["FIVE"] > 0) {
    amountDue -= 500;
    myCID["FIVE"] -= 500;
    openCID["FIVE"] += 5;
  }

  while (amountDue >= 100 && myCID["ONE"] > 0) {
    amountDue -= 100;
    myCID["ONE"] -= 100;
    openCID["ONE"] += 1;
  }

  while (amountDue >= 25 && myCID["QUARTER"] > 0) {
    amountDue -= 25;
    myCID["QUARTER"] -= 25;
    openCID["QUARTER"] += 0.25;
  }

  while (amountDue >= 10 && myCID["DIME"] > 0) {
    amountDue -= 10;
    myCID["DIME"] -= 10;
    openCID["DIME"] += 0.10;
  }

  while (amountDue >= 5 && myCID["NICKEL"] > 0) {
    amountDue -= 5;
    myCID["NICKEL"] -= 5;
    openCID["NICKEL"] += 0.05;
  }

  while (amountDue >= 1 && myCID["PENNY"] > 0) {
    amountDue -= 1;
    myCID["PENNY"] -= 1;
    openCID["PENNY"] += 0.01;
  }

  // create the object for the result
  const result = {
    "status": "INSUFFICIENT_FUNDS",
    "change": []
  }

  // if the client is still owed money
  if (amountDue > 0) {
    return result;
  }

  // if no money is owed...
  else if (amountDue === 0) {

    // check if there's money left on the CID ("CLOSED") or not ("OPEN")
    let tracker = 0;
    for (let key in myCID) {
      if (myCID[key] !== 0) {
        tracker = 1;
      }
    }

    // if there's no money left on the CID
    if (tracker === 0) {
      result.status = "CLOSED",
      result.change = cid;
      return result;
    }

    // if there's money left on the CID
    else {

      // convert the obj openCID to an array
      const change = [];
      for (let key in openCID) {
        const newArr = [];
        if (openCID[key] !== 0) {
          newArr.push(key);
          newArr.push(openCID[key]);
          change.push(newArr);
        }
      }

      result.status = "OPEN";
      result.change = change;
      return result;
    }
  }
}

Absolutely a full on PAT PAT, nice one!

If it works and is clear, it’s all the good! Refactoring comes later where you perhaps DRY things up, or other kind of improvements :purple_heart:

1 Like

Here’s mine.
I added a few more comments to make it clearer before posting it.

I also used “simple stuff” rather than the things we learned recently, because with this kind of exercise, I need most of my brain energy to even figure out how to do the thing itself, there’s no more brain energy left for thinking about using the “new” things, because within the very limited time of this bootcamp, there wasn’t yet time for any of it to sink in, it will take more time and repetitions before I can really use these new methods and stuff.
This week, I constantly had a feeling of “running out of working memory” or “not enough RAM”. (I think this was the busy octopus in the guest session?)
Maybe scheduling 2 weeks for these exercises in future JavaScript bootcamps (if planned) might be a good idea?
I felt my brain was going to explode before the end of the week and I should ask someone to come over at the weekend to clean up the mess of my exploded brain and feed the fish. :rofl:
Well, tomorrow and Friday I will try to finish the 14 exercises of the “Intermediate Algorithm Scripting” that I still have to do.

As for this one, I started out in a similar way as Ramón, but I did not run any tests before I thought everything was finished, so I had to fix the issue of having enough money but not the right coins for the change later.
And as usual, I did most of my thinking with pencil and paper first.

function checkCashRegister(price, cash, cid) {
  //money in Cents for calculations
  const moneyArray = [1,5,10,25,100,500,1000,1000,10000];

  let changeDue = cash - price;
  let result = {status: "INSUFFICIENT_FUNDS", change: []}; 
  let resultAr = []; //will hold change money
  let inRegister = 0;  //sum of what's in register

  // get the sum of a given array
  function arrayTotal(arr, sum) {
    for (let i = 0; i<arr.length; i++) {
      // *100 because odd float behavior
      sum += arr[i][1]*100;
    }
    return sum;
   };
 
  inRegister = arrayTotal(cid, inRegister);
  console.log(inRegister/100, changeDue);

  // if there's less cash in register than change due simply return result
  if (inRegister/100 < changeDue) {
    console.log(result);
    return result;
  } 
  // if cash in register is equal to change due, change result values and return result
  else if (inRegister/100 == changeDue) {
    result.status="CLOSED";
    result.change=[...cid];
    console.log(result);
    return result;
  } 
  // if there is more money than change due
  // calculate the amount in bills/coins available
  else {
      (function() {
        let changeD = changeDue*100;
        for (let i = cid.length-1; i>=0; i--) {
          if (moneyArray[i] < changeD) {
            // compare changeDue (in Cents) to amount of money of this bill/coin in the register
            let tracker = changeD - cid[i][1]*100;
            // if there's enough money of bills/coins of this kind 
            if (tracker >=0) {
              resultAr.push(cid[i]);
              changeD = tracker;
              //console.log(cid[i]);
            } else {    
              // e.g. if change is 80$ and there are only 60$ in "twenty" bills
              let calcul = Math.floor(changeD/moneyArray[i]);
              let miniAr = [cid[i][0], moneyArray[i]*calcul/100]
              changeD -= moneyArray[i]*calcul;
              resultAr.push(miniAr);
              //console.log(miniAr)
            }
          }
        }
      })();
      //if there's more money than change due, but cannot be given with the 
      // bills/coins that are there (added later, because test failed^^)
      if (arrayTotal(resultAr,0)/100 < changeDue ) {
        console.log(result)
        return result;
      }
      //enough money in register and change can be given, 
      // return the resulting change money in bills/coins
       else {
        result.status = "OPEN";
        result.change = [...resultAr];
        console.log(result);
        return 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]]);

By the way, I think it’s okay to go through the ‘pain’, because I’ve heard somewhere that this actually shows your brain is learning new things! :slightly_smiling_face:

2 Likes

Yes, I agree this week was a step up. For the first time I did not finish all the exercises before the class.

I admit defeat on this one. Trying to work stubbornly with floats and fighting with 0.30000000000000004s didn’t go well. So, converting to cents was a brilliant idea, and I think one of the most important takeaways from yesterday’s stream was that work with integers whenever you can.

This could be one of the most inelegant and terrible ways to solve it, but works for the tests. Still, got some Intermediate Algorithm Scripting to do!

function checkCashRegister(price, cash, cid) {
  const currencies = {
    'ONE HUNDRED': 100,
    TWENTY: 20,
    TEN: 10,
    FIVE: 5,
    ONE: 1,
    QUARTER: 0.25,
    DIME: 0.1,
    NICKEL: 0.05,
    PENNY: 0.01
  }
  
  let change = (cash - price) * 100;
  let result = {status: 'OPEN', change: []};

  // Get total available value in drawer
  let total = cid.reduce(function(acc, item) {
    return acc + item[1] * 100;
  }, 0); 

  if (total < change) {
    result.status = 'INSUFFICIENT_FUNDS';
    return result;
  }

  if (total === change) {
    result.status = 'CLOSED';
    result.change = cid;
    return result;
  }

  // Get the cid items into an object, initialize count property 
  // to later keep count for how many times the value will be subtracted
  let inDrawer = {};
  for (let item of cid.reverse()) {
    inDrawer[item[0]] = {value: item[1] * 100, count: 0};
  }

  let keys = (Object.keys(currencies));
  let i = 0; // Initialize index
  let changeRes = {} // Object to hold change due

  while (change > 0) {
    if (i === keys.length + 1 && change > 0) {
      result.status = 'INSUFFICIENT_FUNDS';
      return result;
    }
    // If change is more than a currency value and 
    // the cash in drawer of that currency still exists,
    // subtract the value from both cash and inDrawer
    if (change >= currencies[keys[i]] * 100 && inDrawer[keys[i]].value > 0) {
      change -= currencies[keys[i]] * 100;
      inDrawer[keys[i]].value -= currencies[keys[i]] * 100;
      inDrawer[keys[i]].count++;
      // Get the total value of current currency for the change
      let totalVal = currencies[keys[i]] * inDrawer[keys[i]].count;
      changeRes[keys[i]] = totalVal;
      continue;
    } 
    i++;
  }     

  // Get the change results into the result.change as array
  for (let curr in changeRes) {
    result.change.push([curr, changeRes[curr]]);
  }
  
  return result;
}
1 Like

`function checkCashRegister(price, cash, cid) {
let change = cash - price;
console.log(change);//1st log
let emptyArr = [];
var changeDue = {
“ONE HUNDRED”: 0,
“TWENTY”: 0,
“TEN”: 0,
“FIVE”: 0,
“ONE”: 0,
“QUARTER”: 0,
“DIME”: 0,
“NICKEL”: 0,
“PENNY”: 0
};
let sumChDue = 0;
let cidCopy = cid.slice();
console.log(cidCopy)//2nd log
//compute total cash in drawer
let sumCid = 0;
for (let i = 0; i < cid.length; i++){
sumCid += cid[i][1]
}
sumCid = sumCid.toFixed(2)
console.log(sumCid);//3rd log

//define fxn for the change due
function changedue(chng) {

while ((chng/100) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("ONE HUNDRED"))][1] > 0 ){  
 changeDue["ONE HUNDRED"] += 100;
  cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("ONE HUNDRED"))][1] -= 100;
  chng-=100;
  }
while ((chng/20) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("TWENTY"))][1] > 0){
    changeDue["TWENTY"] = changeDue["TWENTY"] + 20;
    cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("TWENTY"))][1] -= 20;
    chng-=20;}
while ((chng/10) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("TEN"))][1] > 0){
      changeDue["TEN"] = changeDue["TEN"] + 10;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("TEN"))][1] -= 10;
      chng-=10;}
while ((chng/5) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("FIVE"))][1] > 0){
      changeDue["FIVE"] = changeDue["FIVE"] + 5;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("FIVE"))][1] -= 5;
        chng-=5;}
while ((chng/1) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("ONE"))][1] > 0){
      changeDue["ONE"] = changeDue["ONE"] + 1;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("ONE"))][1] -= 1;
      chng-=1;}
while ((chng/0.25) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("QUARTER"))][1] > 0){
      //chng = chng.toFixed(2);
      changeDue["QUARTER"] = changeDue["QUARTER"] + 0.25;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("QUARTER"))][1] -= 0.25;
        chng-=0.25;
        }
while ((chng/0.1) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("DIME"))][1] > 0){
      //chng = chng.toFixed(2);
      changeDue["DIME"] = changeDue["DIME"] + 0.1;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("DIME"))][1] -= 0.1;
      chng-=0.1;}
while ((chng/0.05) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("NICKEL"))][1] > 0){
      //chng = chng.toFixed(2);
      changeDue["NICKEL"] = changeDue["NICKEL"] + 0.05;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("NICKEL"))][1] -= 0.05;
      chng-=0.05;}
while ((chng/0.01) >= 1.0 && cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("PENNY"))][1] > 0.00){
      chng = chng.toFixed(2);
      changeDue["PENNY"] = changeDue["PENNY"] + 0.01;
      cidCopy[cidCopy.findIndex(cidCopy => cidCopy.includes("PENNY"))][1] -= 0.01;
      chng-=0.01;
      }

//remove coins and bills with zero values
for (const [key, value] of Object.entries(changeDue)) {
if (changeDue[key] > 0){
sumChDue += value;
emptyArr.push([key, value]);
}

} console.log(changeDue);
console.log(sumChDue)

return emptyArr;

}//end of changedue function
if (sumCid < change){
return {status: “INSUFFICIENT_FUNDS”, change: []}
}
//else if (sumChDue !== change){
//return {status: “INSUFFICIENT_FUNDS”, change: []}
//}
else if (sumCid == change){
return {status: “CLOSED”, change:cid}
}
else {
return {status:“OPEN”, change: changedue(change)}
}

}// end of checkCashRegister function

Output:
0.5
[ [ ‘PENNY’, 0.01 ],
[ ‘NICKEL’, 0 ],
[ ‘DIME’, 0 ],
[ ‘QUARTER’, 0 ],
[ ‘ONE’, 1 ],
[ ‘FIVE’, 0 ],
[ ‘TEN’, 0 ],
[ ‘TWENTY’, 0 ],
[ ‘ONE HUNDRED’, 0 ] ]
1.01
{ ‘ONE HUNDRED’: 0,
TWENTY: 0,
TEN: 0,
FIVE: 0,
ONE: 0,
QUARTER: 0,
DIME: 0,
NICKEL: 0,
PENNY: 0.01 }
0.01
{ status: ‘OPEN’, change: [ [ ‘PENNY’, 0.01 ] ] }
0.5
[ [ ‘PENNY’, 1.01 ],
[ ‘NICKEL’, 2.05 ],
[ ‘DIME’, 3.1 ],
[ ‘QUARTER’, 4.25 ],
[ ‘ONE’, 90 ],
[ ‘FIVE’, 55 ],
[ ‘TEN’, 20 ],
[ ‘TWENTY’, 60 ],
[ ‘ONE HUNDRED’, 100 ] ]
335.41
{ ‘ONE HUNDRED’: 0,
TWENTY: 0,
TEN: 0,
FIVE: 0,
ONE: 0,
QUARTER: 0.5,
DIME: 0,
NICKEL: 0,
PENNY: 0 }
0.5
{ status: ‘OPEN’, change: [ [ ‘QUARTER’, 0.5 ] ] }`

This was my first try! Quite verbose in deed! but it somehow works, except for one last test which is refusing to fix. Eventually, I had to borrow from Ramon’s solutions. Nonetheless, I was 95% done. Great challenge to get me thinking haaaard! :upside_down_face: :slightly_smiling_face: