trackler 2.0.0.2 → 2.0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/forth/canonical-data.json +1 -1
  3. data/common/exercises/pangram/canonical-data.json +0 -10
  4. data/common/exercises/run-length-encoding/canonical-data.json +21 -11
  5. data/lib/trackler/version.rb +1 -1
  6. data/tracks/bash/SETUP.md +2 -39
  7. data/tracks/bash/config.json +0 -9
  8. data/tracks/bash/exercises/hello-world/HINTS.md +38 -0
  9. data/tracks/bash/exercises/hello-world/hello_world_test.sh +0 -14
  10. data/tracks/haskell/.travis.yml +2 -13
  11. data/tracks/haskell/README.md +2 -1
  12. data/tracks/haskell/config.json +6 -0
  13. data/tracks/haskell/exercises/accumulate/examples/success-standard/package.yaml +16 -0
  14. data/tracks/haskell/exercises/accumulate/{src/Example.hs → examples/success-standard/src/Accumulate.hs} +0 -0
  15. data/tracks/haskell/exercises/all-your-base/examples/success-standard/package.yaml +16 -0
  16. data/tracks/haskell/exercises/all-your-base/{src/Example.hs → examples/success-standard/src/Base.hs} +0 -0
  17. data/tracks/haskell/exercises/allergies/examples/success-standard/package.yaml +16 -0
  18. data/tracks/haskell/exercises/allergies/{src/Example.hs → examples/success-standard/src/Allergies.hs} +0 -0
  19. data/tracks/haskell/exercises/alphametics/HINTS.md +5 -0
  20. data/tracks/haskell/exercises/alphametics/examples/success-standard/package.yaml +18 -0
  21. data/tracks/haskell/exercises/alphametics/examples/success-standard/src/Alphametics.hs +116 -0
  22. data/tracks/haskell/exercises/alphametics/package.yaml +20 -0
  23. data/tracks/haskell/exercises/alphametics/src/Alphametics.hs +4 -0
  24. data/tracks/haskell/exercises/alphametics/stack.yaml +1 -0
  25. data/tracks/haskell/exercises/alphametics/test/Tests.hs +78 -0
  26. data/tracks/haskell/exercises/anagram/examples/{list-string → success-liststring}/package.yaml +0 -1
  27. data/tracks/haskell/exercises/anagram/examples/{list-string → success-liststring/src}/Anagram.hs +0 -0
  28. data/tracks/haskell/exercises/anagram/examples/{set-text → success-settext}/package.yaml +0 -0
  29. data/tracks/haskell/exercises/anagram/examples/{set-text → success-settext/src}/Anagram.hs +0 -0
  30. data/tracks/haskell/exercises/atbash-cipher/examples/success-standard/package.yaml +18 -0
  31. data/tracks/haskell/exercises/atbash-cipher/{src/Example.hs → examples/success-standard/src/Atbash.hs} +0 -0
  32. data/tracks/haskell/exercises/bank-account/examples/success-standard/package.yaml +18 -0
  33. data/tracks/haskell/exercises/bank-account/{src/Example.hs → examples/success-standard/src/BankAccount.hs} +0 -0
  34. data/tracks/haskell/exercises/beer-song/examples/success-standard/package.yaml +16 -0
  35. data/tracks/haskell/exercises/beer-song/{src/Example.hs → examples/success-standard/src/Beer.hs} +0 -0
  36. data/tracks/haskell/exercises/binary-search-tree/examples/success-standard/package.yaml +16 -0
  37. data/tracks/haskell/exercises/binary-search-tree/{src/Example.hs → examples/success-standard/src/BST.hs} +0 -0
  38. data/tracks/haskell/exercises/binary/examples/success-standard/package.yaml +16 -0
  39. data/tracks/haskell/exercises/binary/{src/Example.hs → examples/success-standard/src/Binary.hs} +0 -0
  40. data/tracks/haskell/exercises/bob/examples/success-standard/package.yaml +16 -0
  41. data/tracks/haskell/exercises/bob/{src/Example.hs → examples/success-standard/src/Bob.hs} +0 -0
  42. data/tracks/haskell/exercises/change/examples/success-standard/package.yaml +16 -0
  43. data/tracks/haskell/exercises/change/{src/Example.hs → examples/success-standard/src/Change.hs} +0 -0
  44. data/tracks/haskell/exercises/clock/examples/success-standard/package.yaml +16 -0
  45. data/tracks/haskell/exercises/clock/{src/Example.hs → examples/success-standard/src/Clock.hs} +0 -0
  46. data/tracks/haskell/exercises/connect/examples/success-standard/package.yaml +18 -0
  47. data/tracks/haskell/exercises/connect/{src/Example.hs → examples/success-standard/src/Connect.hs} +0 -0
  48. data/tracks/haskell/exercises/crypto-square/examples/success-standard/package.yaml +18 -0
  49. data/tracks/haskell/exercises/crypto-square/{src/Example.hs → examples/success-standard/src/CryptoSquare.hs} +0 -0
  50. data/tracks/haskell/exercises/custom-set/examples/success-standard/package.yaml +16 -0
  51. data/tracks/haskell/exercises/custom-set/{src/Example.hs → examples/success-standard/src/CustomSet.hs} +0 -0
  52. data/tracks/haskell/exercises/difference-of-squares/examples/success-standard/package.yaml +16 -0
  53. data/tracks/haskell/exercises/difference-of-squares/{src/Example.hs → examples/success-standard/src/Squares.hs} +0 -0
  54. data/tracks/haskell/exercises/etl/examples/success-standard/package.yaml +17 -0
  55. data/tracks/haskell/exercises/etl/{src/Example.hs → examples/success-standard/src/ETL.hs} +0 -0
  56. data/tracks/haskell/exercises/food-chain/examples/success-standard/package.yaml +18 -0
  57. data/tracks/haskell/exercises/food-chain/{src/Example.hs → examples/success-standard/src/FoodChain.hs} +0 -0
  58. data/tracks/haskell/exercises/forth/HINTS.md +2 -2
  59. data/tracks/haskell/exercises/forth/examples/success-standard/package.yaml +19 -0
  60. data/tracks/haskell/exercises/forth/{src/Example.hs → examples/success-standard/src/Forth.hs} +3 -3
  61. data/tracks/haskell/exercises/forth/package.yaml +0 -1
  62. data/tracks/haskell/exercises/forth/src/Forth.hs +3 -3
  63. data/tracks/haskell/exercises/forth/test/Tests.hs +120 -65
  64. data/tracks/haskell/exercises/gigasecond/examples/success-standard/package.yaml +17 -0
  65. data/tracks/haskell/exercises/gigasecond/{src/Example.hs → examples/success-standard/src/Gigasecond.hs} +0 -0
  66. data/tracks/haskell/exercises/go-counting/examples/success-standard/package.yaml +20 -0
  67. data/tracks/haskell/exercises/go-counting/{src/Example.hs → examples/success-standard/src/Counting.hs} +0 -0
  68. data/tracks/haskell/exercises/grade-school/examples/success-standard/package.yaml +18 -0
  69. data/tracks/haskell/exercises/grade-school/{src/Example.hs → examples/success-standard/src/School.hs} +0 -0
  70. data/tracks/haskell/exercises/grains/examples/success-standard/package.yaml +16 -0
  71. data/tracks/haskell/exercises/grains/{src/Example.hs → examples/success-standard/src/Grains.hs} +0 -0
  72. data/tracks/haskell/exercises/grains/test/Tests.hs +1 -2
  73. data/tracks/haskell/exercises/hamming/examples/success-standard/package.yaml +16 -0
  74. data/tracks/haskell/exercises/hamming/{src/Example.hs → examples/success-standard/src/Hamming.hs} +0 -0
  75. data/tracks/haskell/exercises/hexadecimal/examples/success-standard/package.yaml +16 -0
  76. data/tracks/haskell/exercises/hexadecimal/{src/Example.hs → examples/success-standard/src/Hexadecimal.hs} +0 -0
  77. data/tracks/haskell/exercises/house/examples/success-standard/package.yaml +16 -0
  78. data/tracks/haskell/exercises/house/{src/Example.hs → examples/success-standard/src/House.hs} +0 -0
  79. data/tracks/haskell/exercises/kindergarten-garden/examples/success-standard/package.yaml +19 -0
  80. data/tracks/haskell/exercises/kindergarten-garden/{src/Example.hs → examples/success-standard/src/Garden.hs} +0 -0
  81. data/tracks/haskell/exercises/largest-series-product/examples/success-standard/package.yaml +18 -0
  82. data/tracks/haskell/exercises/largest-series-product/{src/Example.hs → examples/success-standard/src/Series.hs} +0 -0
  83. data/tracks/haskell/exercises/leap/examples/success-standard/package.yaml +16 -0
  84. data/tracks/haskell/exercises/leap/{src/Example.hs → examples/success-standard/src/LeapYear.hs} +0 -0
  85. data/tracks/haskell/exercises/lens-person/examples/success-standard/package.yaml +19 -0
  86. data/tracks/haskell/exercises/lens-person/{src/Example.hs → examples/success-standard/src/Person.hs} +0 -0
  87. data/tracks/haskell/exercises/linked-list/examples/success-standard/package.yaml +18 -0
  88. data/tracks/haskell/exercises/linked-list/{src/Example.hs → examples/success-standard/src/Deque.hs} +0 -0
  89. data/tracks/haskell/exercises/list-ops/examples/success-standard/package.yaml +16 -0
  90. data/tracks/haskell/exercises/list-ops/{src/Example.hs → examples/success-standard/src/ListOps.hs} +0 -0
  91. data/tracks/haskell/exercises/luhn/examples/success-standard/package.yaml +16 -0
  92. data/tracks/haskell/exercises/luhn/{src/Example.hs → examples/success-standard/src/Luhn.hs} +0 -0
  93. data/tracks/haskell/exercises/matrix/examples/success-standard/package.yaml +17 -0
  94. data/tracks/haskell/exercises/matrix/{src/Example.hs → examples/success-standard/src/Matrix.hs} +0 -0
  95. data/tracks/haskell/exercises/meetup/examples/success-standard/package.yaml +17 -0
  96. data/tracks/haskell/exercises/meetup/{src/Example.hs → examples/success-standard/src/Meetup.hs} +0 -0
  97. data/tracks/haskell/exercises/minesweeper/examples/success-standard/package.yaml +16 -0
  98. data/tracks/haskell/exercises/minesweeper/{src/Example.hs → examples/success-standard/src/Minesweeper.hs} +0 -0
  99. data/tracks/haskell/exercises/nth-prime/examples/success-standard/package.yaml +16 -0
  100. data/tracks/haskell/exercises/nth-prime/{src/Example.hs → examples/success-standard/src/Prime.hs} +0 -0
  101. data/tracks/haskell/exercises/nucleotide-count/examples/success-standard/package.yaml +17 -0
  102. data/tracks/haskell/exercises/nucleotide-count/{src/Example.hs → examples/success-standard/src/DNA.hs} +0 -0
  103. data/tracks/haskell/exercises/ocr-numbers/examples/success-standard/package.yaml +19 -0
  104. data/tracks/haskell/exercises/ocr-numbers/{src/Example.hs → examples/success-standard/src/OCR.hs} +0 -0
  105. data/tracks/haskell/exercises/octal/examples/success-standard/package.yaml +17 -0
  106. data/tracks/haskell/exercises/octal/{src/Example.hs → examples/success-standard/src/Octal.hs} +0 -0
  107. data/tracks/haskell/exercises/palindrome-products/examples/success-standard/package.yaml +16 -0
  108. data/tracks/haskell/exercises/palindrome-products/{src/Example.hs → examples/success-standard/src/Palindromes.hs} +0 -0
  109. data/tracks/haskell/exercises/parallel-letter-frequency/examples/success-standard/package.yaml +20 -0
  110. data/tracks/haskell/exercises/parallel-letter-frequency/{src/Example.hs → examples/success-standard/src/Frequency.hs} +0 -0
  111. data/tracks/haskell/exercises/pascals-triangle/examples/success-standard/package.yaml +16 -0
  112. data/tracks/haskell/exercises/pascals-triangle/{src/Example.hs → examples/success-standard/src/Triangle.hs} +0 -0
  113. data/tracks/haskell/exercises/phone-number/examples/success-standard/package.yaml +16 -0
  114. data/tracks/haskell/exercises/phone-number/{src/Example.hs → examples/success-standard/src/Phone.hs} +0 -0
  115. data/tracks/haskell/exercises/pig-latin/examples/success-standard/package.yaml +16 -0
  116. data/tracks/haskell/exercises/pig-latin/{src/Example.hs → examples/success-standard/src/PigLatin.hs} +0 -0
  117. data/tracks/haskell/exercises/pig-latin/test/Tests.hs +2 -1
  118. data/tracks/haskell/exercises/pov/examples/success-standard/package.yaml +17 -0
  119. data/tracks/haskell/exercises/pov/{src/Example.hs → examples/success-standard/src/POV.hs} +0 -0
  120. data/tracks/haskell/exercises/pov/test/Tests.hs +34 -8
  121. data/tracks/haskell/exercises/prime-factors/examples/success-standard/package.yaml +16 -0
  122. data/tracks/haskell/exercises/prime-factors/{src/Example.hs → examples/success-standard/src/PrimeFactors.hs} +0 -0
  123. data/tracks/haskell/exercises/pythagorean-triplet/examples/success-standard/package.yaml +16 -0
  124. data/tracks/haskell/exercises/pythagorean-triplet/{src/Example.hs → examples/success-standard/src/Triplet.hs} +0 -0
  125. data/tracks/haskell/exercises/queen-attack/examples/success-standard/package.yaml +16 -0
  126. data/tracks/haskell/exercises/queen-attack/{src/Example.hs → examples/success-standard/src/Queens.hs} +0 -0
  127. data/tracks/haskell/exercises/raindrops/examples/success-standard/package.yaml +16 -0
  128. data/tracks/haskell/exercises/raindrops/{src/Example.hs → examples/success-standard/src/Raindrops.hs} +0 -0
  129. data/tracks/haskell/exercises/rna-transcription/examples/success-standard/package.yaml +18 -0
  130. data/tracks/haskell/exercises/rna-transcription/{src/Example.hs → examples/success-standard/src/DNA.hs} +0 -0
  131. data/tracks/haskell/exercises/robot-name/examples/success-standard/package.yaml +18 -0
  132. data/tracks/haskell/exercises/robot-name/{src/Example.hs → examples/success-standard/src/Robot.hs} +0 -0
  133. data/tracks/haskell/exercises/robot-simulator/examples/success-standard/package.yaml +16 -0
  134. data/tracks/haskell/exercises/robot-simulator/{src/Example.hs → examples/success-standard/src/Robot.hs} +0 -0
  135. data/tracks/haskell/exercises/roman-numerals/examples/success-standard/package.yaml +16 -0
  136. data/tracks/haskell/exercises/roman-numerals/{src/Example.hs → examples/success-standard/src/Roman.hs} +0 -0
  137. data/tracks/haskell/exercises/saddle-points/examples/success-standard/package.yaml +19 -0
  138. data/tracks/haskell/exercises/saddle-points/{src/Example.hs → examples/success-standard/src/Matrix.hs} +0 -0
  139. data/tracks/haskell/exercises/say/examples/success-standard/package.yaml +18 -0
  140. data/tracks/haskell/exercises/say/{src/Example.hs → examples/success-standard/src/Say.hs} +0 -0
  141. data/tracks/haskell/exercises/say/test/Tests.hs +4 -2
  142. data/tracks/haskell/exercises/scrabble-score/examples/success-standard/package.yaml +18 -0
  143. data/tracks/haskell/exercises/scrabble-score/{src/Example.hs → examples/success-standard/src/Scrabble.hs} +0 -0
  144. data/tracks/haskell/exercises/secret-handshake/examples/success-standard/package.yaml +16 -0
  145. data/tracks/haskell/exercises/secret-handshake/{src/Example.hs → examples/success-standard/src/SecretHandshake.hs} +0 -0
  146. data/tracks/haskell/exercises/series/examples/success-standard/package.yaml +16 -0
  147. data/tracks/haskell/exercises/series/{src/Example.hs → examples/success-standard/src/Series.hs} +0 -0
  148. data/tracks/haskell/exercises/sgf-parsing/examples/success-standard/package.yaml +20 -0
  149. data/tracks/haskell/exercises/sgf-parsing/{src/Example.hs → examples/success-standard/src/Sgf.hs} +0 -0
  150. data/tracks/haskell/exercises/sieve/examples/success-standard/package.yaml +18 -0
  151. data/tracks/haskell/exercises/sieve/{src/Example.hs → examples/success-standard/src/Sieve.hs} +0 -0
  152. data/tracks/haskell/exercises/simple-cipher/examples/success-standard/package.yaml +18 -0
  153. data/tracks/haskell/exercises/simple-cipher/{src/Example.hs → examples/success-standard/src/Cipher.hs} +0 -0
  154. data/tracks/haskell/exercises/simple-linked-list/examples/success-standard/package.yaml +16 -0
  155. data/tracks/haskell/exercises/simple-linked-list/{src/Example.hs → examples/success-standard/src/LinkedList.hs} +0 -0
  156. data/tracks/haskell/exercises/space-age/examples/success-double/package.yaml +0 -3
  157. data/tracks/haskell/exercises/space-age/examples/success-double/{SpaceAge.hs → src/SpaceAge.hs} +0 -0
  158. data/tracks/haskell/exercises/space-age/examples/success-rational/package.yaml +0 -3
  159. data/tracks/haskell/exercises/space-age/examples/success-rational/{SpaceAge.hs → src/SpaceAge.hs} +0 -0
  160. data/tracks/haskell/exercises/strain/examples/success-standard/package.yaml +16 -0
  161. data/tracks/haskell/exercises/strain/{src/Example.hs → examples/success-standard/src/Strain.hs} +0 -0
  162. data/tracks/haskell/exercises/sublist/examples/success-standard/package.yaml +16 -0
  163. data/tracks/haskell/exercises/sublist/{src/Example.hs → examples/success-standard/src/Sublist.hs} +0 -0
  164. data/tracks/haskell/exercises/sum-of-multiples/examples/success-standard/package.yaml +16 -0
  165. data/tracks/haskell/exercises/sum-of-multiples/{src/Example.hs → examples/success-standard/src/SumOfMultiples.hs} +0 -0
  166. data/tracks/haskell/exercises/triangle/examples/success-standard/package.yaml +18 -0
  167. data/tracks/haskell/exercises/triangle/{src/Example.hs → examples/success-standard/src/Triangle.hs} +0 -0
  168. data/tracks/haskell/exercises/trinary/examples/success-standard/package.yaml +17 -0
  169. data/tracks/haskell/exercises/trinary/{src/Example.hs → examples/success-standard/src/Trinary.hs} +0 -0
  170. data/tracks/haskell/exercises/word-count/examples/success-newtype/package.yaml +0 -2
  171. data/tracks/haskell/exercises/word-count/examples/success-newtype/{WordCount.hs → src/WordCount.hs} +0 -0
  172. data/tracks/haskell/exercises/word-count/examples/success-simple/package.yaml +0 -2
  173. data/tracks/haskell/exercises/word-count/examples/success-simple/{WordCount.hs → src/WordCount.hs} +0 -0
  174. data/tracks/haskell/exercises/wordy/examples/success-standard/package.yaml +19 -0
  175. data/tracks/haskell/exercises/wordy/{src/Example.hs → examples/success-standard/src/WordProblem.hs} +0 -0
  176. data/tracks/haskell/exercises/zebra-puzzle/examples/success-standard/package.yaml +16 -0
  177. data/tracks/haskell/exercises/zebra-puzzle/{src/Example.hs → examples/success-standard/src/ZebraPuzzle.hs} +0 -0
  178. data/tracks/haskell/exercises/zipper/examples/success-standard/package.yaml +16 -0
  179. data/tracks/haskell/exercises/zipper/{src/Example.hs → examples/success-standard/src/Zipper.hs} +0 -0
  180. data/tracks/java/config.json +7 -1
  181. data/tracks/java/exercises/difference-of-squares/build.gradle +17 -0
  182. data/tracks/java/exercises/difference-of-squares/src/example/java/.keep +0 -0
  183. data/tracks/java/exercises/difference-of-squares/src/example/java/Difference.java +20 -0
  184. data/tracks/java/exercises/difference-of-squares/src/main/java/.keep +0 -0
  185. data/tracks/java/exercises/difference-of-squares/src/main/java/Difference.java +5 -0
  186. data/tracks/java/exercises/difference-of-squares/src/test/java/DifferenceTest.java +87 -0
  187. data/tracks/java/exercises/settings.gradle +1 -0
  188. data/tracks/kotlin/docs/TESTS.md +97 -13
  189. data/tracks/ruby/exercises/alphametics/.version +1 -1
  190. data/tracks/ruby/exercises/alphametics/alphametics_test.rb +55 -45
  191. data/tracks/ruby/exercises/alphametics/example.rb +100 -63
  192. data/tracks/ruby/exercises/alphametics/example.tt +7 -6
  193. data/tracks/ruby/lib/alphametics_cases.rb +49 -13
  194. data/tracks/ruby/lib/generator.rb +2 -1
  195. data/tracks/rust/docs/LEARNING.md +1 -0
  196. data/tracks/rust/exercises/acronym/tests/acronym.rs +6 -0
  197. metadata +164 -80
@@ -1 +1 @@
1
- 3
1
+ 4
@@ -3,64 +3,75 @@ gem 'minitest', '>= 5.0.0'
3
3
  require 'minitest/autorun'
4
4
  require_relative 'alphametics'
5
5
 
6
- # Test data version:
7
- # 8d8589f
6
+ # Test data version: 9dab356
8
7
  class AlphameticsTest < Minitest::Test
9
- def test_solve_short_puzzle
8
+
9
+ def test_puzzle_with_three_letters
10
10
  # skip
11
- expect = {
12
- 'I' => 1, 'B' => 9, 'L' => 0
13
- }
14
- actual = Alphametics.new.solve('I + BB == ILL')
15
- assert_equal(expect, actual)
11
+ input = 'I + BB == ILL'
12
+ expected = { 'B' => 9, 'I' => 1, 'L' => 0 }
13
+ assert_equal expected, Alphametics.solve(input)
16
14
  end
17
15
 
18
- # This test has been commented out due its long runtime.
19
- # def test_solve_long_puzzle
20
- # skip
21
- # expect = {
22
- # 'S' => 9, 'E' => 5, 'N' => 6, 'D' => 7,
23
- # 'M' => 1, 'O' => 0, 'R' => 8, 'Y' => 2
24
- # }
25
- # actual = Alphametics.new.solve('SEND + MORE == MONEY')
26
- # assert_equal(expect, actual)
27
- # end
28
-
29
16
  def test_solution_must_have_unique_value_for_each_letter
30
17
  skip
31
- expect = nil
32
- actual = Alphametics.new.solve('A == B')
33
- assert_equal(expect, actual)
18
+ input = 'A == B'
19
+ expected = {}
20
+ assert_equal expected, Alphametics.solve(input)
34
21
  end
35
22
 
36
23
  def test_leading_zero_solution_is_invalid
37
24
  skip
38
- expect = nil
39
- actual = Alphametics.new.solve('ACA + DD == BD')
40
- assert_equal(expect, actual)
25
+ input = 'ACA + DD == BD'
26
+ expected = {}
27
+ assert_equal expected, Alphametics.solve(input)
41
28
  end
42
29
 
43
- def test_solve_puzzle_with_four_words
30
+ def test_puzzle_with_four_letters
44
31
  skip
45
- expect = {
46
- 'E' => 4, 'G' => 2, 'H' => 5, 'I' => 0,
47
- 'L' => 1, 'S' => 9, 'T' => 7
48
- }
49
- actual = Alphametics.new.solve('HE + SEES + THE == LIGHT')
50
- assert_equal(expect, actual)
32
+ input = 'AS + A == MOM'
33
+ expected = { 'A' => 9, 'M' => 1, 'O' => 0, 'S' => 2 }
34
+ assert_equal expected, Alphametics.solve(input)
51
35
  end
