freeCodeCamp Algorithm Challenge Guide: Exact Change

freeCodeCamp Algorithm Challenge Guide: Exact Change
0

#1

:triangular_flag_on_post: Remember to use Read-Search-Ask if you get stuck. Try to pair program :busts_in_silhouette: and write your own code :pencil:

:checkered_flag: Problem Explanation:

  • You have to create a program that will handle when the register does not have enough cash or will have no cash after the transaction. Other than that it needs to return an array of the change in the form of an array, so that will be a 2D array.

Relevant Links

:speech_balloon: Hint: 1

  • It is easier to handle if you have to close the register, or if you know how much money is in your register beforehand and you will not have enough money to complete the transaction. For this it is recommended to have a function to assign this information to a variable.

try to solve the problem now

:speech_balloon: Hint: 2

  • Life is easier when you get to know the value of each currency type in the register instead of how much money is composed of that particular currency. So be sure to watch out for that.

try to solve the problem now

:speech_balloon: Hint: 3

  • You will have to get as much change from one type before moving to the next from greater value to lesser, and keep going until you have covered the whole change.

try to solve the problem now

Spoiler Alert!

687474703a2f2f7777772e796f75726472756d2e636f6d2f796f75726472756d2f696d616765732f323030372f31302f31302f7265645f7761726e696e675f7369676e5f322e676966.gif

Solution ahead!

:beginner: Beginner Code Solution:

// Create an object which hold the denominations and their values
var denom = [
  { name: 'ONE HUNDRED', val: 100.00},
  { name: 'TWENTY', val: 20.00},
  { name: 'TEN', val: 10.00},
  { name: 'FIVE', val: 5.00},
  { name: 'ONE', val: 1.00},
  { name: 'QUARTER', val: 0.25},
  { name: 'DIME', val: 0.10},
  { name: 'NICKEL', val: 0.05},
  { name: 'PENNY', val: 0.01}
];

function checkCashRegister(price, cash, cid) {
  var change = cash - price;

  // Transform CID array into drawer object
  var register = cid.reduce(function(acc, curr) {
    acc.total += curr[1];
    acc[curr[0]] = curr[1];
    return acc;
  }, {total: 0});

  // Handle exact change
  if (register.total === change) {
    return 'Closed';
  }

  // Handle obvious insufficent funds
  if (register.total < change) {
    return 'Insufficient Funds';
  }

  // Loop through the denomination array
  var change_arr = denom.reduce(function(acc, curr) {
    var value = 0;
    // While there is still money of this type in the drawer
    // And while the denomination is larger than the change reminaing
    while (register[curr.name] > 0 && change >= curr.val) {
      change -= curr.val;
      register[curr.name] -= curr.val;
      value += curr.val;

      // Round change to the nearest hundreth deals with precision errors
      change = Math.round(change * 100) / 100;
    }
    // Add this denomination to the output only if any was used.
    if (value > 0) {
        acc.push([ curr.name, value ]);
    }
    return acc; // Return the current Change Array
  }, []); // Initial value of empty array for reduce

  // If there are no elements in change_arr or we have leftover change, return
  // the string "Insufficient Funds"
  if (change_arr.length < 1 || change > 0) {
    return "Insufficient Funds";
  }

  // Here is your change, ma'am.
  return change_arr;
}

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

:rocket: Run Code

Code Explanation:

First, the CID array is transformed into a drawer object. Then we handle the conditions of exact change and insufficient funds. Then we loop through the denomination array and update the change and values while there is still money of this type in the drawer and while the denomination is larger than the change reminaing. Then we add this denomination to the output only if any was used. Finally, if there are no elements in change_arr or we have leftover change, return the string “Insufficient Funds”.

Relevant Links

:clipboard: NOTES FOR CONTRIBUTIONS:

  • :warning: DO NOT add solutions that are similar to any existing solutions. If you think it is similar but better, then try to merge (or replace) the existing similar solution.
  • Add an explanation of your solution.
  • Categorize the solution in one of the following categories — Basic, Intermediate and Advanced. :traffic_light:
  • Please add your username only if you have added any relevant main contents. (:warning: DO NOT remove any existing usernames)

See :point_right: Wiki Challenge Solution Template for reference.


Need help with Exact Change Challenge
#2

#3

#4

Here’s another way to solve it. It uses direct calculation instead of a while loop to calculate the change for each denomination.

