Build a Cash Register

this is a globally defined variable.
This will cause the test to fail because the cid is reset between different testcases without this code running again.
Globally defined variables will only be created and set once at the start when your code is loaded and then never again. So as the test cases run in sequence, your centCid will not get updated and therefore your results will be incorrect.

Please re-write your code so that there is no globally scoped variables that rely on the price or the cid.
Also no globally defined or invoked functions that modify the cid or change-due.
Everything should be triggered when the purchase clicks the purchase button and not before.

I didn’t understand about global variables.
I changed the change code as follows, set the value myself, and checked the value displayed in the console
As before, the test results are fine when I run the test myself, but when I run “Run the test”, the test fails.

  let price = 1.5;
  let cid = [
  ['PENNY', 0.11],
  ['NICKEL', 0],
  ['DIME', 0.3],
  ['QUARTER', 0],
  ['ONE', 1],
  ['FIVE', 1],
  ['TEN', 1],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0]
];

// Reset #change-due
const resetChangeDue = (changeHundred, changeTwenty, changeTen, changeFive, changeOne, changeQuarter, changeDime, changeNickel, changePenny) => {

  changeHundred.innerHTML = '';
  changeTwenty.innerHTML = '';
  changeTen.innerHTML = '';
  changeFive.innerHTML = '';
  changeOne.innerHTML = '';
  changeQuarter.innerHTML = '';
  changeDime.innerHTML = '';
  changeNickel.innerHTML = '';
  changePenny.innerHTML = '';
};

// Check register cash's count
const checkRegister = (availableCid) => {

  const hundredIndex = availableCid.findIndex(coin => coin[0] === 'ONE HUNDRED');
  const twentyIndex = availableCid.findIndex(coin => coin[0] === 'TWENTY');
  const tenIndex = availableCid.findIndex(coin => coin[0] === 'TEN');
  const fiveIndex = availableCid.findIndex(coin => coin[0] === 'FIVE');
  const oneIndex = availableCid.findIndex(coin => coin[0] === 'ONE');
  const quarterIndex = availableCid.findIndex(coin => coin[0] === 'QUARTER');
  const dimeIndex = availableCid.findIndex(coin => coin[0] === 'DIME');
  const nickelIndex = availableCid.findIndex(coin => coin[0] === 'NICKEL');
  const pennyIndex = availableCid.findIndex(coin => coin[0] === 'PENNY');

  // Now you can access the coin name using index 0
  const hundred = availableCid[hundredIndex][1];
  const twenty = availableCid[twentyIndex][1];
  const ten = availableCid[tenIndex][1];
  const five = availableCid[fiveIndex][1];
  const one = availableCid[oneIndex][1];
  const quarter = availableCid[quarterIndex][1];
  const dime = availableCid[dimeIndex][1];
  const nickel = availableCid[nickelIndex][1];
  const penny = availableCid[pennyIndex][1];

  return {
    hundred,
    twenty,
    ten,
    five,
    one,
    quarter,
    dime,
    nickel,
    penny
  };
};