52
36
 
53
- # This test has been commented out due its long runtime.
54
- # def test_solve_puzzle_with_many_words
55
- # skip
56
- # expect = {
57
- # 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7,
58
- # 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1,
59
- # 'S' => 6, 'T' => 9
60
- # }
61
- # actual = Alphametics.new.solve('AND + A + STRONG + OFFENSE + AS + A + GOOD = DEFENSE')
62
- # assert_equal(expect, actual)
63
- # end
37
+ def test_puzzle_with_six_letters
38
+ skip
39
+ input = 'NO + NO + TOO == LATE'
40
+ expected = { 'A' => 0, 'E' => 2, 'L' => 1, 'N' => 7,
41
+ 'O' => 4, 'T' => 9 }
42
+ assert_equal expected, Alphametics.solve(input)
43
+ end
44
+
45
+ def test_puzzle_with_seven_letters
46
+ skip
47
+ input = 'HE + SEES + THE == LIGHT'
48
+ expected = { 'E' => 4, 'G' => 2, 'H' => 5, 'I' => 0,
49
+ 'L' => 1, 'S' => 9, 'T' => 7 }
50
+ assert_equal expected, Alphametics.solve(input)
51
+ end
52
+
53
+ # The obvious algorithm can take a long time to solve this puzzle,
54
+ # but an optimised solution can solve it fairly quickly.
55
+ # (It's OK to submit your solution without getting this test to pass.)
56
+ def test_puzzle_with_eight_letters
57
+ skip
58
+ input = 'SEND + MORE == MONEY'
59
+ expected = { 'D' => 7, 'E' => 5, 'M' => 1, 'N' => 6,
60
+ 'O' => 0, 'R' => 8, 'S' => 9, 'Y' => 2 }
61
+ assert_equal expected, Alphametics.solve(input)
62
+ end
63
+
64
+ # The obvious algorithm can take a long time to solve this puzzle,
65
+ # but an optimised solution can solve it fairly quickly.
66
+ # (It's OK to submit your solution without getting this test to pass.)
67
+ def test_puzzle_with_ten_letters
68
+ skip
69
+ input = 'AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE'
70
+ expected = { 'A' => 5, 'D' => 3, 'E' => 4, 'F' => 7,
71
+ 'G' => 8, 'N' => 0, 'O' => 2, 'R' => 1,
72
+ 'S' => 6, 'T' => 9 }
73
+ assert_equal expected, Alphametics.solve(input)
74
+ end
64
75
 