function checkCashRegister(price, cash, cid) {
  // All amounts are multiplied by 100 until the final result to avoid errors with floating point math
  const denominations = { "PENNY": 1, "NICKEL": 5, "DIME": 10, "QUARTER": 25, "ONE": 100, "FIVE": 500, "TEN": 1000, "TWENTY": 2000, "ONE HUNDRED": 10000 }
  let changeDue = (cash * 100 - price * 100);
  const register = cid.reverse().map(el => [el[0], Math.round(el[1]*100)]);
  const registerTotal = register.reduce((sum, elem) => (sum + elem[1]), 0);
  
  if (changeDue > registerTotal ) return "Insufficient Funds";
  if (changeDue === registerTotal ) return "Closed";

  let partial;
  let change = register.reduce((acc, elem) => {
        // for each denomination calculate the lesser of (a) the amount that could be paid with that
        // denomination without going over the amount owed, and (b) the actual amount of that denomination in 
        // the register. Denominations not used to make change are excluded from the resulting array.
        partial = Math.min(elem[1], Math.floor(changeDue / denominations[elem[0]]) * denominations[elem[0]]);
        if ( partial > 0 ) {
          changeDue -= partial;
          acc.push([elem[0], partial / 100]);
        } return acc;
    }, [])
      
  // If the correct change could not be made from what was in the register.
  if (changeDue > 0 ) return "Insufficient Funds"

  return change;
}

#5

Actually, I don’t see much value from converting the ‘cid’ array into an object for this task. Below’s my approach just with arrays. It also tests at the very beginning if enough cash is in the drawer before doing any computations. I think the structure is cleaner as the current “Beginner Code Solution”. Take a look:

/*jshint esversion: 6 */

function checkCashRegister(price, cash, cid) {
  //declare and initialize variables
  var change = Math.round((cash - price) * 100);
  var value = 0;
  var changeRecord = [];
  var currency = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];
  //convert all floats to integers due to floating point number issue
  cid.forEach(el => el[1] = Math.round(el[1] * 100));
  //helper function to check if sufficient cash for change is in the drawer
  function enoughFund(cid) {
    var sum = cid.filter((el, i) => change >= currency[i]);
    return sum.reduce((a, b) => {
      return a + b[1];
    }, 0);
  }

  //Actual program/control flow starts here
  if (enoughFund(cid) < change)
    return "Insufficient Funds";
  else if (enoughFund(cid) === change)
    return "Closed";
  else {
    for (var i = cid.length - 1; i > -1; i--) {
      value = 0;
      while (cid[i][1] > 0 && change >= currency[i]) {
        //update everything as long as condition is true
        change -= currency[i];
        cid[i][1] -= currency[i];
        //value keeps track of the amount of each currency unit as change
        value += currency[i];
      }
      if (value)
        changeRecord.push([cid[i][0], value]);
    }
  }
  //divide each array by 100 to display a proper money format
  changeRecord.forEach(el => el[1] = (el[1] / 100));
  return changeRecord;
}

#6

The result of this code for check #5 is “[[“TWENTY”,80],[“TEN”,10],[“FIVE”,5],[“ONE”,1],[“QUARTER”,0.5],[“DIME”,0.2],[“PENNY”,0.04]]”, whereas the expected answer for check #5 has been “[[“TWENTY”, 60.00], [“TEN”, 20.00], [“FIVE”, 15.00], [“ONE”, 1.00], [“QUARTER”, 0.50], [“DIME”, 0.20], [“PENNY”, 0.04]]”. There seems to be a bug in this challenge scenario. This is what I have:

function checkCashRegister(price, cash, cid) {
var changeValue=cash-price;
var flattened = [].concat.apply([], cid);
var numbersOnly = flattened.filter(function(element) {return !isNaN(parseFloat(element)) && isFinite(element);});
var registerValue=numbersOnly.reduce((a, b) => a + b, 0).toFixed(2);
var change=[];
var smallChange=(changeValue%1).toFixed(2);
var coinsValue=0;

for (i=0;i<4;i++){
coinsValue+=numbersOnly[i];
}

if (registerValue==changeValue) return “Closed”;
if (registerValue>changeValue){
if (changeValue>=100) change.push([“ONE HUNDRED”,100Math.floor(changeValue/100)]); changeValue=changeValue%100;
if (changeValue>=20) change.push([“TWENTY”,20
Math.floor(changeValue/20)]); changeValue=changeValue%20;
if (changeValue>=10) change.push([“TEN”,10Math.floor(changeValue/10)]); changeValue=changeValue%10;
if (changeValue>=5) change.push([“FIVE”,5
Math.floor(changeValue/5)]); changeValue=changeValue%5;
if (changeValue>=1) change.push([“ONE”,1Math.floor(changeValue)]); changeValue=changeValue%1;
if (changeValue>=0.25) { change.push([“QUARTER”,0.25
Math.floor(changeValue/0.25)]); changeValue=changeValue%0.25; }
if (changeValue>=0.10){ change.push([“DIME”,0.10Math.floor(changeValue/0.10)]); changeValue=changeValue%0.1;}
if (changeValue>=0.05){ change.push([“NICKEL”,0.05
Math.floor(changeValue/0.05)]); changeValue=changeValue%0.05;}
if (changeValue>=0.01){ change.push([“PENNY”,0.01*Math.ceil(changeValue/0.01)]);}
} else {return “Insufficient Funds”;}
if (coinsValue<smallChange) return “Insufficient Funds”;

return change;
}


#7

I’ve fixed my own chicken scratch. Although I’ve also realized that this challenge is to help one with learning the skills of object oriented programming, I’ve proceeded to solve the puzzle with sequential coding. Thus, this following snippet probably qualifies as a very basic-level solution:

function checkCashRegister(price, cash, cid) {
var changeValue=cash-price;
var flattened = [].concat.apply([], cid);
var numbersOnly = flattened.filter(function(element) {return !isNaN(parseFloat(element)) && isFinite(element);}).reverse();
var registerValue=numbersOnly.reduce((a, b) => a + b, 0).toFixed(2);
var change=[];
var smallChange=(changeValue%1).toFixed(2);
var coinsValue=0;
var grab=0;

for (i=0;i<4;i++){
coinsValue+=numbersOnly[i];
}

if (registerValue==changeValue) return “Closed”;
if (registerValue>changeValue){

// Let's deal with HUNDREDs
if (changeValue>=100){ 
  grab=100*Math.floor(changeValue/100) > numbersOnly[0]? numbersOnly[0] : 100*Math.floor(changeValue/100);
  change.push(["ONE HUNDRED",grab]);
  changeValue-=grab; }

// TWENTIES
if (changeValue>=20){ 
  grab=20*Math.floor(changeValue/20) > numbersOnly[1]? numbersOnly[1] : 20*Math.floor(changeValue/20);
  change.push(["TWENTY",grab]); 
  changeValue-=grab; }

// TENs
if (changeValue>=10){
  grab=10*Math.floor(changeValue/10) > numbersOnly[2]? numbersOnly[2] : 10*Math.floor(changeValue/10);
  change.push(["TEN",grab]);
  changeValue-=grab;}

// FIVEs
if (changeValue>=5){ 
  grab=5*Math.floor(changeValue/5) > numbersOnly[3]? numbersOnly[3] : 5*Math.floor(changeValue/5);
  change.push(["FIVE",grab]); 
  changeValue-=grab;}

// ONEs
if (changeValue>=1){
  grab=changeValue > numbersOnly[4]? numbersOnly[4] : Math.ceil(changeValue%1);
  change.push(["ONE",grab]); 
  changeValue-=grab;
}

if (changeValue>=0.25) {

// return changeValue;
grab=changeValue > numbersOnly[5]? numbersOnly[5] : 0.25*Math.floor(changeValue/0.25);
change.push([“QUARTER”,grab]);
changeValue-=grab;
}

if (changeValue>=0.10){ 
  grab=changeValue > numbersOnly[6]? numbersOnly[6] : 0.1*Math.floor(changeValue/0.1);
  change.push(["DIME",grab]);
  changeValue-=grab;}

if (changeValue>=0.05){ 
  grab=changeValue > numbersOnly[7]? numbersOnly[7] : 0.05*Math.floor(changeValue/0.05);
  change.push(["NICKEL",grab]);
  changeValue-=grab;}

if (changeValue>=0.01){ 
  change.push(["PENNY",Math.round(changeValue*100)/100]);
  }

} else {return “Insufficient Funds”;}
if (coinsValue<smallChange) return “Insufficient Funds”;

return change;
}


#8

This is the first working solution I came up with.
Feedback always welcome:

function checkCashRegister(price, cash, cid) {
    var change = cash - price;
    var currencyValues = { 0: 100, 1: 20, 2: 10, 3: 5, 4: 1, 5: 0.25, 6: 0.10, 7: 0.05, 8: 0.01 };
    console.log(totalInDrawer(cid));
    if (change > totalInDrawer(cid) || enoughCurrencyValue(cid, change, currencyValues) === false) {
        return 'Insufficient Funds';
    } else if (change == totalInDrawer(cid)) {
        return 'Closed';
    }
    var ticket = createTicket(cid, change, currencyValues);
    // Here is your change, ma'am.
    return ticket;
}

function enoughCurrencyValue(cid, change, values) {
    var lower = cid.reverse().filter(function(item, index) {
        if(values[index] <= change || (item[1] >= change && values[index] <= change)) return item;
    }, []);
    return totalInDrawer(lower) >= change;
}

function createTicket(cid, change, currencyValues) {
    
    var ticket = cid.filter(function (current, index) {
        let changeAcc = 0;
        while (current[1] >= currencyValues[index] && current[1] >= 0 && currencyValues[index] <= change && change > 0) {
            if (enoughCurrency(currencyValues[index], current[1])) {
                change = change.toFixed(2);
                change -= currencyValues[index];
                current[1] -= currencyValues[index];
                changeAcc += currencyValues[index];
            }
        }
        if (changeAcc > 0) {
            current[1] = changeAcc;
            return current;
        }
    });
    return ticket;
}

function enoughCurrency(value, available) {
    return available >= value ? true : false;
}

function totalInDrawer(array) {
    return array.reduce(function (prev, curr) {
        return prev + curr[1];
    }, 0);
}

#9

My solution uses two 2D arrays: inDrawer (denominations and cash) and changeArray (output)
inDrawer = [ [denomination value, current value ], … ];
changeArray = [ [denominatin name, current change ], … ]

    function checkCashRegister(price, cash, cid) {

  var change = cash - price,
  cashInDrawer = 0,
  // Part of cashInDrawer, which currency is  equal or less than change
  possibleChange = 0,
  // Part of change in one denomination
  giveChange = 0,
  inDrawer = [[100], [20], [10], [5], [1], [0.25], [0.10], [0.05], [0.01]],
  changeArray = [];

  cid.reverse();
  // Counts all cash in drawer,
  // Comletes inDrawer (denominations) with appropriate cash
  // Pushes each name of denominations into  changeArray
  for (var i = cid.length-1; i >= 0; i--) {
    cashInDrawer += cid[i][1];
    inDrawer[i].push(cid[i][1]);
    changeArray.push([cid[i][0]]);
  }

  changeArray.reverse();

  if (change > cashInDrawer) {
    return "Insufficient Funds";
  } else if (change === cashInDrawer) {
    return "Closed";
  } else {
// ----------- count change START ----------- //
    for (var k = 0; k < inDrawer.length; k++) {
      // Counts change of each denomination type ...
      while (change >= inDrawer[k][0] && inDrawer[k][1] > 0) {
        giveChange += inDrawer[k][0];
        inDrawer[k][1] -= inDrawer[k][0];
        change -= inDrawer[k][0];
        change = Math.round(change * 100) / 100;
      }
      // ... and pushes it to appropriate denomination name
      if (giveChange > 0) {
        changeArray[k].push(Math.round(giveChange * 100) / 100);
      }
      // counts possibleChange
      if (cash - price >= inDrawer[k][0]) {
        possibleChange += inDrawer[k][1];
      }
      // Assign giveChange to 0 for next k-iteration
      giveChange = 0;
    }
// ----------- count change END ----------- //
  }
  // Second case, when change returning is impossible
  if (cash - price > possibleChange) {
    return "Insufficient Funds";
  }
   // Filters out items with 2 elements (denomination name and appropriate cash)
  return changeArray.filter(function(item) {
    return item.length === 2;
  });
}

console.log(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]]));

#11
function checkCashRegister(price, cash, cid) {

var obj = {“PENNY”:0.01,“NICKEL”:0.05,“DIME”: 0.10,“QUARTER” : 0.25,“ONE”:1.00, “FIVE”:5.00, “TEN”:10.00, “TWENTY” :20.00, “ONE HUNDRED”:100.00};
var returnVal;
var change=[];
var diff = parseFloat(cash-price).toFixed(2);
for (var i=cid.length-1;i>=0;i–){
var accumilator=0;
var money = cid[i][1];
var currencyName = cid[i][0];
var objDivid = obj[cid[i][0]];

while(money/objDivid>=1&&diff>=objDivid){
accumilator +=objDivid;
money=  parseFloat(money-objDivid).toFixed(2);
diff=parseFloat(diff-objDivid).toFixed(2);
   }
  if(accumilator>0)change.push([currencyName,accumilator]);

}
// Here is your change, ma’am.
if(diff==0)returnVal=change;
if(diff>0)returnVal=“Insufficient Funds”;
if(diff==0&&cid[0][1]<1)returnVal=“Closed”;
return returnVal;
}


#12

I can’t pass the #5 tests because of JS’s DEMICAL BUG.
I tried to multiply every demical to 100 and divide it by 100 but the bug is still there.
So I just put my code here hope that someone could fix this for me.Meanwhile I’d have to copy one of yours to pass the god damn test :frowning:

function checkCashRegister(price, cash, cid) {
   // Here is your change, ma'am.
  var funds=(cid.reduce(function(acc,val){
    return acc+val[1]*100;
  },0))/100;
  var newArr=cid.reduce(function(acc,val){
      acc.push(val.slice());
    return acc;
    },[]);
 
  for(i=0;i<newArr.length;i++){
    switch(newArr[i][0]){
      case "PENNY":newArr[i][0]=0.01;break;
      case "NICKEL":newArr[i][0]=0.05;break;
      case "DIME":newArr[i][0]=0.10;break;
      case "QUARTER":newArr[i][0]=0.25;break;
      case "ONE":newArr[i][0]=1;break;
      case "FIVE":newArr[i][0]=5;break;
      case "TEN":newArr[i][0]=10;break;
      case "TWENTY":newArr[i][0]=20;break;
      case "ONE HUNDRED":newArr[i][0]=100;break;
    }
  }
  
 //return newArr;
  //return cid;
 
  if(cash-price>funds){
    return "Insufficient Funds";
  }
  else if(cash-price===funds){
    return "Closed";
  }
  else{
    var list=[];
    var change=cash-price;
   for(i=8;i>=0;i--){
     if(change>=cid[i][1]){
       change=(change*100-cid[i][1]*100)/100;
       list.push(cid[i]);
     }
     else if(change>=newArr[i][0]){
       list.push([cid[i][0],Math.floor(change/newArr[i][0])*newArr[i][0]]);
       change=(change*100-newArr[i][0]*100*Math.floor((change*100)/(newArr[i][0]*100)))/100;
       
     }
    
   }
    
   if(change!==0){
     return"Insufficient Funds";
   }
   else{
    return list;
      }
  }
  
}



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

#13

why do you divide by a hundred before you finish operations? Doesn’t that defeat the purpose of multiplying by a 100 to began with? You end up doing a lot of your operations in float anyway, just with a redundant *100/100. Why not multiply by 100, do all the math operations, then divide by 100?


#14

My approach first checks if there is enough cash in the drawer to satisfy the required change. Then it loops through the cash in drawer (cid) array, starting with the largest denomination. Each iteration checks if that denomination is smaller than the amount of change remaining and if there is actually any of that denomination in the cid. If not, it moves to the next denomination. If there is, it subtracts that denomination from the change and the cid, then adds that amount to changeArr.


function checkCashRegister(price, cash, cid) {
  var worth = [0.01, 0.05, 0.10, 0.25, 1.00, 5.00, 10.00, 20.00, 100.00];
  var changeArr = [];
  var change = cash - price;
  var cashDrawer = 0;
  var changeAvail = 0;
  for(i = 0; i < cid.length; i++) {
    cashDrawer += cid[i][1];
  }
  cashDrawer = cashDrawer.toFixed(2);
  if(cashDrawer < cash - price) { // Is there not enough cash in the drawer?
    return "Insufficient Funds";
  } else if(cashDrawer == cash - price) { // Is there exactly enough cash in the drawer?
    return "Closed";
  } else {
    for(i = 8; i > -1; i--) {
      //Create a copy of the cid array to prevent unwanted changes to it
      var cidCopy = [];
      for (var k = 0; k < cid.length; k++) {
        cidCopy[k] = cid[i].slice();
      }
      var x = worth[i];
      var y = cidCopy[i];
      var z = cidCopy[i][0];
      // If there is cash in the drawer of that denomination,
      // and if that denomination is smaller than the change remaining:
      if(change >= x && cidCopy[i][1] > 0) {
        change -= x;
        change = Number(change.toFixed(2)); // Round change to nearest hundredth
        cid[i][1] -= x;
        if(!changeArr.length) {
          changeArr.unshift(y);
          changeArr[0][1] = x;
        } else if(changeArr[0][0] == z) {
          changeArr[0][1] += x;
        } else {
          changeArr.unshift(y);
          changeArr[0][1] = x;
        }
        i++;
      }
    }

  }  
  // Here is your change, ma'am.
  for(j = 0; j < changeArr.length; j++) {
    changeAvail += changeArr[j][1];
  }
  if(changeAvail < cash - price) {
    return "Insufficient Funds";
  } else {
    return changeArr.reverse();
  }
}