// Check coin pattern
const checkCoinPattern = (availableCid, difference) => {
  let cashStock = checkRegister(availableCid);

  let numHundred = 0;
  let numTwenty = 0;
  let numTen = 0;
  let numFive = 0;
  let numOne = 0;
  let numQuarter = 0;
  let numDime = 0;
  let numNickel = 0;
  let numPenny = 0;
  let leftHundred = cashStock.hundred;
  let leftTwenty = cashStock.twenty;
  let leftTen = cashStock.ten;
  let leftFive = cashStock.five;
  let leftOne = cashStock.one;
  let leftQuarter = cashStock.quarter;
  let leftDime = cashStock.dime;
  let leftNickel = cashStock.nickel;
  let leftPenny = cashStock.penny;
  let changeFlg = false;

  // Calc cash
  if (difference >= 10000 && cashStock.hundred >= 10000) {
    if (difference <= cashStock.hundred) {
      numHundred = Math.floor(difference / 10000) * 10000;
    } else {
      numHundred = cashStock.hundred;
    }
      difference = difference - numHundred;
      leftHundred = cashStock.hundred - numHundred;
    }

    if (difference >= 2000 && cashStock.twenty >= 2000) {
      if (difference <= cashStock.twenty) {
        numTwenty = Math.floor(difference / 2000) * 2000;
      } else {
        numTwenty = cashStock.twenty;
      }
        difference = difference - numTwenty;
        leftTwenty = cashStock.twenty - numTwenty; 
    }

    if (difference >= 1000 && cashStock.ten >= 1000) {
      if (difference <= cashStock.ten) {
        numTen = Math.floor(difference / 1000) * 1000;
      } else {
        numTen = cashStock.ten;
      }
      difference = difference - numTen;
      leftTen = cashStock.ten - numTen;
    }

    if (difference >= 500 && cashStock.five >= 500) {
      if (difference <= cashStock.five) {
        numFive = Math.floor(difference / 500) * 500;
      } else {
        numFive = cashStock.five;
      }
        difference = difference - numFive;
        leftFive = cashStock.five - numFive;
      }
      
      if (difference >= 100 && cashStock.one >= 100) {
        if (difference <= cashStock.one) {
            numOne = Math.floor(difference / 100) * 100;
        } else {
          numOne = cashStock.one ;
        }
          difference = difference - numOne;
          leftOne = cashStock.one - numOne;
        }

        if (difference >= 25 && cashStock.quarter >= 25) {
          if (difference <= cashStock.quarter) {
            numQuarter = Math.floor(difference / 25) * 25;
          } else {
            numQuarter = cashStock.quarter;
          }
          difference = difference - numQuarter;
          leftQuarter = cashStock.quarter - numQuarter;
        }

        if (difference >= 10 && cashStock.dime >= 10) {
          if (difference <= cashStock.dime) {
            numDime = Math.floor(difference / 10) * 10;
          } else {
              numDime = cashStock.dime;
          }
          difference = difference - numDime;
          leftDime = cashStock.dime - numDime;
        }

        if (difference >= 5 && cashStock.nickel >= 5) {
          if (difference <= cashStock.nickel) {
              numNickel = Math.floor(difference / 5) * 5;
          } else {
            numNickel = cashStock.nickel;
          }
          difference = difference - numNickel;
          leftNickel = cashStock.nickel - numNickel
        }

        if (difference >= 1 && cashStock.penny >= 1) {
          if (difference <= cashStock.penny) {
            numPenny = difference;
          } else {
            numPenny = cashStock.penny;
          }
          difference = difference - numPenny;
          leftPenny = cashStock.penny - numPenny;
        }

        console.log("残りのおつり¢",difference);
        
        if (difference > 0) {
          changeFlg = false;
        } else {
          changeFlg = true;
        }

        return {
        numHundred,
        numTwenty,
        numTen,
        numFive,
        numOne,
        numQuarter,
        numDime,
        numNickel,
        numPenny,
        leftHundred,
        leftTwenty,
        leftTen,
        leftFive,
        leftOne,
        leftQuarter,
        leftDime,
        leftNickel,
        leftPenny,
        changeFlg
      };
};

