Last active
January 18, 2022 15:18
-
-
Save ioncreature/1ce42cc458bc5fde133a3e93cef3821e to your computer and use it in GitHub Desktop.
Printify interview
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as assert from 'assert'; | |
const coins = [1, 2, 5, 10, 20, 50, 100, 200].reverse(); | |
type Coins = Map<number, number>; | |
interface Product { | |
name: string; | |
price: number; | |
} | |
class Machine { | |
constructor(private readonly products: Product[]) { | |
} | |
buy(productName: string, coins: Coins): { coins: Coins, product: Product } { | |
const product = this.getProduct(productName); | |
const amount = this.countCoins(coins); | |
if (amount < product.price) { | |
throw new Error('Not enough money'); | |
} | |
return { | |
product, | |
coins: Machine.getChange(amount - product.price) | |
}; | |
} | |
private getProduct(name: string) { | |
const product = this.products.find((p) => p.name == name); | |
if (!product) { | |
throw new Error('No such product'); | |
} | |
return product; | |
} | |
private countCoins(coins: Coins): number { | |
let amount = 0; | |
coins.forEach((count, coinPrice) => { | |
amount += count * coinPrice; | |
}) | |
return amount; | |
} | |
static getChange(amount: number): Coins { | |
const change = new Map(); | |
for (let i = 0; i < coins.length; i++) { | |
const q = Math.floor(amount / coins[i]); | |
if (q >= 1) { | |
change.set(coins[i], q); | |
amount -= coins[i] * q; | |
} | |
if (!amount) { | |
break; | |
} | |
} | |
return change; | |
} | |
} | |
// Unit tests | |
assert.deepEqual(Machine.getChange(500), new Map([[200, 2], [100, 1]])); | |
assert.deepEqual(Machine.getChange(105), new Map([[100, 1], [5, 1]])); | |
assert.deepEqual(Machine.getChange(0), new Map()); | |
console.log('\n\nUNIT TESTS PASSED\n\n') | |
// Integrations | |
const machine = new Machine([ | |
{name: 'Knachapury', price: 233}, | |
{name: 'B', price: 126}, | |
{name: 'C', price: 95}, | |
]); | |
// it should throw on unknown product | |
assert.throws( | |
() => { | |
machine.buy('Cola', new Map([[200, 1]])); | |
}, | |
{ | |
name: 'Error', | |
message: 'No such product' | |
} | |
); | |
// it should throw if user inserts not enough money | |
assert.throws( | |
() => { | |
machine.buy('Knachapury', new Map([[200, 1]])); | |
}, | |
{ | |
name: 'Error', | |
message: 'Not enough money' | |
} | |
); | |
// it should return product and change | |
assert.deepEqual(machine.buy('Knachapury', new Map([[200, 2]])), { | |
product: {name: 'Knachapury', price: 233}, | |
coins: new Map([[100, 1], [50, 1], [10, 1], [5, 1], [2, 1]]) | |
}); | |
console.log('\n\nINTEGRATION TESTS PASSED\n\n') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment