Ken Nguyen

Programming Blog

View project on GitHub

Making a Cash Register with JavaScript

03 Jan 2019
programming

I’ve been working through the curriculum at Free Code Camp to learn front end development. Since I already know some HTML and CSS, I spent the majority of my time learning JavaScript. This post is about the solution for last challenge of the JavaScript section, Cash Register.

The Problem

Design a cash register drawer function checkCashRegister() that accepts purchase price as the first argument price, payment as the second argument cash, and cash-in-drawer cid as the third argument.

cid is a 2D array listing available currency.

The function should always return an object with a status key and a change key.

Return {status: 'INSUFFICIENT_FUNDS', change: []} if cash-in-drawer is less than the change due, or if you cannot return the exact change.

Return {status: 'CLOSED', change: [...]} with cash-ind-drawer as the value for the key change if it’s equal to the change due.

Otherwise, return {status: 'OPEN', change: [...]}, with the change due in coins and bills, sorted in highest to lowest order, as the value of the change key.

Sample Test and Output

An example test and answer was given on the challenge:

// Test
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]]);

// Answer
{status: "OPEN", change: [["QUARTER", 0.5]]}

The Solution

From the test, I could see that I needed to find a way to loop through all denominations of bills and coins. The problem specified that the change array should be sorted from highest to lowest. I tried to use an object but immediately ran into the problem or ordering. Since an object is an unordered collection of properties, which is the same as Python’s dictionary.

Two Arrays for Money and Value

So I had to fall back to using two arrays, one for the denominations and the other for the values.

let denom = ['ONE HUNDRED', 'TWENTY', 'TEN', 'FIVE', 'ONE', 'QUARTER', 'DIME', 'NICKEL', 'PENNY'];
let value = [100, 20, 10, 5, 1, .25, .1, .05, .01];

The elements are from highest to lowest order so I do not have to do an extra step of sorting them.

Convert 2D Array to Object

cid is a 2D array, which can be prone to errors if I’m not careful when working with it. An easier way to work with it is to simply convert the cid 2D array into an object. I will also define two variables, total and change, to keep track of the total amount in the register and change left.

let total = 0;
let change = cash - price;

let register = {};
for (let i of cid) {
    total += i[1];
    register[i[0]] = i[1];
}

I run the code now and the result is something like this:

total = 335.40999999999997;
register = {
    PENNY: 1.01,
    NICKEL: 2.05,
    DIME: 3.1,
    QUARTER: 4.25,
    ONE: 90,
    FIVE: 55,
    TEN: 20,
    TWENTY: 60,
    'ONE HUNDRED': 100
}

The total is a bit weird but it’s due to rounding error so I can fix it later. The main point is that I have converted cid into an object.

A Function to Round 2 Decimal Places

Before I go any further, I need to have a way to round the intermediate floats to two decimal places. If I don’t do that, the answer will not work for every test case. The Number.toFixed() method formats a number into string using fixed-point notation. I just need to cast the string back into number again to get what I want:

function twoDecimal(n) {
    return Number(n.toFixed(2));
}

Looping and Subtracting

Now comes the main logic of the function. I defined a cashback object to hold the money subtracted from the register. Then I loop through the value array, if the change is at least the current value and the denomination in the register is not zero, I subtract that from total, change, and register and round the intermediate results.

The cashback object will be increased by the amount of the value if the denomination is already in it. Otherwise, it will create a new key for that denomination with the current value.

let cashback = {};
for (let i = 0; i < value.length; i++) {
    let v = value[i];
    let d = denom[i];

    while (change >= v && register[d] > 0) {
        total = twoDecimal(total - v);
        change = twoDecimal(change - v);
        register[d] -= v;

        if (d in cashback) {
            cashback[d] += v;
        } else {
            cashback[d] = v;
        }
    }
}

Return the Result

Finally, I defined a result object with two keys, status and change as specified by the problem. The status is initially set to OPEN and change set to an empty array.

After the previous loop, if change is greater than 0, that means there’s not enough money in the register. If total is equal to 0, the amount of money in the register equal to the change so I just set result.change equal to cid.

Otherwise, there’s more money in the register than the change. I will push all the keys and values in cashback object to the result.change array and return that.

let result = {status: 'OPEN', change: []};

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

for (let d of denom) {
    if (d in cashback) {
        result.change.push([d, cashback[d]]);
    }
}

A Challenging Problem

I spent quite a bit of time on this problem. With cid being a 2D array, it forced me to use other data structures to makes my job easier. The problem also required me to sort the output from high to low so that’s an additional step I had to think about.

Overall, it’s a decently challenging problem for someone who was just getting started with JavaScript. I had to think of ways to manipulate the data and it taught me a few things about array and object manipulation.

Back to top