window.onload = function() {
  let purchaseBtnCount = 0;
  let availableCid = [];
  let totalCid = 0;

  // get HTMl elements
  const changeStatus = document.getElementById('change-status');
  const changeHundred = document.getElementById('change-hundred');
  const changeTwenty = document.getElementById('change-twenty');
  const changeTen = document.getElementById('change-ten')
  const changeFive = document.getElementById('change-five');
  const changeOne = document.getElementById('change-one');
  const changeQuarter = document.getElementById('change-quarter');
  const changeDime = document.getElementById('change-dime');
  const changeNickel = document.getElementById('change-nickel');
  const changePenny = document.getElementById('change-penny');

  const cash = document.getElementById('cash');

  const purchaseBtn = document.getElementById('purchase-btn');
  const priceElement = document.getElementById('price');
  const drawerPennies = document.getElementById('drawer-pennies');
  const drawerNickels = document.getElementById('drawer-nickels');
  const drawerDimes = document.getElementById('drawer-dimes');
  const drawerQuarters = document.getElementById('drawer-quarters');
  const drawerOnes = document.getElementById('drawer-ones');
  const drawerFives = document.getElementById('drawer-fives');
  const drawerTens = document.getElementById('drawer-tens');
  const drawerTwenties = document.getElementById('drawer-twenties');
  const drawerHundreds = document.getElementById('drawer-hundreds');

  // Display price
  priceElement.innerHTML = `<p>Price: $${price}</p>`;

  // Display drawer
  const penny = cid.find(coin => coin[0] === 'PENNY');
drawerPennies.innerHTML = `<p>Pennies: $${penny[1]}</p>`;
  const nickel = cid.find(coin => coin[0] === 'NICKEL');
drawerNickels.innerHTML = `<p>Nickels: $${nickel[1]}</p>`;
  const dime = cid.find(coin => coin[0] === 'DIME');
drawerDimes.innerHTML = `<p>Dimes: $${dime[1]}</p>`;
  const quarter = cid.find(coin => coin[0] === 'QUARTER');
drawerQuarters.innerHTML = `<p>Quarters: $${quarter[1]}</p>`;
  const one = cid.find(coin => coin[0] === 'ONE');
drawerOnes.innerHTML = `<p>Ones: $${one[1]}</p>`;
  const five = cid.find(coin => coin[0] === 'FIVE');
drawerFives.innerHTML = `<p>Fives: $${five[1]}</p>`;
  const ten = cid.find(coin => coin[0] === 'TEN');
drawerTens.innerHTML = `<p>Tens: $${ten[1]}</p>`;
  const tenty = cid.find(coin => coin[0] === 'TWENTY');
drawerTwenties.innerHTML = `<p>Twenties: $${tenty[1]}</p>`;
  const hundred = cid.find(coin => coin[0] === 'ONE HUNDRED');
drawerHundreds.innerHTML = `<p>Hundreds: $${hundred[1]}</p>`;

  purchaseBtn.addEventListener('click', () => {
    // let availableCid = [];
    // To avoid decimal calculations, convert cid to cents.
    let centCid = cid.map(([coin, amount]) => {
    let decimalAmount = new Decimal(amount);
    let decimalCid = decimalAmount.mul(100);
    return [coin, decimalCid.toNumber()];
    });
console.log(centCid);

    // Reset display change
    resetChangeDue(changeHundred, changeTwenty, changeTen, changeFive, changeOne, changeQuarter, changeDime, changeNickel, changePenny);

    const sentCash = new Decimal(cash.value).mul(100).toNumber();
    const sentPrice = new Decimal(price).mul(100).toNumber();
console.log("受取金額¢", sentCash);
console.log("値段¢", sentPrice);

    // Check inputted cash
    // Not enough cash
    if (sentCash < sentPrice) {
      alert('Customer does not have enough money to purchase the item');
    }
    // No cash
    if (sentCash === sentPrice) {
      changeStatus.innerHTML = '<p>No change due - customer paid with exact cash</p>';
    }

    // Calcurate cash
    if (sentCash > sentPrice) {
      purchaseBtnCount++;

      if (purchaseBtnCount > 1) {
        availableCid = availableCid.slice();

      } else {
        availableCid = centCid.slice();
      }
    
      totalCid = parseFloat(availableCid.reduce((total, coin) => total + coin[1], 0));
      //console.log("レジ(¢)",availableCid);
console.log(centCid);

      // Calcurate register total
      //let difference =  Math.floor((cash - price).toFixed(2) * 100) ;
      let difference =  sentCash - sentPrice;
console.log("おつり¢",difference);

      // Check lack of change
      if (difference > totalCid) {
        changeStatus.innerHTML = '<p>Status: INSUFFICIENT_FUNDS </p>';
console.log(difference , totalCid);
      } else {
        let result = checkCoinPattern(availableCid, difference);
console.log("計算結果", result);

        // Check coin pattern
        if (!result.changeFlg) {
          // Enable to return change
          changeStatus.innerHTML = '<p>Status: INSUFFICIENT_FUNDS </p>';
        // Return changes
        } else {
          // Display #change-due
          result.numHundred >= 10000 ? 
          changeHundred.innerHTML = `<p>ONE HUNDRED: $${result.numHundred / 100} </p>` : '';

          result.numTwenty >= 2000 ? 
            changeTwenty.innerHTML = `<p>TWENTY: $${result.numTwenty / 100} </p>` : '';

          result.numTen >= 1000 ? 
            changeTen.innerHTML = `<p>TEN: $${result.numTen / 100} </p>` : '';

          result.numFive >= 500 ? 
            changeFive.innerHTML = `<p>FIVE: $${result.numFive / 100} </p>` : '';
      
          result.numOne >= 100 ? 
            changeOne.innerHTML = `<p>ONE: $${result.numOne / 100} </p>` : '';
      
          result.numQuarter >= 25 ? 
            changeQuarter.innerHTML = `<p>QUARTER: $${result.numQuarter / 100} </p>` : '';
      
          result.numDime >= 10 ? 
            changeDime.innerHTML = `<p>DIME: $${result.numDime / 100} </p>` : '';
      
          result.numNickel >= 5 ? 
            changeNickel.innerHTML = `<p>NICKEL: $${result.numNickel / 100} </p>` : '';
      
          result.numPenny >= 1 ? 
            changePenny.innerHTML = `<p>PENNY: $${result.numPenny / 100} </p>` : '';

          // Update drawer
          drawerPennies.innerHTML = `<p>Pennies: $${result.leftPenny / 100} </p>`;

          drawerNickels.innerHTML = `<p>Nickels: $${result.leftNickel / 100} </p>`;

          drawerDimes.innerHTML = `<p>Dimes: $${result.leftDime / 100} </p>`;

          drawerQuarters.innerHTML = `<p>Quarters: $${result.leftQuarter / 100} </p>`;

          drawerOnes.innerHTML = `<p>Ones: $${result.leftOne / 100} </p>`;

          drawerFives.innerHTML = `<p>Fives: $${result.leftFive / 100} </p>`;

          drawerTens.innerHTML = `<p>Tens: $${result.leftTen / 100} </p>`;

          drawerTwenties.innerHTML = `<p>Twenties: $${result.leftTwenty / 100} </p>`;

          drawerHundreds.innerHTML = `<p>Hundreds: $${result.leftHundred / 100} </p>`;

          availableCid = [
            ['PENNY', result.leftPenny],
            ['NICKEL', result.leftNickel],
            ['DIME', result.leftDime],
            ['QUARTER', result.leftQuarter],
            ['ONE', result.leftOne],
            ['FIVE', result.leftFive],
            ['TEN', result.leftTen],
            ['TWENTY', result.leftTwenty],
            ['ONE HUNDRED', result.leftHundred]
          ];

          // Change Status
          if (sentPrice < sentCash && totalCid - difference > 0) { 
            changeStatus.innerHTML = '<p>Status: OPEN </p>';
          } else if (sentPrice < sentCash && difference === totalCid) {
            changeStatus.innerHTML = '<p>Status: CLOSED </p>';
          }
        }
      }
    }
    // Clear inputed cash
    cash.value = '';
  });
};

