FreeCodeCamp and JavaScript: Cash Register

So, today I want to look at the challenge that follows Symmetric Difference on FreeCodeCamp, named “Exact Change”.

Here’s the code we’re given to start with:

function checkCashRegister(price, cash, cid) {
  var change;
  // Here is your change, ma’am.
  return change;
}
// Example cash-in-drawer array:
// [[“PENNY”, 1.01],
// [“NICKEL”, 2.05],
// [“DIME”, 3.10],
// [“QUARTER”, 4.25],
// [“ONE”, 90.00],
// [“FIVE”, 55.00],
// [“TEN”, 20.00],
// [“TWENTY”, 60.00],
// [“ONE HUNDRED”, 100.00]]
checkCashRegister(19.50, 20.00, [[“PENNY”, 1.01], [“NICKEL”, 2.05], [“DIME”, 3.10], [“QUARTER”, 4.25], [“ONE”, 90.00], [“FIVE”, 55.00], [“TEN”, 20.00], [“TWENTY”, 60.00], [“ONE HUNDRED”, 100.00]]);

Let’s get the low hanging fruit first.  I know I’m going to need a variable to hold what the total value of the cash in the drawer is.  How to get this value I’ll look at in a little bit; for now, I’ll just give it a value of $0 and call it “totalCashID”.

I also know that I need to know how much change is needed and I’ll call that totChange.  That’s easy to find; it’s just the cash the customer gives me minus the price of the item, or cash – price.

I know that I have some conditional tests, so I’ll set up an if…then…else statement.  First, if the amount of change that is in the drawer (totCashID) is less than the change I need to give, then I return “Insufficient Funds”, else if if the amount of change that is in the drawer (totCashID) is equal to the change I need to give, I return “Closed”, else I process the transaction and return the person’s change, an object sorted according to the values of the change.  I’ll figure out how to calculate change in a little bit.

So what I have so far is:

function checkCashRegister(price, cash, cid) {
  var change;
  // Here is your change, ma’am.
  var totalCashID = 0;
  var totChange = cash – price;
  if (totalCashID < totChange) {
    return “Insufficient Funds”;
  } else if (totalCashID === totChange) {
    return “Closed”;
  } else {
    return change;
  }
  //return change;
}

So let’s figure out how to get the amount of change in the drawer.  What we have is a variable, “cid”, that’s really a multidimensional array.  Looking at the example they give (see above) we see that, for example, the entry for pennies is [“PENNY”, 1.01].  This is sneaky if you don’t know arrays well.  The entry for pennies is an array INSIDE the array cid.  So, we need to access cid, then the first entry in cid (which is element[0] – remember, arrays in javascript begin with 0! – and then the second element (element[1], because…well, I just said why!) of the embedded array which gives us the number and not the word “PENNY”.  So, in code, that’s:

cid[0][1]

We can do this for each of the coins and bills in the drawer, assigning them to a variable.  Then we add up the variables and get the totalChangeID value!  That even passes four of the tests!  Halfway there already!  Here’s what the code looks like now:

function checkCashRegister(price, cash, cid) {
  var change;
  // Here is your change, ma’am.
  var pennies = cid[0][1];
  var nickels = cid[1][1];
  var dimes = cid[2][1];
  var quarters = cid[3][1];
  var ones = cid[4][1];
  var fives = cid[5][1];
  var tens = cid[6][1];
  var twenties = cid[7][1];
  var hundreds = cid[8][1];
  var totalCashID = pennies + nickels + dimes + quarters + ones + fives + tens + twenties + hundreds;
  var totChange = cash – price;
  if (totalCashID < totChange) {
    return “Insufficient Funds”;
  } else if (totalCashID === totChange) {
    return “Closed”;
  } else {
    return change;
  }
  //return change;
}

So, now comes what I consider to be the hardest part: figuring out the change to return to the customer and breaking it down by bills and coins.  It doesn’t seem that difficult; I know that I’m going to use the modulus operator, for example.

So let’s put it into operation and write some code.  One more thing that I’ll point out is that if the amount is less than one you’ll be dividing by a decimal remainder and get ridiculously high amounts so make sure you have an if then statement for whether the change is more than one or less than one.

Here we go:

if (totChange > 1) {
  remainder = totChange % 100;
  hundredsChange = (totChange – (totChange % 100)) / 100;
  twentiesChange = (remainder – (remainder % 20)) / 20;
  remainder = remainder % 20;
  tensChange = (remainder – (remainder % 10)) / 10;
  remainder = remainder % 10;
  fivesChange = (remainder – (remainder % 5)) / 5;
  remainder = remainder % 5;
  onesChange = (remainder – (remainder % 1)) / 1;
  remainder = (remainder % 1) * 100;
  quartersChange = (remainder – (remainder % 25)) / 25;
  remainder = remainder % 25;
  dimesChange = (remainder – (remainder % 10)) / 10;
  remainder = remainder % 10;
  nickelsChange = (remainder – (remainder % 5)) / 5;
  remainder = remainder % 5;
  penniesChange = (remainder – (remainder % 1)) / 1;
  } else {
    remainder = totChange * 100;
  quartersChange = (remainder – (remainder % 25)) / 25;
    //alert(quartersChange);
  remainder = remainder % 25;
  dimesChange = (remainder – (remainder % 10)) / 10;
  remainder = remainder % 10;
  nickelsChange = (remainder – (remainder % 5)) / 5;
  remainder = remainder % 5;
  penniesChange = (remainder – (remainder % 1)) / 1;
  }

There’s a lot of repetition there and if this was the real world I would create a separate function for it.

Now we’ve got the amounts per coin, and we need to assemble it into an array with our old friend push.  Note that trial and error showed me that FreeCodeCamp doesn’t want the number of coins returned; they want the monetary value.  So when I push it to the array below I multiply to get the value.

change.push([“PENNY”, penniesChange * 0.01],[“NICKEL”, nickelsChange * 0.05],[“DIME”, dimesChange * 0.10], [“QUARTER”,quartersChange * 0.25],[“ONE”, onesChange], [“FIVE”, fivesChange], [“TEN”, tensChange], [“TWENTY”, twentiesChange], [“ONE HUNDRED”, hundredsChange]);

However, this still isn’t right.  FreeCodeCamp wants to only return the values of coins if they are greater than zero.  I’ll have to re-write the statement:

    if (penniesChange > 0) change.push([“PENNY”, penniesChange * 0.01]);
    if (nickelsChange > 0) change.push([“NICKEL”, nickelsChange * 0.05]);
    if (dimesChange > 0) change.push([“DIME”, dimesChange * 0.10]);
    if (quartersChange > 0) change.push([“QUARTER”,quartersChange * 0.25]);
    if (onesChange > 0) change.push([“ONE”, onesChange * 1.00]);
    if (fivesChange > 0) change.push([“FIVE”, fivesChange * 5.00]);
    if (tensChange > 0) change.push([“TEN”, tensChange * 10.00]);
    if (twentiesChange > 0) change.push([“TWENTY”, twentiesChange * 20.00]);
    if (hundredsChange > 0) change.push([“ONE HUNDRED”, hundredsChange * 100.00]);

Well, I’m closer.  This would work if the register had unlimited change.  However. in one of the tests I’m getting wrong, the register returns $80.00 in twenties, but there are only $60.00 in twenties in the drawer.  Time to refactor, again.

UPDATE:

Well, I certainly did that the long way around.  There were several things I had wrong in my code, and it took some bashing around to straighten it out.  Here it is, section by section:

function checkCashRegister(price, cash, cid) {
  var change = [];
  var remainder = 0;
  var hundredsChange = 0;
  var twentiesChange = 0;
  var tensChange = 0;
  var fivesChange = 0;
  var onesChange = 0;
  var quartersChange = 0;
  var dimesChange = 0;
  var nickelsChange = 0;
  var penniesChange = 0;
  var bills = 0;
  var coins = 0;
var pennies = cid[0][1];
  var nickels = cid[1][1];
  var dimes = cid[2][1];
  var quarters = cid[3][1];
  var ones = cid[4][1];
  var fives = cid[5][1];
  var tens = cid[6][1];
  var twenties = cid[7][1];
  var hundreds = cid[8][1];
  var totalCashID = pennies + nickels + dimes + quarters + ones + fives + tens + twenties + hundreds;
  var totChange = cash – price;

The opening, of course, and me declaring my multitude of variables that represent what we’re going to give back to the customer.  Then, we have the actual change in the drawer – I explained this above.  Next, we have the if…else if…else statement that I mentioned above.  The contents of the else portion have changed, so I’ll look at those below.

if (totalCashID < totChange) {
    return “Insufficient Funds”;
  } else if (totalCashID === totChange) {
    return “Closed”;
  } else {
     //else portion here
}

Here’s the portion in between the brackets following else:

if (totChange > 1) {
    remainder = totChange % 100;
    hundredsChange = (totChange – (totChange % 100)) / 100;
       if(hundredsChange > hundreds) {
         remainder = remainder + (hundredsChange – hundreds);
         hundredsChange = hundreds;
       }
    twentiesChange = (remainder – (remainder % 20)) / 20;
      if((twentiesChange * 20) > twenties) {
         remainder = (remainder % 20) + ((twentiesChange * 20) – twenties);
         twentiesChange = (twenties / 20);
        } else {
        remainder = remainder % 20;
       }
    tensChange = (remainder – (remainder % 10)) / 10;
      if((tensChange * 10) > tens) {
         remainder = (remainder % 10) + ((tensChange * 10) – tens);
         tensChange = (tens / 10);
        } else {
         remainder = remainder % 10;
              }
    fivesChange = (remainder – (remainder % 5)) / 5;
    if(fivesChange * 5 > fives) {
         remainder = (remainder % 5) + ((fivesChange * 5) – fives);
         fivesChange = fives / 5;
       } else {
         remainder = remainder % 5;
              }
    onesChange = (remainder – (remainder % 1)) / 1;
    if(onesChange > ones) {
         remainder = (remainder % 1) + (onesChange – ones);
         onesChange = ones;
       } else {
         remainder = remainder % 1;
              }
    remainder = (remainder % 1) * 100;
    quartersChange = (remainder – (remainder % 25)) / 25;
    if(quartersChange > quarters) {
         remainder = (remainder % 25) + (quartersChange – quarters);
         quartersChange = quarters;
       } else {
         remainder = remainder % 25;
              }
    dimesChange = (remainder – (remainder % 10)) / 10;
    if(dimesChange > dimes) {
         remainder = (remainder % 10) + (dimesChange – dimes);
         dimesChange = dimes;
       } else {
         remainder = remainder % 10;
              }
    nickelsChange = (remainder – (remainder % 5)) / 5;
    if(nickelsChange > nickels) {
         remainder = (remainder % 5) + (nickelsChange – nickels);
         nickelsChange = nickels;
       } else {
         remainder = remainder % 5;
              }
    penniesChange = Math.ceil(remainder);
  } else {
    remainder = totChange * 100;
    quartersChange = (remainder – (remainder % 25)) / 25;
    if(quartersChange > quarters) {
         remainder = (remainder % 25) + (quartersChange – quarters);
         quartersChange = quarters;
       } else {
         remainder = remainder % 25;
              }
    dimesChange = (remainder – (remainder % 10)) / 10;
    if(dimesChange > dimes) {
         remainder = (remainder % 10) + (dimesChange – dimes);
         dimesChange = dimes;
       } else {
         remainder = remainder % 10;
              }
    nickelsChange = (remainder – (remainder % 5)) / 5;
    if(nickelsChange > nickels) {
         remainder = (remainder % 5) + (nickelsChange – nickels);
         nickelsChange = nickels;
       } else {
         remainder = remainder % 5;
              }
    penniesChange = Math.ceil(remainder);

Now, as I said, I did this the hard way, so let me explain.  There are two parts to the if statement – one if the change required is a dollar or more, and one if the change is less than one dollar.  If this was a professional job, I would make the change a separate function rather than repeat it.  I also had it calculate the number of coins rather than the value of the change; this is why the code is so tortured with conversions.  I would change that too if I was doing this professionally but since I am a learner I want you to see some of the ways I worked to solve it originally.  This also shows there’s more than one way to get to the right answer!

Next, I had to find a way to solve what would happen if I couldn’t give the customer any change despite the fact that I had enough total in the drawer, I just couldn’t divide what I had – so, for example, they should get 13 cents but all I have is one dollar and one nickel.  I have $1.05, but I can’t divide it to make 13 cents.  The test above for insufficient funds doesn’t catch this.  But, if the amount of change I return is greater than the change required, I know I can’t return it.  Thus:

var totalChgGiven = hundredsChange * 100 + twentiesChange * 20 + tensChange * 10 + fivesChange * 5 + onesChange + quartersChange * 0.25 + dimesChange * 0.1 + nickelsChange * 0.05 + penniesChange * 0.01;
    if(+totalChgGiven.toFixed(2) != totChange) {
      return “Insufficient Funds”;
    }

See the toFixed function being used there?  It stymied me for awhile because you need 2 decimal points, which is why I used it, but you get a string back, which is no help at all!  After some web searching, I found that putting a plus sign (+) in front fixes that issue.  So, finally, I need to return the array.  The way I originally did it had it start with the pennies and progress to the hundreds; as it turns out, FreeCodeCamp doesn’t accept that answer and I had to re-arrange it so that it started with hundreds and descended to pennies:

if (hundredsChange > 0) change.push([“ONE HUNDRED”, (hundredsChange * 100.00)]);
    if (twentiesChange > 0) change.push([“TWENTY”, twentiesChange * 20.00]);
    if (tensChange > 0) change.push([“TEN”, (tensChange * 10.00)]);
    if (fivesChange > 0) change.push([“FIVE”, (fivesChange * 5.00)]);
    if (onesChange > 0) change.push([“ONE”, (onesChange * 1.00)]);
    if (quartersChange > 0) change.push([“QUARTER”,(quartersChange * 0.25)]);
    if (dimesChange > 0) change.push([“DIME”, (dimesChange * 0.10)]);
    if (nickelsChange > 0) change.push([“NICKEL”, (nickelsChange * 0.05)]);
    if (penniesChange > 0) change.push([“PENNY”, (penniesChange * 0.01)]);
    return change;
  }
}

And there you have it!  The Exact Change challenge solved.  Note that FreeCodeCamp’s answer uses an object and loops through it, so obviously I could have shortened this quite a bit; as I said though, now you can see that I’m no expert and this is how someone of intermediate knowledge of JavaScript might solve it!

Leave a comment