#15

I used:
change = Number(change.toFixed(2));

The toFixed method actually returns a string, so I had to convert it back to a number. But this seems to do the trick pretty well.

See my code to see it in action. I only had to use it in one line to fix the problem.


#16

Here’s my current solution.

function checkCashRegister(price, cash, cid) {
  const values = [1,5,10,25,100,500,1000,2000,10000];
  let change = cash*100 - price*100; 
  let allCash = true;

  let moneyback = cid.reduceRight(function(p,c,i){
      let out = Math.min(change-change%values[i], c[1]*100);
      change -= out;
      if (out !== c[1]*100) { allCash = false; }
      return out ? p.concat([[c[0], out/100]]) : p;
    },[]);

  return change > 0 ? "Insufficient Funds" : allCash ? "Closed" : moneyback;
}

#17

forkerino, I tryed this test:

checkCashRegister(19.70, 20.00, [[“PENNY”, 0], [“NICKEL”, 0], [“DIME”, 0.5], [“QUARTER”, 0.5], [“ONE”, 0], [“FIVE”, 0], [“TEN”, 0], [“TWENTY”, 0], [“ONE HUNDRED”, 100.00]]);

And got:

“Insufficient Funds”


#18

Hi, thanks for catching that one. It seems to be a situation that is not tested for in any of the provided test-cases (the change can be given only by skipping one of the denomenations, in this case the quarters). I suspect most other solutions on this page have the same problem, at least as far as I can see from skimming the code… I also don’t see an easy way to solve this based on my current solution, but it’s definitely an interesting case to think about.


#19

Here is my advanced solution:

function checkCashRegister(price, cash, cid) {
    let mNames = ['PENNY', 'NICKEL', 'DIME', 'QUARTER', 'ONE', 'FIVE', 'TEN', 'TWENTY', 'ONE HUNDRED'],
        mValues = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000],
        mAmount = [];

    let goal = cash * 100 - price * 100;
    
    for(let i = 0; i < cid.length; i++) {
        let sum = Math.round(cid[i][1] * 100);
        mAmount[i] =  Math.floor(sum / mValues[i]); 
    }
    
    console.log('mAmount:');
    console.log(mAmount);
    
    let hRes = h(goal, 8);
    
    if(hRes) { 
        let res = [],
            flag = 0;

        for(let i = hRes.length - 1; i >= 0; i--) {
            let sum = ((hRes[i] * mValues[i]) / 100 ).toFixed(2);
            let have = (cid[i][1]).toFixed(2); 
          
            if(have == sum) {
                flag++;
            }
            
            if(sum > 0) {
                sum = Number(sum);
                res.push([mNames[i], sum]);    
            } 
        }
        
        if(flag === 9) {
            return 'Closed';
        } else {
            return res;
        }  
    } else {
        return 'Insufficient Funds';
    }
  
    function h(goal, i) {
        if(i < 0) {
            return false;
        }
        
        console.log(`goal: ${goal}`);
        console.log(`coin: ${mValues[i]}`);
        console.log(`i: ${i}`);
        
        let value = mValues[i],
            amount = mAmount[i];
        
        let div = Math.floor(goal / value);
        let n = Math.min(div, amount);
        
        if(goal - n * value == 0) {
            let coins = [0,0,0,0,0,0,0,0,0];
            coins[i] = n;
            return coins;
        } else {
            while(n >= 0) {
                let newGoal = goal - n * value;
                let hRes = h(newGoal, i-1);
                
                if(hRes) {
                    hRes[i] = n;
                    return hRes;
                }
                
                n--;
            }
    
            return false;
        } 
    }
}

#20

forkerino, if you interested, check my solution above


#21

Thanks for sharing. I haven’t had time to look at it, but will do later.