Check1.
cid = [ [‘PENNY’, 1.01], [‘NICKEL’, 205], [‘DIME’, 3.10], [‘QUARTER’, 4.25], [‘ONE’, 90], [‘FIVE’, 550], [‘TEN’, 20], [‘TWENTY’, 60], [‘ONE HUNDRED’, 100] ];
price = 3.26
The following cases were run consecutively

cach = 100 >>> No problems with calculation processing and Status.
cach = 100 >>> No problems with calculation processing and Status.
cach = 2.13 >>> No problems. (The alart is displayed.)
cach = 100 >>> No problems with calculation processing and Status.
cach = 150 >>> No problems with Status. (calculation processing wasn’t executed.)
cach = 136.92 >>> No problems with calculation processing and Status.
cach = 6.53 >>> No problems with calculation processing and Status.
Executing “Run the test” with this value of cid, No.14-19 failed.

Check2.
cid = [ [‘PENNY’, 0.5], [‘NICKEL’, 0], [‘DIME’, 0], [‘QUARTER’, 0], [‘ONE’, 0], [‘FIVE’, 0], [‘TEN’, 0], [‘TWENTY’, 0], [‘ONE HUNDRED’, 0] ];
price = 19.6
The following cases were run.
cach = 20 >>> No problems with calculation processing and Status.

And then, the following cases were run consecutively.
cach = 19.6 >>> No problems with calculation processing and Status.
cach = 19.51 >>> No problems with calculation processing and Status.
cach = 19.89 >>> No problems with calculation processing and Status.

Executing “Run the test” with this value of cid, No.13-19 failed.
(Just by changing the value of cid, No.13 fail anew…)

Check3.
cid = [ [‘PENNY’, 0.01], [‘NICKEL’, 0], [‘DIME’, 0], [‘QUARTER’, 0], [‘ONE’, 0], [‘FIVE’, 0], [‘TEN’, 0], [‘TWENTY’, 0], [‘ONE HUNDRED’, 0] ];
price = 19.5
The following cases were run consecutively

cach = 20>>> No problems Status.
cach = 19.6 >>> No problems Status.
cach = 19.51 >>> No problems with calculation processing and Status.

Executing “Run the test” with this value of cid, No.13-19 failed.

Check4.
cid = [ [‘PENNY’, 1.01], [‘NICKEL’, 0], [‘DIME’, 0.3], [‘QUARTER’, 0], [‘ONE’, 1], [‘FIVE’, 1], [‘TEN’, 1], [‘TWENTY’, 0], [‘ONE HUNDRED’, 0] ];
price = 1.5

cach = 2.61>>> No problems with calculation processing and Status.

