vvm 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce724b1605a33efcf6822c2847adf138484b9e491a284c539cd080e6e26e38d5
4
- data.tar.gz: 688ccdc909529f01f7eacc8097566da61cd09c058743b32f0aff8a9d1673eecc
3
+ metadata.gz: '0742129dc37e28bf46ea49679313f24eb670cbf949f5db63c433a6dfd0848349'
4
+ data.tar.gz: 28be2e9c01eee6566c07a3f8618c06601b3534bffa097de8514da72df1b4e856
5
5
  SHA512:
6
- metadata.gz: 3990c247245ba68151721b49fb2d457c5a48746c7b87730d9e245ce2dfa3f6422b25df8c9e5cafb79a8ce0a8797d8e90606f56a0f293fc157af18c9f39ae9fe0
7
- data.tar.gz: 669430561a7fd57cc46b36c3f2a3671d8b21eb94722e208a006d510abd32387d920cb37545548c9d74d00126dac7efec815d0e514af7a8e546cf1c18ba6e6ad0
6
+ metadata.gz: f341b440b96bf4669f8fb8af2c85ee696a662ba4f68fde5cee5ee3061ff912ebc405f334f2b0ec3f6b254c2ca8608a63febb5aad59ddaa2997adbd9ee9a8502c
7
+ data.tar.gz: 668038ac248fc9a3fd99085fecbe0960c97fd78a45622744291500bd49992713dddcebaa8cee308fb8cdd59b7ae0961d0cd44621a7ca3a5809b0db5fc89c59f6
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vvm
4
+ class Dispenser
5
+ def initialize(amount, coins)
6
+ @amount = amount
7
+ @coins = coins
8
+ @min_coins = []
9
+ @min_qty = 0
10
+ @subset = coins
11
+ end
12
+
13
+ def call # rubocop:disable Metrics/AbcSize
14
+ return give_away if not_enough_change?
15
+
16
+ coins.each_with_object([]).with_index do |(_, memo), index|
17
+ self.subset = define_subset(index)
18
+
19
+ result = calculate(subset, amount)
20
+
21
+ memo << result if result.sum { _1.value * _1.qty } == amount
22
+
23
+ match_qty = calculate_min_qty(memo)
24
+
25
+ calibrate(memo, match_qty) if min_coins.empty? || match_qty < min_qty
26
+ end
27
+
28
+ min_coins
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :amount, :coins
34
+ attr_accessor :min_coins, :min_qty, :subset
35
+
36
+ def give_away
37
+ coins.map do |coin|
38
+ dup = coin.dup
39
+ coin.qty = 0
40
+ dup
41
+ end
42
+ end
43
+
44
+ def not_enough_change?
45
+ amount > coins.sum { _1.value * _1.qty }
46
+ end
47
+
48
+ def define_subset(index)
49
+ coins.dup.tap do |list|
50
+ list.delete_at(index) unless index.zero?
51
+ list.each { |coin| coin.qty = initial_coins.detect { coin.value == _1.value }.qty }
52
+ end
53
+ end
54
+
55
+ def calculate_min_qty(coins_matrix)
56
+ coins_matrix.min_by { _1.sum(&:qty) }.sum(&:qty)
57
+ end
58
+
59
+ def calibrate(coins_matrix, match_qty)
60
+ self.min_coins = coins_matrix.detect { _1.sum(&:qty) == match_qty }
61
+ self.min_qty = match_qty
62
+ end
63
+
64
+ def calculate(coins, change, index = 0) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
65
+ coins.drop(index).each_with_object([]).with_index do |(coin, memo), idx|
66
+ remainder = change % coin.value
67
+
68
+ if coin.qty.positive? && coin.value <= change && remainder < change
69
+ required_qty = [coin.qty, (change - remainder) / coin.value].min
70
+
71
+ memo << Vvm::Model::Coin.new(coin.value, required_qty)
72
+
73
+ amount = required_qty * coin.value
74
+ change_left = change - amount
75
+ coin.qty -= 1
76
+
77
+ break memo if change_left.zero?
78
+
79
+ sub_result = calculate(coins, change_left, idx + 1)
80
+
81
+ break unless sub_result
82
+
83
+ return memo + sub_result
84
+ end
85
+ end
86
+ end
87
+
88
+ def initial_coins
89
+ @initial_coins ||= coins.map(&:dup)
90
+ end
91
+ end
92
+ end
@@ -3,6 +3,10 @@
3
3
  module Vvm
4
4
  module State
5
5
  class Base
6
+ extend Forwardable
7
+
8
+ def_delegators :machine, :coins, :balance
9
+
6
10
  def initialize(machine)
7
11
  @machine = machine
8
12
  end
@@ -15,21 +19,12 @@ module Vvm
15
19
  raise NotImplementedError
16
20
  end
17
21
 
18
- def dispense # rubocop:disable Metrics/AbcSize
19
- machine.coins.each_with_object([]) do |coin, acc|
20
- next if coin.value > machine.balance
21
-
22
- unbalansed_qty = (machine.balance / coin.value).floor
23
- qty_to_return = unbalansed_qty > coin.qty ? coin.qty : unbalansed_qty
24
-
25
- coin_to_return = coin.dup
26
- coin_to_return.qty = qty_to_return
22
+ def dispense
23
+ result = Vvm::Dispenser.new(balance, coins).call
27
24
 
28
- acc.push(coin_to_return)
29
- coin.qty -= qty_to_return
25
+ machine.balance -= result.sum { _1.qty * _1.value }
30
26
 
31
- machine.balance = (machine.balance - (coin.value * qty_to_return)).round(2)
32
- end
27
+ result
33
28
  end
34
29
 
35
30
  private
data/lib/vvm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vvm
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/vvm.rb CHANGED
@@ -7,6 +7,7 @@ require 'forwardable'
7
7
  require_relative 'vvm/version'
8
8
  require_relative 'vvm/cli'
9
9
  require_relative 'vvm/machine'
10
+ require_relative 'vvm/dispenser'
10
11
  require_relative 'vvm/model/coin'
11
12
  require_relative 'vvm/model/product'
12
13
  require_relative 'vvm/error'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vvm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Bykov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-20 00:00:00.000000000 Z
11
+ date: 2021-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-prompt
@@ -46,6 +46,7 @@ files:
46
46
  - lib/vvm/cli/command/pick_product.rb
47
47
  - lib/vvm/cli/command/show_main_menu.rb
48
48
  - lib/vvm/cli/environment.rb
49
+ - lib/vvm/dispenser.rb
49
50
  - lib/vvm/error.rb
50
51
  - lib/vvm/machine.rb
51
52
  - lib/vvm/model/coin.rb