exact change challenge
Today I tackled the Exact Change Challenge from Free Code Camp. Some work friends and I discussed this problem over lunch a few days ago and I was eager to get my hands on it.
This solution is my preliminary version. It technically makes all the tests go green, but it is very bulky and has a lot of nesting. My goal is to refactor this in a more declarative, functional style.
I learned some interesting stuff in the process, for example, the native Number.prototype.toFixed()
method in JavaScipt is used to convert a number to a decimal using fixed-point notation. Example use:
5.8484.toFixed(2)
//=> "5.85"
However it returns a string instead of an actual number. So then parseFloat
has to be called on the result.
Oh, silly JavaScript.
But for now here’s today’s post: a solution to the Exact Change Challenge.
var changeMap = {
'ONE HUNDRED': 100.00,
'TWENTY': 20.00,
'TEN': 10.00,
'FIVE': 5.00,
'ONE': 1.00,
'QUARTER': 0.25,
'DIME': 0.10,
'NICKEL': 0.05,
'PENNY': 0.01
};
function getDrawTotal(drawerArray) {
return drawerArray.reduce((acc, cur) => {
return acc + cur[1];
}, 0);
}
function moneyify(number) {
return parseFloat(number.toFixed(2));
}
function checkCashRegister(price, cash, cid) {
var change = [];
var changeDue = moneyify(cash - price);
var drawTotal = moneyify(getDrawTotal(cid));
if (drawTotal < changeDue) {
return 'Insufficient Funds';
}
if (drawTotal === changeDue) {
return 'Closed';
}
var changeDrawer = cid.reverse();
// refactor goal: use a reduce function here instead
changeDrawer.forEach(denom => {
denomName = denom[0];
denomValue = changeMap[denom[0]];
denomStartingAmount = denom[1];
if (changeDue >= denomValue && denomStartingAmount > 0) {
var unitsInDrawer = denomStartingAmount / denomValue;
var denomWithdrawl = [denomName, 0.00];
while (unitsInDrawer && changeDue && denomValue <= changeDue) {
denomWithdrawl[1] += denomValue;
unitsInDrawer -= 1;
changeDue = moneyify(changeDue - denomValue);
}
change.push(denomWithdrawl);
}
});
var result = change.filter(denom => denom[1] > 0.00);
if (moneyify(getDrawTotal(result)) !== moneyify(cash - price)) {
return 'Insufficient Funds';
}
return result;
}
var solution = checkCashRegister(3.26, 100.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]])
console.log(solution)
//=> [ [ 'TWENTY', 60 ],
//=> [ 'TEN', 20 ],
//=> [ 'FIVE', 15 ],
//=> [ 'ONE', 1 ],
//=> [ 'QUARTER', 0.5 ],
//=> [ 'DIME', 0.2 ],
//=> [ 'PENNY', 0.04 ] ]