trackler 2.0.0.2 → 2.0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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