Desafio: Retirada de dinheiro em Javascript como caixa eletrônico
Esses dias fiquei pensando como funcionava a funcao que faz a retirada de dinheiro de um caixa eletronico. Parei para tentar fazer essa funcao e confesso que foi desafiador, fiz varios loops e coisas malukas até chegar a um resultado que gostaria de compartilhar com vocês
Basicamente pensei em função em javascript que faça saque com base no saldo e um array de notas disponivel, exemplo, preciso sacar 5 reais, e tem notas de 5 notas de 10, 4 notas de 20, 3 de 50, 5 de 100, logo nao teria o valor de 5 reais, e se eu sacar 550 descontar das notas e sempre fazer da melhor forma possivel.
function cashWithdrawal(value, availableNotes) {
let notes = [];
let availableNotesOriginal = structuredClone(availableNotes);
// array com os valores de todas as notas disponíveis
const allNotesValues = Object.keys(availableNotes).map((note) => Number(note)).sort((a, b) => b - a);
for (const subsetNotes of subsets(allNotesValues, 0, 2)) {
let remainingValue = value;
for (const noteValue of subsetNotes) {
// quantas notas desse valor eu preciso?
const need = Math.min(Math.floor(remainingValue / noteValue), availableNotes[noteValue]);
for (let i = 0; i < need; i++) { // adiciona as notas
notes.push(noteValue);
}
// subtrai a quantidade e atualiza o valor restante
availableNotes[noteValue] -= need;
remainingValue -= noteValue * need;
}
if (remainingValue == 0) { // se o valor zerou, é porque deu certo
const availableNotesSum = Object.entries(availableNotes).reduce((sum, [note, quantity]) => sum + Number(note) * quantity, 0);
return {
notes,
availableNotes,
availableNotesSum
};
} else {
// se não deu certo, zera o array de notas e volta para as notas disponíveis original
notes = [];
availableNotes = JSON.parse(JSON.stringify(availableNotesOriginal));
}
// se o valor não zerou, é porque não foi possível, então tenta com a próxima combinação de notas
}
return null; // se tentou todas as combinações e chegou aqui, é porque não é possível
}
Exemplo de uso:
const availableNotes = {10: 4, 20: 4, 50: 3, 100: 5};
const value = 580;
console.log('availableNotesSum', Object.entries(availableNotes).reduce((sum, [note, quantity]) => sum + Number(note) * quantity, 0))
const result = cashWithdrawal(value, availableNotes);
console.log(result);
// {
// notes: [100, 100, 100, 100, 100, 50, 50, 50, 20, 20, 20, 20, 10, 10, 10, 10],
// remainingValue: 0,
// availableNotes: {10: 0, 20: 0, 50: 0, 100: 1},
// availableNotesSum: 100,
// }
Agradecimentos especial ao @kht pela contribuição!
Criei um gist para deixar isso salvo por lá
https://gist.github.com/joaosouz4dev/d9bcce6f45f1af0aa3b337db847ec09d