Executing “Run the test” with this value of cid, No.13-19 failed.

not sure how you’ve re-written it but it still doesn’t work with the tests.

To see an example, copy and paste the code below to the very bottom of your js file

price = 19.5;
cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]];
cash.value = 20;
document.querySelector('#purchase-btn').click();

This code emulates the test script. It sets the price, the cid and the cash.value and then it causes a click event on the purchase button.
The change-due should change to show the INSUFFICIENT_FUNDS but it doesn’t.
Somehow the click is never registers.

I pasted the code I received at the bottom and ran the “Run the test” and the cid was updated.

However, I also checked the values of cid, price, difference (the variable that stores the change), numHundred~numPenny, and leftHundred~leftPenny by outputting them all to the console,
When the value of cid was changed, the value of leftHundred~leftPenny was not updated, resulting in inaccurate output.

When I manually run the same values, there is no problem.
I’m wondering if the cashStock in the checkCoinPattern function is doing something wrong,
Why is this situation happening in the case of automated test execution? I am not sure why this is happening in the case of an automated test run,
I don’t know how to solve this problem because I don’t know the reason.

When the following values are initially inserted into cid, even if the value of cash is different, the output will be fine.
centCid [
[ ‘PENNY’, 101 ],
[ ‘NICKEL’, 205 ],
[ ‘DIME’, 310 ],
[ ‘QUARTER’, 425 ],
[ ‘ONE’, 9000 ],
[ ‘FIVE’, 5500 ],
[ ‘TEN’, 2000 ],
[ ‘TWENTY’, 6000 ],
[ ‘ONE HUNDRED’, 10000 ] ]

After the cid value is updated, for some reason, completely unrelated values for numHundred~numPenny and leftHundred~leftPenny suddenly appear in the cid.
centCid [

the tests run in sequence in a script.
so just like the code i showed you but more of it

your code is loaded exactly one time and never again, and as I said, the tests are part of script that just runs the purchase button click event with updates to price/cid over and over.

So with this information, please update your code as needed.
You will need to add more logs to track exactly what is the issue.

If I enter it manually myself, there is no problem,
when “Run the test” is executed, I found that the purchaseBtnCount is not initialized when the cid is changed.

I wrote a proxy object to initialize purchaseBtnCount when the cid value is changed, but it does not catch the cid change.
Is it nonsense to try to catch changes in array values?

const originalCid = new Proxy(cid, {
  set: (target, property, value) => {
    target[property] = value;
    purchaseBtnCount = 0;
    console.log('cid has been changed');
    return purchaseBtnCount;
  }
});

I’m sorry I don’t understand your design so I have no comment on it.
I asked you before why you need this purchaseBtnCount?
There is no need for it at all.

The algorithm should be very simple.
You should listen for a button click.
Grab the cash value.
Check the conditions that are described by the testcases then
calculate the change from the cid (while updating it accordingly and managing floating point errors), then
display the results in the order and style requested.

Anything over and above that is just complicating the code and making life harder for you than it needs to be.

I strongly agree that algorithms should be easy!
Also, your comment made me realize that my algorithm was making it more difficult than it needed to be!
Thank you.

I was thinking that the cid should not be changed directly in order to be able to display the first cid value again when reloading.
So, to carry over the remaining money from the previous cashier’s calculation without changing the cid value when calculating the change in succession,
I thought counting by cidpurchaseBtnCount was the simplest algorithm.

Am I first of all wrong in my understanding that the cid value should not be changed directly in the first place?
I’m starting to feel like I’m making a serious mistake… :roll_eyes:

you can definitely change the cid! It is a variable that represents the ‘cash-in-drawer’ so it should contain the current value of the cash in the drawer!

I’m sorry you spent so long on this method to find it doesn’t work with the tests, that is truly unfortunate.
I hope you will have better luck with a re-write.

I’m a little sad to hear this because it bothered me for over a week!

But, thanks to asking about it for the first time, I learned a lot of things, such as

  • How to use the forum
  • Decimal point calculations are subject to errors, so it is better to quit.
  • The variable to be placed in the global variable must be selected.
  • The behavior of the system when run by hand is different from the behavior when automated tests are run.
  • How to debug
  • That there are kind people like you in the forum.

I appreciate your kindness.
I will try to change the code and run the test again!

1 Like

For the global variable issue. You can have some global variables that never change defined. Like the variables for the elements on the page. Just don’t use them for values that change based on price or cid .

1 Like

I was able to pass the test after removing the slice() and purchaseBtnCount from the cid array

Thank you so much!!!

1 Like