-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvending_machine.rb
116 lines (98 loc) · 2.23 KB
/
vending_machine.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class VendingMachine
Drink = Struct.new(:name, :price, :amount) do
def stock?
amount >= 1
end
def pop
self.amount -= 1
end
def buyable?(current_amount)
stock? && price <= current_amount
end
end
attr_reader :drinks, :sales
def initialize
cola = Drink.new('コーラ', 120, 5)
water = Drink.new('水', 100, 5)
redbull = Drink.new('レッドブル', 200, 5)
@drinks = [cola,water,redbull]
@change_stock = ChangeStock.new
@sales = 0
end
def insert_coin(amount)
@change_stock.insert(amount)
amount
end
def total_amount
@change_stock.total_deposit
end
def refund
@change_stock.refund
end
def buyable?(drink_name)
find_drink_by_name(drink_name)&.buyable?(@change_stock.total_deposit)
end
def buy(drink_name)
return unless buyable?(drink_name)
drink = find_drink_by_name(drink_name)
drink.pop
@sales += drink.price
@change_stock.pull_deposit(drink.price)
end
def buyables
@drinks.select do |drink|
drink.buyable?(@change_stock.total_deposit)
end.map(&:name)
end
def change_stock
@change_stock.summary
end
def find_drink_by_name(name)
@drinks.find { |drink| drink.name == name }
end
end
class ChangeStock
ACCEPTABLE_CURRENCIES = [10, 50, 100, 500, 1000]
def initialize
@deposit = 0
@changes = ACCEPTABLE_CURRENCIES.each_with_object([]) do |currency, array|
10.times { array << currency }
end
end
def summary
@changes.group_by(&:itself).transform_values(&:size)
end
def insert(currency)
if ACCEPTABLE_CURRENCIES.include? currency
@deposit += currency
@changes << currency
end
end
def refund
refund_changes = []
sorted_changes = @changes.sort.reverse
tmp_deposit = @deposit
loop do
change = sorted_changes.shift
break if change.nil?
if tmp_deposit >= change
refund_changes << change
tmp_deposit -= change
end
break if tmp_deposit.zero?
end
if tmp_deposit.zero?
@deposit = 0
@changes -= refund_changes
refund_changes
else
raise('refund error')
end
end
def total_deposit
@deposit
end
def pull_deposit(price)
@deposit -= price
end
end