fix: drop deprecated coin change lib
This commit is contained in:
parent
38100a523e
commit
3151d0e7c9
4 changed files with 2 additions and 149 deletions
|
|
@ -1,127 +1,7 @@
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const sumService = require('@haensl/subset-sum')
|
|
||||||
|
|
||||||
const logger = require('./logger')
|
|
||||||
const cc = require('./coin-change')
|
const cc = require('./coin-change')
|
||||||
|
|
||||||
const BILL_LIST_MODES = {
|
|
||||||
LAST_UNIT_FIRST: 0,
|
|
||||||
FIRST_UNIT_FIRST: 1,
|
|
||||||
LOWEST_VALUE_FIRST: 2,
|
|
||||||
HIGHEST_VALUE_FIRST: 3,
|
|
||||||
UNIT_ROUND_ROBIN: 4,
|
|
||||||
VALUE_ROUND_ROBIN: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildBillList = (units, mode) => {
|
|
||||||
switch (mode) {
|
|
||||||
case BILL_LIST_MODES.LAST_UNIT_FIRST:
|
|
||||||
return _.reduce(
|
|
||||||
(acc, value) => {
|
|
||||||
acc.push(..._.times(_.constant(value.denomination), value.count))
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
_.reverse(units),
|
|
||||||
)
|
|
||||||
case BILL_LIST_MODES.FIRST_UNIT_FIRST:
|
|
||||||
return _.reduce(
|
|
||||||
(acc, value) => {
|
|
||||||
acc.push(..._.times(_.constant(value.denomination), value.count))
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
units,
|
|
||||||
)
|
|
||||||
case BILL_LIST_MODES.LOWEST_VALUE_FIRST:
|
|
||||||
return _.reduce(
|
|
||||||
(acc, value) => {
|
|
||||||
acc.push(..._.times(_.constant(value.denomination), value.count))
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
_.orderBy(['denomination'], ['asc'])(units),
|
|
||||||
)
|
|
||||||
case BILL_LIST_MODES.HIGHEST_VALUE_FIRST:
|
|
||||||
return _.reduce(
|
|
||||||
(acc, value) => {
|
|
||||||
acc.push(..._.times(_.constant(value.denomination), value.count))
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
_.orderBy(['denomination'], ['desc'])(units),
|
|
||||||
)
|
|
||||||
case BILL_LIST_MODES.UNIT_ROUND_ROBIN: {
|
|
||||||
const amountOfBills = _.reduce(
|
|
||||||
(acc, value) => acc + value.count,
|
|
||||||
0,
|
|
||||||
units,
|
|
||||||
)
|
|
||||||
|
|
||||||
const _units = _.filter(it => it.count > 0)(_.cloneDeep(units))
|
|
||||||
const bills = []
|
|
||||||
|
|
||||||
for (let i = 0; i < amountOfBills; i++) {
|
|
||||||
const idx = i % _.size(_units)
|
|
||||||
if (_units[idx].count > 0) {
|
|
||||||
bills.push(_units[idx].denomination)
|
|
||||||
_units[idx].count--
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_units[idx].count === 0) {
|
|
||||||
_units.splice(idx, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bills
|
|
||||||
}
|
|
||||||
case BILL_LIST_MODES.VALUE_ROUND_ROBIN: {
|
|
||||||
const amountOfBills = _.reduce(
|
|
||||||
(acc, value) => acc + value.count,
|
|
||||||
0,
|
|
||||||
units,
|
|
||||||
)
|
|
||||||
|
|
||||||
const _units = _.flow([
|
|
||||||
_.filter(it => it.count > 0),
|
|
||||||
_.orderBy(['denomination'], ['asc']),
|
|
||||||
])(_.cloneDeep(units))
|
|
||||||
const bills = []
|
|
||||||
|
|
||||||
for (let i = 0; i < amountOfBills; i++) {
|
|
||||||
const idx = i % _.size(_units)
|
|
||||||
if (_units[idx].count > 0) {
|
|
||||||
bills.push(_units[idx].denomination)
|
|
||||||
_units[idx].count--
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_units[idx].count === 0) {
|
|
||||||
_units.splice(idx, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bills
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new Error(`Invalid mode: ${mode}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSolution_old = (units, amount, mode) => {
|
|
||||||
const billList = buildBillList(units, mode)
|
|
||||||
|
|
||||||
if (_.sum(billList) < amount.toNumber()) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const solver = sumService.subsetSum(billList, amount.toNumber())
|
|
||||||
const solution = _.countBy(Math.floor, solver.next().value)
|
|
||||||
return Object.entries(solution).map(([denomination, provisioned]) => [
|
|
||||||
_.toNumber(denomination),
|
|
||||||
provisioned,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSolution = (units, amount) => {
|
const getSolution = (units, amount) => {
|
||||||
amount = amount.toNumber()
|
amount = amount.toNumber()
|
||||||
units = Object.entries(
|
units = Object.entries(
|
||||||
|
|
@ -147,25 +27,10 @@ const solutionToOriginalUnits = (solution, units) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeChange(outCassettes, amount) {
|
function makeChange(outCassettes, amount) {
|
||||||
const ss_solution = getSolution_old(
|
|
||||||
outCassettes,
|
|
||||||
amount,
|
|
||||||
BILL_LIST_MODES.VALUE_ROUND_ROBIN,
|
|
||||||
)
|
|
||||||
const cc_solution = getSolution(outCassettes, amount)
|
const cc_solution = getSolution(outCassettes, amount)
|
||||||
|
|
||||||
if (!cc.check(cc_solution, amount.toNumber())) {
|
if (!cc.check(cc_solution, amount.toNumber())) {
|
||||||
logger.error(new Error('coin-change provided a bad solution'))
|
throw new Error('coin-change provided a bad solution')
|
||||||
return solutionToOriginalUnits(ss_solution, outCassettes)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!ss_solution !== !!cc_solution) {
|
|
||||||
logger.error(
|
|
||||||
new Error(
|
|
||||||
`subset-sum and coin-change don't agree on solvability -- subset-sum:${!!ss_solution} coin-change:${!!cc_solution}`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return solutionToOriginalUnits(ss_solution, outCassettes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return solutionToOriginalUnits(cc_solution, outCassettes)
|
return solutionToOriginalUnits(cc_solution, outCassettes)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ const memo_set = (memo, target, denom, solution) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const check = (solution, target) =>
|
const check = (solution, target) =>
|
||||||
!solution ||
|
solution &&
|
||||||
target ===
|
target ===
|
||||||
solution.reduce((sum, [denom, provisioned]) => sum + denom * provisioned, 0)
|
solution.reduce((sum, [denom, provisioned]) => sum + denom * provisioned, 0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
"@graphql-tools/merge": "^9.0.22",
|
"@graphql-tools/merge": "^9.0.22",
|
||||||
"@graphql-tools/schema": "^10.0.21",
|
"@graphql-tools/schema": "^10.0.21",
|
||||||
"@graphql-tools/utils": "^10.8.4",
|
"@graphql-tools/utils": "^10.8.4",
|
||||||
"@haensl/subset-sum": "^3.0.5",
|
|
||||||
"@lamassu/coins": "v1.6.1",
|
"@lamassu/coins": "v1.6.1",
|
||||||
"@simplewebauthn/server": "^3.0.0",
|
"@simplewebauthn/server": "^3.0.0",
|
||||||
"@vonage/auth": "1.5.0",
|
"@vonage/auth": "1.5.0",
|
||||||
|
|
|
||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
|
|
@ -240,9 +240,6 @@ importers:
|
||||||
'@graphql-tools/utils':
|
'@graphql-tools/utils':
|
||||||
specifier: ^10.8.4
|
specifier: ^10.8.4
|
||||||
version: 10.8.6(graphql@16.11.0)
|
version: 10.8.6(graphql@16.11.0)
|
||||||
'@haensl/subset-sum':
|
|
||||||
specifier: ^3.0.5
|
|
||||||
version: 3.0.7
|
|
||||||
'@lamassu/coins':
|
'@lamassu/coins':
|
||||||
specifier: v1.6.1
|
specifier: v1.6.1
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
|
|
@ -1261,10 +1258,6 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||||
|
|
||||||
'@haensl/subset-sum@3.0.7':
|
|
||||||
resolution: {integrity: sha512-67zH9BEaRPXrPeQviZpKuFOavcgx6PMK3BnvTgwhsTUePhf1PncysxLNA6G100fekvxbNrV3cGPVi8qj8DOTmQ==}
|
|
||||||
engines: {node: '>=10.12.0'}
|
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
|
|
@ -8456,10 +8449,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
graphql: 16.11.0
|
graphql: 16.11.0
|
||||||
|
|
||||||
'@haensl/subset-sum@3.0.7':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.27.1
|
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.6':
|
'@humanfs/node@0.16.6':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue