From 5f4917d50103b47db0a65cc1b5e54412a83c8ffd Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Mon, 24 Oct 2016 19:56:05 +0100 Subject: [PATCH 1/7] Ignore long running tests in the common test data. Ignore test cases based on the complexity of the expected result. Hardcoded commented out versions of the hard(er) tests along with instructions on why you might want to enable them. Refactored lib/alphametics_cases.rb. Use the common generator method names. Tidied up expected value string generation code. Re-generate tests based on version based on proposed changes. https://github.com/exercism/x-common/pull/425 Update `example.rb` to pass the current version of tests. --- exercises/alphametics/.version | 2 +- exercises/alphametics/alphametics_test.rb | 93 +++++++++++++---------- exercises/alphametics/example.rb | 7 +- exercises/alphametics/example.tt | 33 ++++++-- lib/alphametics_cases.rb | 47 ++++++++---- 5 files changed, 117 insertions(+), 65 deletions(-) diff --git a/exercises/alphametics/.version b/exercises/alphametics/.version index e440e5c842..bf0d87ab1b 100644 --- a/exercises/alphametics/.version +++ b/exercises/alphametics/.version @@ -1 +1 @@ -3 \ No newline at end of file +4 \ No newline at end of file diff --git a/exercises/alphametics/alphametics_test.rb b/exercises/alphametics/alphametics_test.rb index e9990c06c9..2cf049afed 100755 --- a/exercises/alphametics/alphametics_test.rb +++ b/exercises/alphametics/alphametics_test.rb @@ -3,63 +3,72 @@ require 'minitest/autorun' require_relative 'alphametics' -# Test data version: -# 8d8589f +# Test data version: c1cb73f class AlphameticsTest < Minitest::Test - def test_solve_short_puzzle + + def test_puzzle_with_three_letters # skip - expect = { - 'I' => 1, 'B' => 9, 'L' => 0 - } - actual = Alphametics.new.solve('I + BB == ILL') - assert_equal(expect, actual) + input = 'I + BB == ILL' + expected = { 'B' => 9, 'I' => 1, 'L' => 0 } + assert_equal expected, Alphametics.solve(input) end - # This test has been commented out due its long runtime. - # def test_solve_long_puzzle - # skip - # expect = { - # 'S' => 9, 'E' => 5, 'N' => 6, 'D' => 7, - # 'M' => 1, 'O' => 0, 'R' => 8, 'Y' => 2 - # } - # actual = Alphametics.new.solve('SEND + MORE == MONEY') - # assert_equal(expect, actual) - # end - def test_solution_must_have_unique_value_for_each_letter skip - expect = nil - actual = Alphametics.new.solve('A == B') - assert_equal(expect, actual) + input = 'A == B' + expected = {} + assert_equal expected, Alphametics.solve(input) end def test_leading_zero_solution_is_invalid skip - expect = nil - actual = Alphametics.new.solve('ACA + DD == BD') - assert_equal(expect, actual) + input = 'ACA + DD == BD' + expected = {} + assert_equal expected, Alphametics.solve(input) + end + + def test_puzzle_with_four_letters + skip + input = 'AS + A == MOM' + expected = { 'A' => 9, 'M' => 1, 'O' => 0, 'S' => 2 } + assert_equal expected, Alphametics.solve(input) end - def test_solve_puzzle_with_four_words + def test_puzzle_with_six_letters skip - expect = { - 'E' => 4, 'G' => 2, 'H' => 5, 'I' => 0, - 'L' => 1, 'S' => 9, 'T' => 7 - } - actual = Alphametics.new.solve('HE + SEES + THE == LIGHT') - assert_equal(expect, actual) + input = 'NO + NO + TOO == LATE' + expected = { 'A' => 0, 'E' => 2, 'L' => 1, 'N' => 7, + 'O' => 4, 'T' => 9 } + assert_equal expected, Alphametics.solve(input) end - # This test has been commented out due its long runtime. - # def test_solve_puzzle_with_many_words + def test_puzzle_with_seven_letters + skip + input = 'HE + SEES + THE == LIGHT' + expected = { 'E' => 4, 'G' => 2, 'H' => 5, 'I' => 0, + 'L' => 1, 'S' => 9, 'T' => 7 } + assert_equal expected, Alphametics.solve(input) + end + + # These tests have been commented out due their long runtime. If you are + # interested in optimsing your solution for speed these are a good tests to + # try. + # + # def test_puzzle_with_eight_letters + # skip + # input = 'SEND + MORE == MONEY' + # expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6, + # 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 } + # assert_equal expected, Alphametics.solve(input) + # end + + # def test_puzzle_with_ten_letters # skip - # expect = { - # 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, - # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, - # 'S' => 6, 'T' => 9 - # } - # actual = Alphametics.new.solve('AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE') - # assert_equal(expect, actual) + # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE' + # expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, + # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, + # 'S' => 6, 'T' => 9 } + # assert_equal expected, Alphametics.solve(input) # end # Problems in exercism evolve over time, as we find better ways to ask @@ -81,6 +90,6 @@ def test_solve_puzzle_with_four_words def test_bookkeeping skip - assert_equal 3, BookKeeping::VERSION + assert_equal 4, BookKeeping::VERSION end end diff --git a/exercises/alphametics/example.rb b/exercises/alphametics/example.rb index 2a20e14b26..d5746ae336 100644 --- a/exercises/alphametics/example.rb +++ b/exercises/alphametics/example.rb @@ -1,8 +1,10 @@ module BookKeeping - VERSION = 3 + VERSION = 4 end class Alphametics + class << self + def solve(puzzle) letters = Hash.new(0) puzzle.scan(/[a-zA-Z]/) { |w| letters[w] += 1 } @@ -11,7 +13,7 @@ def solve(puzzle) return letters_values if valid?(puzzle, letters_values) end - nil + {} end private @@ -30,6 +32,7 @@ def valid?(puzzle, letters_values) equation = puzzle.gsub(/[a-zA-Z]/, letters_values) Equation.new(equation).valid? end + end end class Equation diff --git a/exercises/alphametics/example.tt b/exercises/alphametics/example.tt index 03d126c39f..0e66a715eb 100644 --- a/exercises/alphametics/example.tt +++ b/exercises/alphametics/example.tt @@ -3,16 +3,37 @@ gem 'minitest', '>= 5.0.0' require 'minitest/autorun' require_relative 'alphametics' -# Test data version: -# <%= sha1 %> -class AlphameticsTest < Minitest::Test<% test_cases.each do |test_case| %> +# Test data version: <%= sha1 %> +class AlphameticsTest < Minitest::Test +<% test_cases.each do |test_case| %> def <%= test_case.test_name %> <%= test_case.skipped %> - expect = <%= test_case.expect %> - actual = <%= test_case.work_load %> - assert_equal(expect, actual) + input = <%= test_case.input %> + expected = <%= test_case.expect %> + <%= test_case.workload %> end <% end %> + # These tests have been commented out due their long runtime. If you are + # interested in optimsing your solution for speed these are a good tests to + # try. + # + # def test_puzzle_with_eight_letters + # skip + # input = 'SEND + MORE == MONEY' + # expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6, + # 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 } + # assert_equal expected, Alphametics.solve(input) + # end + + # def test_puzzle_with_ten_letters + # skip + # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE' + # expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, + # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, + # 'S' => 6, 'T' => 9 } + # assert_equal expected, Alphametics.solve(input) + # end + <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> def test_bookkeeping skip diff --git a/lib/alphametics_cases.rb b/lib/alphametics_cases.rb index 44cc5a664e..be5c175469 100644 --- a/lib/alphametics_cases.rb +++ b/lib/alphametics_cases.rb @@ -1,35 +1,54 @@ class AlphameticsCase < OpenStruct - PAIRS_PER_LINE = 4 - SPACE = ->(num) { ' ' * num } - def test_name "test_#{description.tr(' ', '_')}" end - def work_load - "Alphametics.new.solve('#{puzzle}')" + def skipped + index.zero? ? '# skip' : 'skip' + end + + def input + "'#{puzzle}'" end def expect - return 'nil' if expected.nil? - expected_values + expected.nil? ? {} : expected_values end + def workload + 'assert_equal expected, Alphametics.solve(input)' + end + + private + def expected_values - "{\n" << expected.each_slice(PAIRS_PER_LINE).map do |pairs| - '%s'.prepend(SPACE[6]) % - pairs.map { |k, v| "'#{k}' => #{v}" }.join(', ') - end.join(",\n") << "\n }" + "{ #{indent(expected_values_as_lines,17)} }" end - def skipped - index.zero? ? '# skip' : 'skip' + def expected_values_as_lines + lines = expected_values_as_strings.each_slice(4).map { |line| line.join(', ') } + add_trailing_comma(lines) + end + + def expected_values_as_strings + expected.sort.map { |(key,value)| "'#{key}' => #{value}" } + end + + def add_trailing_comma(lines) + lines[0...-1].map { |line| "#{line}," }.push(lines.last) + end + + def indent(string, spaces) + string.join("\n" + ' ' * spaces) end end AlphameticsCases = proc do |data| - JSON.parse(data)['solve']['cases'].map.with_index do |row, i| + testcases = JSON.parse(data)['solve']['cases'].map.with_index do |row, i| row = row.merge('index' => i) AlphameticsCase.new(row) end + + # The example algorithm takes a long time to solve these. + testcases.reject { |testcase| (testcase.expected||{}).size > 7 } end From 336a9112d4c5a2ded26732999910f9536013ca74 Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Sat, 29 Oct 2016 08:15:07 +0100 Subject: [PATCH 2/7] Fix typos --- exercises/alphametics/example.tt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/alphametics/example.tt b/exercises/alphametics/example.tt index 0e66a715eb..21a65ecd10 100644 --- a/exercises/alphametics/example.tt +++ b/exercises/alphametics/example.tt @@ -14,7 +14,7 @@ class AlphameticsTest < Minitest::Test end <% end %> # These tests have been commented out due their long runtime. If you are - # interested in optimsing your solution for speed these are a good tests to + # interested in optimising your solution for speed these are a good tests to # try. # # def test_puzzle_with_eight_letters @@ -27,7 +27,7 @@ class AlphameticsTest < Minitest::Test # def test_puzzle_with_ten_letters # skip - # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE' + # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE' # expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, # 'S' => 6, 'T' => 9 } From ea2ad66f1455bd318049d5949573711bf885ccb4 Mon Sep 17 00:00:00 2001 From: Mark Oveson Date: Mon, 31 Oct 2016 13:09:00 -0600 Subject: [PATCH 3/7] Fast alphametics solver that uses partials to limit the set of viable permutations. --- exercises/alphametics/example.rb | 162 +++++++++++++++++++------------ 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/exercises/alphametics/example.rb b/exercises/alphametics/example.rb index d5746ae336..49446d4326 100644 --- a/exercises/alphametics/example.rb +++ b/exercises/alphametics/example.rb @@ -3,99 +3,133 @@ module BookKeeping end class Alphametics - class << self - def solve(puzzle) - letters = Hash.new(0) - puzzle.scan(/[a-zA-Z]/) { |w| letters[w] += 1 } + def self.solve(equation) + new.solve(equation) + end - possible_values(letters.keys) do |letters_values| - return letters_values if valid?(puzzle, letters_values) - end + def solve(equation) + @prime_solver = AlphaSolver.new(equation) + solve_using_partials + end + + private + + attr_accessor :prime_solver + def solve_using_partials + prime_solver.partial_solutions.each do |partial_solution| + sub_solver = AlphaSolver.new(prime_solver.partial_equation(partial_solution)) + sub_solution = sub_solver.first_solution + return sub_solution.merge(partial_solution) if sub_solution + end {} end +end + +class AlphaSolver + + def initialize(input_equation) + @input_equation = input_equation.gsub('^', '**') + @puzzle = Puzzle.new(input_equation) + end + + def partial_solutions + AlphaSolver.new(puzzle.simplified).all_solutions + end + + def all_solutions + numeric_permutations.map { |values| result_table if solution?(values) }.compact + end + + def first_solution + numeric_permutations.each { |values| return result_table if solution?(values) } + nil + end + + def partial_equation(partial_solution) + input_equation.tr(partial_solution.keys.join, partial_solution.values.join) + end + private - def possible_values(letters) - (0..9).to_a.combination(letters.length) do |combined_integers| - combined_integers.permutation do |permutated_integers| - yield permutated_integers.map.with_index { |integer, index| - [letters[index], integer] - }.to_h - end - end + attr_reader :input_equation, :puzzle + attr_accessor :proposed_values + + def solution?(values) + self.proposed_values = values.join + proposed_equation_qualified? && proposed_equation_evaluates? end - def valid?(puzzle, letters_values) - equation = puzzle.gsub(/[a-zA-Z]/, letters_values) - Equation.new(equation).valid? + def proposed_equation + input_equation.tr(puzzle_letters, proposed_values) end + + def numeric_permutations + puzzle.numeric_permutations end -end -class Equation - attr_reader :equation + def puzzle_letters + puzzle.letters + end - def initialize(equation) - @equation = equation + def proposed_equation_qualified? + (proposed_equation =~ /\b0\d+/).nil? end - def valid? - return false if has_leading_zeros? + def proposed_equation_evaluates? + eval(proposed_equation) + end - expression, result = equation.split('==') + def result_table + Hash[puzzle_letters.chars.zip(result_numbers)] + end - numbers = [] - operators = [] + def result_numbers + proposed_values.chars.map(&:to_i) + end - expression.scan(/\d+|\+|\-|\*|\/|\^/).each do |token| - case token - when /^\d+$/ - numbers.push(token.to_i) - when '+', '-', '*', '/', '^' - calculate_last(numbers, operators) if has_precedence?(operators, token) - operators.push(token) - end - end +end - until operators.empty? - calculate_last(numbers, operators) - end +class Puzzle - numbers.last == result.to_i + PATTERNS = {mod_10: ' % 10', + adjacent_letters: /(\b)([A-Z]{1,})([A-Z])/, + equation_left_side: /(.*)( == )/} + + def initialize(string_equation) + @string_equation = string_equation end - private + def letters + @letters ||= string_equation.scan(/[A-Z]/).uniq.join + end - def has_leading_zeros? - equation.match(/^0\d+|\D0\d+/) + def numeric_permutations + @numeric_permutations ||= unused_numbers.to_a.permutation(letter_count) end - def has_precedence?(operators, token) - return false if operators.empty? - prev_operator = operators.last + def simplified + @simplified ||= string_equation + .gsub(PATTERNS[:adjacent_letters], "\\1\\3") + .gsub(PATTERNS[:equation_left_side], "(\\1)#{PATTERNS[:mod_10]}\\2") + end - case token - when '+', '-' - prev_operator == '*' || prev_operator == '/' || prev_operator == '^' - when '*', '/' - prev_operator == '^' - else - false - end + private + + attr_reader :string_equation + + def letter_count + @letter_count ||= letters.length end - def calculate_last(numbers, operators) - right = numbers.pop - left = numbers.pop - operator = as_ruby_operator(operators.pop) - result = left.send(operator, right) - numbers.push(result) + def unused_numbers + @unused_numbers ||= (0..9).to_a.map(&:to_s) - used_numbers end - def as_ruby_operator(operator) - operator == '^' ? '**' : operator + def used_numbers + @used_numbers ||= string_equation.gsub(PATTERNS[:mod_10], '').scan(/\d/).uniq end -end + +end \ No newline at end of file From a270ac302a40e98c2347beb85b8ce4098bbe2066 Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Wed, 2 Nov 2016 12:58:19 +0000 Subject: [PATCH 4/7] Re-add slow cases with warning comment. Re-add the "slow" test cases with a comment about them being slow. --- exercises/alphametics/example.tt | 24 +----------------------- lib/alphametics_cases.rb | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/exercises/alphametics/example.tt b/exercises/alphametics/example.tt index 21a65ecd10..60090c5e8e 100644 --- a/exercises/alphametics/example.tt +++ b/exercises/alphametics/example.tt @@ -6,34 +6,12 @@ require_relative 'alphametics' # Test data version: <%= sha1 %> class AlphameticsTest < Minitest::Test <% test_cases.each do |test_case| %> +<%= test_case.runtime_comment %> def <%= test_case.test_name %> <%= test_case.skipped %> - input = <%= test_case.input %> - expected = <%= test_case.expect %> <%= test_case.workload %> end <% end %> - # These tests have been commented out due their long runtime. If you are - # interested in optimising your solution for speed these are a good tests to - # try. - # - # def test_puzzle_with_eight_letters - # skip - # input = 'SEND + MORE == MONEY' - # expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6, - # 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 } - # assert_equal expected, Alphametics.solve(input) - # end - - # def test_puzzle_with_ten_letters - # skip - # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE' - # expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, - # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, - # 'S' => 6, 'T' => 9 } - # assert_equal expected, Alphametics.solve(input) - # end - <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> def test_bookkeeping skip diff --git a/lib/alphametics_cases.rb b/lib/alphametics_cases.rb index be5c175469..f0971087f6 100644 --- a/lib/alphametics_cases.rb +++ b/lib/alphametics_cases.rb @@ -16,11 +16,31 @@ def expect end def workload - 'assert_equal expected, Alphametics.solve(input)' + body = [ + 'input = %s' % input, + 'expected = %s' % expect, + 'assert_equal expected, Alphametics.solve(input)' + ] + indent(body,4) + end + + def runtime_comment + if slow? + comments = + '', + '# The obvious algorithm can take a long time to solve this puzzle,', + '# but an optimised solution can solve it fairly quickly.', + '# (It\'s OK to submit your solution without getting this test to pass.)' + indent(comments,2) + end end private + def slow? + (expected||{}).size > 7 + end + def expected_values "{ #{indent(expected_values_as_lines,17)} }" end @@ -38,9 +58,10 @@ def add_trailing_comma(lines) lines[0...-1].map { |line| "#{line}," }.push(lines.last) end - def indent(string, spaces) - string.join("\n" + ' ' * spaces) + def indent(lines, spaces) + lines.join("\n" + ' ' * spaces) end + end AlphameticsCases = proc do |data| @@ -50,5 +71,5 @@ def indent(string, spaces) end # The example algorithm takes a long time to solve these. - testcases.reject { |testcase| (testcase.expected||{}).size > 7 } + # testcases.reject { |testcase| (testcase.expected||{}).size > 7 } end From 6286608073f9c7db6ed6f08afc2ab00aaaba2ddb Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Wed, 2 Nov 2016 13:24:23 +0000 Subject: [PATCH 5/7] Slow test cases re-inserted as real tests. --- exercises/alphametics/alphametics_test.rb | 43 ++++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/exercises/alphametics/alphametics_test.rb b/exercises/alphametics/alphametics_test.rb index 2cf049afed..60ebd17754 100755 --- a/exercises/alphametics/alphametics_test.rb +++ b/exercises/alphametics/alphametics_test.rb @@ -3,7 +3,7 @@ require 'minitest/autorun' require_relative 'alphametics' -# Test data version: c1cb73f +# Test data version: 9dab356 class AlphameticsTest < Minitest::Test def test_puzzle_with_three_letters @@ -50,26 +50,28 @@ def test_puzzle_with_seven_letters assert_equal expected, Alphametics.solve(input) end - # These tests have been commented out due their long runtime. If you are - # interested in optimsing your solution for speed these are a good tests to - # try. - # - # def test_puzzle_with_eight_letters - # skip - # input = 'SEND + MORE == MONEY' - # expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6, - # 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 } - # assert_equal expected, Alphametics.solve(input) - # end + # The obvious algorithm can take a long time to solve this puzzle, + # but an optimised solution can solve it fairly quickly. + # (It's OK to submit your solution without getting this test to pass.) + def test_puzzle_with_eight_letters + skip + input = 'SEND + MORE == MONEY' + expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6, + 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 } + assert_equal expected, Alphametics.solve(input) + end - # def test_puzzle_with_ten_letters - # skip - # input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE' - # expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, - # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, - # 'S' => 6, 'T' => 9 } - # assert_equal expected, Alphametics.solve(input) - # end + # The obvious algorithm can take a long time to solve this puzzle, + # but an optimised solution can solve it fairly quickly. + # (It's OK to submit your solution without getting this test to pass.) + def test_puzzle_with_ten_letters + skip + input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE' + expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7, + 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1, + 'S' => 6, 'T' => 9 } + assert_equal expected, Alphametics.solve(input) + end # Problems in exercism evolve over time, as we find better ways to ask # questions. @@ -87,7 +89,6 @@ def test_puzzle_with_seven_letters # # 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 4, BookKeeping::VERSION From 3ded5e9d3f8ff22f6136f60b40bbe05614d26cfc Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Wed, 2 Nov 2016 13:26:17 +0000 Subject: [PATCH 6/7] Move newlines out of indentation method. --- exercises/alphametics/example.tt | 2 ++ lib/alphametics_cases.rb | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/exercises/alphametics/example.tt b/exercises/alphametics/example.tt index 60090c5e8e..48cf2eabf7 100644 --- a/exercises/alphametics/example.tt +++ b/exercises/alphametics/example.tt @@ -6,12 +6,14 @@ require_relative 'alphametics' # Test data version: <%= sha1 %> class AlphameticsTest < Minitest::Test <% test_cases.each do |test_case| %> + <%= test_case.runtime_comment %> def <%= test_case.test_name %> <%= test_case.skipped %> <%= test_case.workload %> end <% end %> + <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> def test_bookkeeping skip diff --git a/lib/alphametics_cases.rb b/lib/alphametics_cases.rb index f0971087f6..1bcc6f3cdd 100644 --- a/lib/alphametics_cases.rb +++ b/lib/alphametics_cases.rb @@ -16,11 +16,10 @@ def expect end def workload - body = [ - 'input = %s' % input, - 'expected = %s' % expect, - 'assert_equal expected, Alphametics.solve(input)' - ] + body = + "input = %s\n" % input, + "expected = %s\n" % expect, + "assert_equal expected, Alphametics.solve(input)" indent(body,4) end @@ -28,9 +27,9 @@ def runtime_comment if slow? comments = '', - '# The obvious algorithm can take a long time to solve this puzzle,', - '# but an optimised solution can solve it fairly quickly.', - '# (It\'s OK to submit your solution without getting this test to pass.)' + "# The obvious algorithm can take a long time to solve this puzzle,\n", + "# but an optimised solution can solve it fairly quickly.\n", + "# (It's OK to submit your solution without getting this test to pass.)\n" indent(comments,2) end end @@ -47,19 +46,19 @@ def expected_values def expected_values_as_lines lines = expected_values_as_strings.each_slice(4).map { |line| line.join(', ') } - add_trailing_comma(lines) + add_trailing_comma_and_newline(lines) end def expected_values_as_strings expected.sort.map { |(key,value)| "'#{key}' => #{value}" } end - def add_trailing_comma(lines) - lines[0...-1].map { |line| "#{line}," }.push(lines.last) + def add_trailing_comma_and_newline(lines) + lines[0...-1].map { |line| "#{line},\n" }.push(lines.last) end def indent(lines, spaces) - lines.join("\n" + ' ' * spaces) + lines.join(' ' * spaces) end end From a5dbabee468668bb4736b4a86a48773f74e7eeb3 Mon Sep 17 00:00:00 2001 From: Geoff Hubbard Date: Wed, 2 Nov 2016 19:26:03 +0000 Subject: [PATCH 7/7] Remove redundant code/comments --- lib/alphametics_cases.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/alphametics_cases.rb b/lib/alphametics_cases.rb index 1bcc6f3cdd..6ead800010 100644 --- a/lib/alphametics_cases.rb +++ b/lib/alphametics_cases.rb @@ -64,11 +64,8 @@ def indent(lines, spaces) end AlphameticsCases = proc do |data| - testcases = JSON.parse(data)['solve']['cases'].map.with_index do |row, i| + JSON.parse(data)['solve']['cases'].map.with_index do |row, i| row = row.merge('index' => i) AlphameticsCase.new(row) end - - # The example algorithm takes a long time to solve these. - # testcases.reject { |testcase| (testcase.expected||{}).size > 7 } end