65
76
  # Problems in exercism evolve over time, as we find better ways to ask
66
77
  # questions.
@@ -78,9 +89,8 @@ class AlphameticsTest < Minitest::Test
78
89
  #
79
90
  # If you are curious, read more about constants on RubyDoc:
80
91
  # http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html
81
-
82
92
  def test_bookkeeping
83
93
  skip
84
- assert_equal 3, BookKeeping::VERSION
94
+ assert_equal 4, BookKeeping::VERSION
85
95
  end
86
96
  end
@@ -1,98 +1,135 @@
1
1
  module BookKeeping
2
- VERSION = 3
2
+ VERSION = 4
3
3
  end
4
4
 
5
5
  class Alphametics
6
- def solve(puzzle)
7
- letters = Hash.new(0)
8
- puzzle.scan(/[a-zA-Z]/) { |w| letters[w] += 1 }
9
6
 
10
- possible_values(letters.keys) do |letters_values|
11
- return letters_values if valid?(puzzle, letters_values)
12
- end
7
+ def self.solve(equation)
8
+ new.solve(equation)
9
+ end
13
10
 
14
- nil
11
+ def solve(equation)
12
+ @prime_solver = AlphaSolver.new(equation)
13
+ solve_using_partials
15
14
  end
16
15
 
17
16
  private
18
17
 
19
- def possible_values(letters)
20
- (0..9).to_a.combination(letters.length) do |combined_integers|
21
- combined_integers.permutation do |permutated_integers|
22
- yield permutated_integers.map.with_index { |integer, index|
23
- [letters[index], integer]
24
- }.to_h
25
- end
18
+ attr_accessor :prime_solver
19
+
20
+ def solve_using_partials
21
+ prime_solver.partial_solutions.each do |partial_solution|
22
+ sub_solver = AlphaSolver.new(prime_solver.partial_equation(partial_solution))
23
+ sub_solution = sub_solver.first_solution
24
+ return sub_solution.merge(partial_solution) if sub_solution
26
25
  end
26
+ {}
27
27
  end
28
28
 
29
- def valid?(puzzle, letters_values)
30
- equation = puzzle.gsub(/[a-zA-Z]/, letters_values)
31
- Equation.new(equation).valid?
32
- end
33
29
  end
34
30
 
35
- class Equation
36
- attr_reader :equation
31
+ class AlphaSolver
37
32
 
38
- def initialize(equation)
39
- @equation = equation
33
+ def initialize(input_equation)
34
+ @input_equation = input_equation.gsub('^', '**')
35
+ @puzzle = Puzzle.new(input_equation)
40
36
  end
41
37
 
42
- def valid?
43
- return false if has_leading_zeros?
38
+ def partial_solutions
39
+ AlphaSolver.new(puzzle.simplified).all_solutions
40
+ end
44
41
 
45
- expression, result = equation.split('==')
42
+ def all_solutions
43
+ numeric_permutations.map { |values| result_table if solution?(values) }.compact
44
+ end
46
45
 
47
- numbers = []
48
- operators = []
46
+ def first_solution
47
+ numeric_permutations.each { |values| return result_table if solution?(values) }
48
+ nil
49
+ end
49
50
 
50
- expression.scan(/\d+|\+|\-|\*|\/|\^/).each do |token|
51
- case token
52
- when /^\d+$/
53
- numbers.push(token.to_i)
54
- when '+', '-', '*', '/', '^'
55
- calculate_last(numbers, operators) if has_precedence?(operators, token)
56
- operators.push(token)
57
- end
58
- end
51
+ def partial_equation(partial_solution)
52
+ input_equation.tr(partial_solution.keys.join, partial_solution.values.join)
53
+ end
59
54
 
60
- until operators.empty?
61
- calculate_last(numbers, operators)
62
- end
55
+ private
56
+
57
+ attr_reader :input_equation, :puzzle
58
+ attr_accessor :proposed_values
63
59
 
64
- numbers.last == result.to_i
60
+ def solution?(values)
61
+ self.proposed_values = values.join
62
+ proposed_equation_qualified? && proposed_equation_evaluates?
65
63
  end
66
64
 
67
- private
65
+ def proposed_equation
66
+ input_equation.tr(puzzle_letters, proposed_values)
67
+ end
68
68
 
69
- def has_leading_zeros?
70
- equation.match(/^0\d+|\D0\d+/)
69
+ def numeric_permutations
70
+ puzzle.numeric_permutations
71
71
  end
72
72
 
73
- def has_precedence?(operators, token)
74
- return false if operators.empty?
75
- prev_operator = operators.last
73
+ def puzzle_letters
74
+ puzzle.letters
75
+ end
76
76
 
77
- case token
78
- when '+', '-'
79
- prev_operator == '*' || prev_operator == '/' || prev_operator == '^'
80
- when '*', '/'
81
- prev_operator == '^'
82
- else
83
- false
84
- end
77
+ def proposed_equation_qualified?
78
+ (proposed_equation =~ /\b0\d+/).nil?
85
79
  end
86
80
 
87
- def calculate_last(numbers, operators)
88
- right = numbers.pop
89
- left = numbers.pop
90
- operator = as_ruby_operator(operators.pop)
91
- result = left.send(operator, right)
92
- numbers.push(result)
81
+ def proposed_equation_evaluates?
82
+ eval(proposed_equation)
93
83
  end
94
84
 
95
- def as_ruby_operator(operator)
96
- operator == '^' ? '**' : operator
85
+ def result_table
86
+ Hash[puzzle_letters.chars.zip(result_numbers)]
97
87
  end
88
+
89
+ def result_numbers
90
+ proposed_values.chars.map(&:to_i)
91
+ end
92
+
98
93
  end
94
+
95
+ class Puzzle
96
+
97
+ PATTERNS = {mod_10: ' % 10',
98
+ adjacent_letters: /(\b)([A-Z]{1,})([A-Z])/,
99
+ equation_left_side: /(.*)( == )/}
100
+
101
+ def initialize(string_equation)
102
+ @string_equation = string_equation
103
+ end
104
+
105
+ def letters
106
+ @letters ||= string_equation.scan(/[A-Z]/).uniq.join
107
+ end
108
+
109
+ def numeric_permutations
110
+ @numeric_permutations ||= unused_numbers.to_a.permutation(letter_count)
111
+ end
112
+
113
+ def simplified
114
+ @simplified ||= string_equation
115
+ .gsub(PATTERNS[:adjacent_letters], "\\1\\3")
116
+ .gsub(PATTERNS[:equation_left_side], "(\\1)#{PATTERNS[:mod_10]}\\2")
117
+ end
118
+
119
+ private
120
+
121
+ attr_reader :string_equation
122
+
123
+ def letter_count
124
+ @letter_count ||= letters.length
125
+ end
126
+
127
+ def unused_numbers
128
+ @unused_numbers ||= (0..9).to_a.map(&:to_s) - used_numbers
129
+ end
130
+
131
+ def used_numbers
132
+ @used_numbers ||= string_equation.gsub(PATTERNS[:mod_10], '').scan(/\d/).uniq
133
+ end
134
+
135
+ end
@@ -3,16 +3,17 @@ gem 'minitest', '>= 5.0.0'
3
3
  require 'minitest/autorun'
4
4
  require_relative 'alphametics'
5
5
 
6
- # Test data version:
7
- # <%= sha1 %>
8
- class AlphameticsTest < Minitest::Test<% test_cases.each do |test_case| %>
6
+ # Test data version: <%= sha1 %>
7
+ class AlphameticsTest < Minitest::Test
8
+ <% test_cases.each do |test_case| %>
9
+
10
+ <%= test_case.runtime_comment %>
9
11
  def <%= test_case.test_name %>
10
12
  <%= test_case.skipped %>
11
- expect = <%= test_case.expect %>
12
- actual = <%= test_case.work_load %>
13
- assert_equal(expect, actual)
13
+ <%= test_case.workload %>
14
14
  end
15
15
  <% end %>
16
+
16
17
  <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
17
18
  def test_bookkeeping
18
19
  skip
@@ -1,30 +1,66 @@
1
1
  class AlphameticsCase < OpenStruct
2
- PAIRS_PER_LINE = 4
3
- SPACE = ->(num) { ' ' * num }
4
-
5
2
  def test_name
6
3
  "test_#{description.tr(' ', '_')}"
7
4
  end
8
5
 
9
- def work_load
10
- "Alphametics.new.solve('#{puzzle}')"
6
+ def skipped
7
+ index.zero? ? '# skip' : 'skip'
8
+ end
9
+
10
+ def input
11
+ "'#{puzzle}'"
11
12
  end
12
13
 
13
14
  def expect
14
- return 'nil' if expected.nil?
15
- expected_values
15
+ expected.nil? ? {} : expected_values
16
+ end
17
+
18
+ def workload
19
+ body =
20
+ "input = %s\n" % input,
21
+ "expected = %s\n" % expect,
22
+ "assert_equal expected, Alphametics.solve(input)"
23
+ indent(body,4)
24
+ end
25
+
26
+ def runtime_comment
27
+ if slow?
28
+ comments =
29
+ '',
30
+ "# The obvious algorithm can take a long time to solve this puzzle,\n",
31
+ "# but an optimised solution can solve it fairly quickly.\n",
32
+ "# (It's OK to submit your solution without getting this test to pass.)\n"
33
+ indent(comments,2)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def slow?
40
+ (expected||{}).size > 7
16
41
  end
17
42
 
18
43
  def expected_values
19
- "{\n" << expected.each_slice(PAIRS_PER_LINE).map do |pairs|
20
- '%s'.prepend(SPACE[6]) %
21
- pairs.map { |k, v| "'#{k}' => #{v}" }.join(', ')
22
- end.join(",\n") << "\n }"
44
+ "{ #{indent(expected_values_as_lines,17)} }"
23
45
  end
24
46
 
25
- def skipped
26
- index.zero? ? '# skip' : 'skip'
47
+ def expected_values_as_lines
48
+ lines = expected_values_as_strings.each_slice(4).map { |line| line.join(', ') }
49
+ add_trailing_comma_and_newline(lines)
50
+ end
51
+
52
+ def expected_values_as_strings
53
+ expected.sort.map { |(key,value)| "'#{key}' => #{value}" }
27
54
  end
55
+
56
+ def add_trailing_comma_and_newline(lines)
57
+ lines[0...-1].map { |line| "#{line},\n" }.push(lines.last)
58
+ end
59
+
60
+ def indent(lines, spaces)
61
+ lines.join(' ' * spaces)
62
+ end
63
+
28
64
  end
29
65
 
30
66
  AlphameticsCases = proc do |data|
@@ -64,7 +64,8 @@ class Generator
64
64
 
65
65
  def generate_test_file
66
66
  File.open(path_to("#{name.gsub(/[ -]/, '_')}_test.rb"), 'w') do |f|
67
- f.write ERB.new(File.read(path_to('example.tt'))).result binding
67
+ template = File.read(path_to('example.tt'))
68
+ f.write ERB.new(template, nil, '<>').result binding
68
69
  end
69
70
  end
70
71
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  * [The Rust Programming Language](http://doc.rust-lang.org/stable/book/) is a great resource for getting started with Rust as well as diving deeper into specific features of Rust.
4
4
  * [Rust by Example](http://rustbyexample.com) shows you examples of the most common things you will be writing in Rust.
5
+ * [Into_rust()](http://intorust.com/) "Screencasts for learning Rust."
5
6
  * [Rustlings](https://github.com/carols10cents/rustlings) "Small exercises to get you used to reading and writing Rust code."
6
7
  * [#rust-beginners](https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-beginners) "an IRC channel that loves answering questions at any depth"
7
8
  * The [Rust User Forum](http://users.rust-lang.org) answers questions of all levels