Skip to content

Commit

Permalink
Merge pull request #695 from adimasuhid/features/implement-change-exe…
Browse files Browse the repository at this point in the history
…rcise

change: Implement Change exercise
  • Loading branch information
kotp authored Jul 27, 2017
2 parents 5fc6cd3 + e230f5e commit 820a137
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
13 changes: 13 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,19 @@
"Strings"
]
},
{
"uuid": "dc6c3e44-1027-4d53-9653-ba06824f8bcf",
"slug": "change",
"core": false,
"unlocked_by": null,
"difficulty": 5,
"topics": [
"Algorithms",
"Control-flow (conditionals)",
"Control-flow (loops)",
"Logic"
]
},
{
"uuid": "cae4e000-3aac-41f7-b727-f9cce12d058d",
"slug": "octal",
Expand Down
1 change: 1 addition & 0 deletions exercises/change/.meta/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
9 changes: 9 additions & 0 deletions exercises/change/.meta/generator/change_case.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'generator/exercise_case'

class ChangeCase < Generator::ExerciseCase

def workload
assert_equal { "Change.generate(#{coins}, #{target})" }
end

end
58 changes: 58 additions & 0 deletions exercises/change/.meta/solutions/change.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module BookKeeping
VERSION = 1
end

class Change
attr_reader :coins, :target

def initialize(coins, target)
@coins = coins.sort.reverse
@target = target
@total_change = []
end

def generate
return [] if target.zero?

calculate_change(coins, [], target)

total_change.any? ? total_change.sort : -1
end

def self.generate(coins, target)
new(coins, target).generate
end

private

attr_accessor :total_change

def calculate_change(current_coins, current_change, current_value)
available_coins = current_coins.reject {|d| d > current_value }

save_change(current_change) if current_value.zero?

return if has_more_coins?(current_change)

each_group(available_coins) do |coin, group|
calculate_change(group, current_change + [coin], current_value - coin)
end
end

def save_change(contents)
return if has_more_coins?(contents)

self.total_change = contents
end

def has_more_coins?(contents)
total_change.any? && (total_change.length < contents.length)
end

def each_group(array)
array.length.times do |n|
yield(array[n], array[n..-1])
end
end

end
77 changes: 77 additions & 0 deletions exercises/change/change_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require 'minitest/autorun'
require_relative 'change'

# Common test data version: 1.0.0 3d8b5b3
class ChangeTest < Minitest::Test
def test_single_coin_change
# skip
assert_equal [25], Change.generate([1, 5, 10, 25, 100], 25)
end

def test_multiple_coin_change
skip
assert_equal [5, 10], Change.generate([1, 5, 10, 25, 100], 15)
end

def test_change_with_lilliputian_coins
skip
assert_equal [4, 4, 15], Change.generate([1, 4, 15, 20, 50], 23)
end

def test_change_with_lower_elbonia_coins
skip
assert_equal [21, 21, 21], Change.generate([1, 5, 10, 21, 25], 63)
end

def test_large_target_values
skip
assert_equal [2, 2, 5, 20, 20, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100], Change.generate([1, 2, 5, 10, 20, 50, 100], 999)
end

def test_possible_change_without_unit_coins_available
skip
assert_equal [2, 2, 2, 5, 10], Change.generate([2, 5, 10, 20, 50], 21)
end

def test_no_coins_make_0_change
skip
assert_equal [], Change.generate([1, 5, 10, 21, 25], 0)
end

def test_error_testing_for_change_smaller_than_the_smallest_of_coins
skip
assert_equal -1, Change.generate([5, 10], 3)
end

def test_error_if_no_combination_can_add_up_to_target
skip
assert_equal -1, Change.generate([5, 10], 94)
end

def test_cannot_find_negative_change_values
skip
assert_equal -1, Change.generate([1, 2, 5], -5)
end

# Problems in exercism evolve over time, as we find better ways to ask
# questions.
# The version number refers to the version of the problem you solved,
# not your solution.
#
# Define a constant named VERSION inside of the top level BookKeeping
# module, which may be placed near the end of your file.
#
# In your file, it will look like this:
#
# module BookKeeping
# VERSION = 1 # Where the version number matches the one in the test.
# end
#
# If you are curious, read more about constants on RubyDoc:
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html

def test_bookkeeping
skip
assert_equal 1, BookKeeping::VERSION
end
end

0 comments on commit 820a137

Please sign in to comment.