trackler 2.2.1.85 → 2.2.1.86

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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/alphametics/canonical-data.json +29 -11
  4. data/problem-specifications/exercises/binary-search-tree/canonical-data.json +177 -0
  5. data/problem-specifications/package.json +2 -2
  6. data/problem-specifications/yarn.lock +61 -51
  7. data/tracks/bash/CONTRIBUTING.md +10 -6
  8. data/tracks/bash/README.md +1 -0
  9. data/tracks/bash/exercises/acronym/README.md +1 -1
  10. data/tracks/bash/exercises/anagram/README.md +1 -1
  11. data/tracks/bash/exercises/anagram/{anagram_tests.sh → anagram_test.sh} +0 -0
  12. data/tracks/bash/exercises/armstrong-numbers/armstrong_numbers_test.sh +25 -17
  13. data/tracks/bash/exercises/armstrong-numbers/example.sh +18 -12
  14. data/tracks/bash/exercises/atbash-cipher/README.md +1 -1
  15. data/tracks/bash/exercises/atbash-cipher/{atbash_cipher_tests.sh → atbash_cipher_test.sh} +0 -0
  16. data/tracks/bash/exercises/difference-of-squares/README.md +1 -1
  17. data/tracks/bash/exercises/gigasecond/README.md +1 -1
  18. data/tracks/bash/exercises/hamming/README.md +1 -1
  19. data/tracks/bash/exercises/hello-world/README.md +1 -1
  20. data/tracks/bash/exercises/leap/README.md +1 -1
  21. data/tracks/bash/exercises/luhn/README.md +1 -1
  22. data/tracks/bash/exercises/nucleotide-count/README.md +1 -1
  23. data/tracks/bash/exercises/pangram/README.md +1 -1
  24. data/tracks/bash/exercises/pangram/{pangram_tests.sh → pangram_test.sh} +0 -0
  25. data/tracks/bash/exercises/phone-number/README.md +1 -1
  26. data/tracks/bash/exercises/phone-number/{phone_number_tests.sh → phone_number_test.sh} +0 -0
  27. data/tracks/bash/exercises/raindrops/README.md +1 -1
  28. data/tracks/bash/exercises/rna-transcription/README.md +1 -1
  29. data/tracks/bash/exercises/triangle/example.sh +23 -4
  30. data/tracks/bash/exercises/triangle/triangle_test.sh +17 -0
  31. data/tracks/bash/exercises/two-fer/README.md +1 -1
  32. data/tracks/bash/exercises/word-count/README.md +1 -1
  33. data/tracks/c/config.json +11 -0
  34. data/tracks/c/exercises/complex-numbers/README.md +67 -0
  35. data/tracks/c/exercises/complex-numbers/makefile +27 -0
  36. data/tracks/c/exercises/complex-numbers/src/complex_numbers.c +46 -0
  37. data/tracks/c/exercises/complex-numbers/src/complex_numbers.h +19 -0
  38. data/tracks/c/exercises/complex-numbers/src/example.c +80 -0
  39. data/tracks/c/exercises/complex-numbers/test/test_complex_numbers.c +397 -0
  40. data/tracks/c/exercises/complex-numbers/test/vendor/unity.c +1300 -0
  41. data/tracks/c/exercises/complex-numbers/test/vendor/unity.h +274 -0
  42. data/tracks/c/exercises/complex-numbers/test/vendor/unity_internals.h +701 -0
  43. data/tracks/crystal/.github/stale.yml +18 -0
  44. data/tracks/csharp/exercises/bob/README.md +3 -2
  45. data/tracks/ecmascript/config.json +4 -4
  46. data/tracks/fsharp/exercises/bob/README.md +4 -2
  47. data/tracks/fsharp/exercises/react/ReactTest.fs +137 -74
  48. data/tracks/fsharp/generators/Generators.fs +76 -0
  49. data/tracks/go/exercises/tree-building/tree_test.go +15 -0
  50. data/tracks/haskell/.travis.yml +1 -1
  51. data/tracks/haskell/exercises/accumulate/stack.yaml +1 -1
  52. data/tracks/haskell/exercises/acronym/package.yaml +1 -1
  53. data/tracks/haskell/exercises/acronym/stack.yaml +1 -1
  54. data/tracks/haskell/exercises/all-your-base/package.yaml +1 -1
  55. data/tracks/haskell/exercises/all-your-base/stack.yaml +1 -1
  56. data/tracks/haskell/exercises/all-your-base/test/Tests.hs +6 -6
  57. data/tracks/haskell/exercises/allergies/package.yaml +1 -1
  58. data/tracks/haskell/exercises/allergies/stack.yaml +1 -1
  59. data/tracks/haskell/exercises/alphametics/stack.yaml +1 -1
  60. data/tracks/haskell/exercises/anagram/package.yaml +1 -1
  61. data/tracks/haskell/exercises/anagram/stack.yaml +1 -1
  62. data/tracks/haskell/exercises/atbash-cipher/package.yaml +1 -1
  63. data/tracks/haskell/exercises/atbash-cipher/stack.yaml +1 -1
  64. data/tracks/haskell/exercises/bank-account/stack.yaml +1 -1
  65. data/tracks/haskell/exercises/beer-song/stack.yaml +1 -1
  66. data/tracks/haskell/exercises/binary-search-tree/package.yaml +1 -1
  67. data/tracks/haskell/exercises/binary-search-tree/stack.yaml +1 -1
  68. data/tracks/haskell/exercises/binary-search-tree/test/Tests.hs +3 -0
  69. data/tracks/haskell/exercises/binary/stack.yaml +1 -1
  70. data/tracks/haskell/exercises/bob/package.yaml +1 -1
  71. data/tracks/haskell/exercises/bob/stack.yaml +1 -1
  72. data/tracks/haskell/exercises/bowling/stack.yaml +1 -1
  73. data/tracks/haskell/exercises/bracket-push/package.yaml +1 -1
  74. data/tracks/haskell/exercises/bracket-push/stack.yaml +1 -1
  75. data/tracks/haskell/exercises/change/package.yaml +1 -1
  76. data/tracks/haskell/exercises/change/stack.yaml +1 -1
  77. data/tracks/haskell/exercises/clock/stack.yaml +1 -1
  78. data/tracks/haskell/exercises/collatz-conjecture/package.yaml +1 -1
  79. data/tracks/haskell/exercises/collatz-conjecture/stack.yaml +1 -1
  80. data/tracks/haskell/exercises/complex-numbers/stack.yaml +1 -1
  81. data/tracks/haskell/exercises/connect/package.yaml +1 -1
  82. data/tracks/haskell/exercises/connect/stack.yaml +1 -1
  83. data/tracks/haskell/exercises/crypto-square/package.yaml +1 -1
  84. data/tracks/haskell/exercises/crypto-square/stack.yaml +1 -1
  85. data/tracks/haskell/exercises/custom-set/stack.yaml +1 -1
  86. data/tracks/haskell/exercises/diamond/package.yaml +1 -1
  87. data/tracks/haskell/exercises/diamond/stack.yaml +1 -1
  88. data/tracks/haskell/exercises/difference-of-squares/package.yaml +1 -1
  89. data/tracks/haskell/exercises/difference-of-squares/stack.yaml +1 -1
  90. data/tracks/haskell/exercises/dominoes/package.yaml +1 -1
  91. data/tracks/haskell/exercises/dominoes/stack.yaml +1 -1
  92. data/tracks/haskell/exercises/etl/stack.yaml +1 -1
  93. data/tracks/haskell/exercises/food-chain/stack.yaml +1 -1
  94. data/tracks/haskell/exercises/forth/stack.yaml +1 -1
  95. data/tracks/haskell/exercises/gigasecond/stack.yaml +1 -1
  96. data/tracks/haskell/exercises/go-counting/stack.yaml +1 -1
  97. data/tracks/haskell/exercises/grade-school/stack.yaml +1 -1
  98. data/tracks/haskell/exercises/grains/stack.yaml +1 -1
  99. data/tracks/haskell/exercises/hamming/stack.yaml +1 -1
  100. data/tracks/haskell/exercises/hello-world/stack.yaml +1 -1
  101. data/tracks/haskell/exercises/hexadecimal/stack.yaml +1 -1
  102. data/tracks/haskell/exercises/house/stack.yaml +1 -1
  103. data/tracks/haskell/exercises/isbn-verifier/examples/success-standard/src/IsbnVerifier.hs +1 -0
  104. data/tracks/haskell/exercises/isbn-verifier/package.yaml +1 -1
  105. data/tracks/haskell/exercises/isbn-verifier/stack.yaml +1 -1
  106. data/tracks/haskell/exercises/isbn-verifier/test/Tests.hs +4 -0
  107. data/tracks/haskell/exercises/isogram/stack.yaml +1 -1
  108. data/tracks/haskell/exercises/kindergarten-garden/stack.yaml +1 -1
  109. data/tracks/haskell/exercises/largest-series-product/stack.yaml +1 -1
  110. data/tracks/haskell/exercises/leap/stack.yaml +1 -1
  111. data/tracks/haskell/exercises/lens-person/stack.yaml +1 -1
  112. data/tracks/haskell/exercises/linked-list/stack.yaml +1 -1
  113. data/tracks/haskell/exercises/list-ops/stack.yaml +1 -1
  114. data/tracks/haskell/exercises/luhn/package.yaml +1 -1
  115. data/tracks/haskell/exercises/luhn/stack.yaml +1 -1
  116. data/tracks/haskell/exercises/luhn/test/Tests.hs +1 -1
  117. data/tracks/haskell/exercises/matrix/stack.yaml +1 -1
  118. data/tracks/haskell/exercises/meetup/package.yaml +1 -1
  119. data/tracks/haskell/exercises/meetup/stack.yaml +1 -1
  120. data/tracks/haskell/exercises/minesweeper/stack.yaml +1 -1
  121. data/tracks/haskell/exercises/nth-prime/stack.yaml +1 -1
  122. data/tracks/haskell/exercises/nucleotide-count/stack.yaml +1 -1
  123. data/tracks/haskell/exercises/ocr-numbers/stack.yaml +1 -1
  124. data/tracks/haskell/exercises/octal/stack.yaml +1 -1
  125. data/tracks/haskell/exercises/palindrome-products/stack.yaml +1 -1
  126. data/tracks/haskell/exercises/pangram/stack.yaml +1 -1
  127. data/tracks/haskell/exercises/parallel-letter-frequency/stack.yaml +1 -1
  128. data/tracks/haskell/exercises/pascals-triangle/stack.yaml +1 -1
  129. data/tracks/haskell/exercises/perfect-numbers/stack.yaml +1 -1
  130. data/tracks/haskell/exercises/phone-number/stack.yaml +1 -1
  131. data/tracks/haskell/exercises/pig-latin/stack.yaml +1 -1
  132. data/tracks/haskell/exercises/pov/stack.yaml +1 -1
  133. data/tracks/haskell/exercises/prime-factors/stack.yaml +1 -1
  134. data/tracks/haskell/exercises/pythagorean-triplet/stack.yaml +1 -1
  135. data/tracks/haskell/exercises/queen-attack/stack.yaml +1 -1
  136. data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +1 -1
  137. data/tracks/haskell/exercises/rail-fence-cipher/stack.yaml +1 -1
  138. data/tracks/haskell/exercises/raindrops/stack.yaml +1 -1
  139. data/tracks/haskell/exercises/rna-transcription/package.yaml +1 -1
  140. data/tracks/haskell/exercises/rna-transcription/stack.yaml +1 -1
  141. data/tracks/haskell/exercises/rna-transcription/test/Tests.hs +0 -12
  142. data/tracks/haskell/exercises/robot-name/stack.yaml +1 -1
  143. data/tracks/haskell/exercises/robot-simulator/stack.yaml +1 -1
  144. data/tracks/haskell/exercises/roman-numerals/stack.yaml +1 -1
  145. data/tracks/haskell/exercises/rotational-cipher/stack.yaml +1 -1
  146. data/tracks/haskell/exercises/run-length-encoding/stack.yaml +1 -1
  147. data/tracks/haskell/exercises/saddle-points/stack.yaml +1 -1
  148. data/tracks/haskell/exercises/say/stack.yaml +1 -1
  149. data/tracks/haskell/exercises/scrabble-score/stack.yaml +1 -1
  150. data/tracks/haskell/exercises/secret-handshake/stack.yaml +1 -1
  151. data/tracks/haskell/exercises/series/stack.yaml +1 -1
  152. data/tracks/haskell/exercises/sgf-parsing/stack.yaml +1 -1
  153. data/tracks/haskell/exercises/sieve/stack.yaml +1 -1
  154. data/tracks/haskell/exercises/simple-cipher/stack.yaml +1 -1
  155. data/tracks/haskell/exercises/simple-linked-list/stack.yaml +1 -1
  156. data/tracks/haskell/exercises/space-age/stack.yaml +1 -1
  157. data/tracks/haskell/exercises/spiral-matrix/stack.yaml +1 -1
  158. data/tracks/haskell/exercises/strain/stack.yaml +1 -1
  159. data/tracks/haskell/exercises/sublist/stack.yaml +1 -1
  160. data/tracks/haskell/exercises/sum-of-multiples/stack.yaml +1 -1
  161. data/tracks/haskell/exercises/triangle/stack.yaml +1 -1
  162. data/tracks/haskell/exercises/trinary/stack.yaml +1 -1
  163. data/tracks/haskell/exercises/twelve-days/stack.yaml +1 -1
  164. data/tracks/haskell/exercises/word-count/stack.yaml +1 -1
  165. data/tracks/haskell/exercises/wordy/stack.yaml +1 -1
  166. data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -1
  167. data/tracks/haskell/exercises/zipper/stack.yaml +1 -1
  168. data/tracks/java/config.json +12 -0
  169. data/tracks/java/exercises/alphametics/.meta/src/reference/java/Alphametics.java +125 -0
  170. data/tracks/java/exercises/alphametics/.meta/src/reference/java/UnsolvablePuzzleException.java +2 -0
  171. data/tracks/java/exercises/alphametics/.meta/src/version +1 -0
  172. data/tracks/java/exercises/alphametics/README.md +47 -0
  173. data/tracks/java/exercises/alphametics/build.gradle +18 -0
  174. data/tracks/java/exercises/alphametics/src/main/java/.keep +0 -0
  175. data/tracks/java/exercises/alphametics/src/main/java/UnsolvablePuzzleException.java +2 -0
  176. data/tracks/java/exercises/alphametics/src/test/java/AlphameticsTest.java +150 -0
  177. data/tracks/java/exercises/beer-song/.meta/src/reference/java/BeerSong.java +5 -4
  178. data/tracks/java/exercises/beer-song/.meta/version +1 -0
  179. data/tracks/java/exercises/beer-song/src/test/java/BeerSongTest.java +24 -16
  180. data/tracks/java/exercises/binary-search/.meta/version +1 -0
  181. data/tracks/java/exercises/book-store/.meta/version +1 -0
  182. data/tracks/java/exercises/book-store/src/test/java/BookStoreTest.java +15 -8
  183. data/tracks/java/exercises/circular-buffer/.meta/version +1 -0
  184. data/tracks/java/exercises/list-ops/.meta/version +1 -1
  185. data/tracks/java/exercises/list-ops/src/test/java/ListOpsTest.java +1 -1
  186. data/tracks/java/exercises/nth-prime/.meta/version +1 -0
  187. data/tracks/java/exercises/settings.gradle +1 -0
  188. data/tracks/java/exercises/tournament/.meta/version +1 -0
  189. data/tracks/java/exercises/transpose/.meta/version +1 -0
  190. data/tracks/java/exercises/transpose/src/test/java/TransposeTest.java +29 -74
  191. data/tracks/java/exercises/wordy/.meta/version +1 -0
  192. data/tracks/javascript/.eslintignore +0 -1
  193. data/tracks/javascript/config.json +13 -3
  194. data/tracks/javascript/exercises/bowling/example.js +24 -10
  195. data/tracks/javascript/exercises/forth/README.md +56 -0
  196. data/tracks/javascript/exercises/forth/example.js +66 -0
  197. data/tracks/javascript/exercises/forth/forth.spec.js +259 -0
  198. data/tracks/lua/config.json +92 -81
  199. data/tracks/lua/exercises/accumulate/README.md +42 -0
  200. data/tracks/lua/exercises/beer-song/README.md +1 -1
  201. data/tracks/lua/exercises/bob/README.md +2 -0
  202. data/tracks/lua/exercises/crypto-square/README.md +6 -4
  203. data/tracks/lua/exercises/house/README.md +1 -1
  204. data/tracks/lua/exercises/isbn-verifier/README.md +25 -20
  205. data/tracks/lua/exercises/kindergarten-garden/README.md +3 -3
  206. data/tracks/lua/exercises/meetup/README.md +16 -12
  207. data/tracks/lua/exercises/nucleotide-count/README.md +2 -2
  208. data/tracks/lua/exercises/phone-number/README.md +1 -1
  209. data/tracks/lua/exercises/pov/README.md +0 -2
  210. data/tracks/lua/exercises/queen-attack/README.md +22 -22
  211. data/tracks/lua/exercises/rectangles/README.md +9 -9
  212. data/tracks/lua/exercises/reverse-string/README.md +23 -0
  213. data/tracks/lua/exercises/reverse-string/example.lua +7 -0
  214. data/tracks/lua/exercises/reverse-string/reverse-string_spec.lua +24 -0
  215. data/tracks/lua/exercises/secret-handshake/README.md +1 -1
  216. data/tracks/lua/exercises/space-age/README.md +1 -2
  217. data/tracks/lua/exercises/sum-of-multiples/README.md +3 -3
  218. data/tracks/perl6/exercises/two-fer/README.md +1 -1
  219. data/tracks/python/exercises/luhn/luhn_test.py +1 -1
  220. metadata +39 -6
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1,5 +1,5 @@
1
1
  name: rail-fence-cipher
2
- version: 1.1.0.1
2
+ version: 1.0.1.2
3
3
 
4
4
  dependencies:
5
5
  - base
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1,5 +1,5 @@
1
1
  name: rna-transcription
2
- version: 1.0.1.4
2
+ version: 1.1.0.5
3
3
 
4
4
  dependencies:
5
5
  - base
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -40,16 +40,4 @@ cases = [ Case { description = "RNA complement of cytosine is guanine"
40
40
  , dna = "ACGTGGTCTTAA"
41
41
  , expected = Just "UGCACCAGAAUU"
42
42
  }
43
- , Case { description = "correctly handles invalid input (RNA instead of DNA)"
44
- , dna = "U"
45
- , expected = Nothing
46
- }
47
- , Case { description = "correctly handles completely invalid DNA input"
48
- , dna = "XXX"
49
- , expected = Nothing
50
- }
51
- , Case { description = "correctly handles partially invalid DNA input"
52
- , dna = "ACGTXXXCTTAA"
53
- , expected = Nothing
54
- }
55
43
  ]
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -1 +1 @@
1
- resolver: lts-9.11
1
+ resolver: lts-10.2
@@ -612,6 +612,18 @@
612
612
  "unlocked_by": "rotational-cipher",
613
613
  "uuid": "d36ce010-210f-4e9a-9d6c-cb933e0a59af"
614
614
  },
615
+ {
616
+ "core": false,
617
+ "difficulty": 6,
618
+ "slug": "alphametics",
619
+ "topics": [
620
+ "mathematics",
621
+ "logic",
622
+ "conditionals"
623
+ ],
624
+ "unlocked_by": "secret-handshake",
625
+ "uuid": "0639a1f8-5af4-4877-95c1-5db8e97c30bf"
626
+ },
615
627
  {
616
628
  "core": false,
617
629
  "difficulty": 6,
@@ -0,0 +1,125 @@
1
+ import java.util.ArrayList;
2
+ import java.util.Arrays;
3
+ import java.util.Collections;
4
+ import java.util.LinkedHashMap;
5
+ import java.util.LinkedHashSet;
6
+ import java.util.List;
7
+ import java.util.Map;
8
+ import java.util.Optional;
9
+ import java.util.Set;
10
+ import java.util.stream.Collectors;
11
+
12
+ public class Alphametics {
13
+ private final List<String> wordsToSum;
14
+ private final String wordResult;
15
+
16
+ Alphametics(String userInput) {
17
+ String[] questionAndAnswer = userInput.split("==");
18
+ wordsToSum = Arrays.stream(questionAndAnswer[0].split("\\+"))
19
+ .map(String::new)
20
+ .map(String::trim)
21
+ .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
22
+ wordResult = questionAndAnswer[1].trim();
23
+ }
24
+
25
+ Map<Character, Integer> solve() throws UnsolvablePuzzleException {
26
+ AlphameticsRecursion solver = new AlphameticsRecursion(getDistinctCharacters());
27
+ solver.generate();
28
+ return solver.get().orElseThrow(UnsolvablePuzzleException::new);
29
+ }
30
+
31
+ /**
32
+ * Returns the list of distinct characters in this alphametic puzzle.
33
+ */
34
+ private List<Character> getDistinctCharacters() {
35
+ Set<Character> distinctCharacters = new LinkedHashSet<>();
36
+ wordsToSum.forEach(word -> distinctCharacters.addAll(toChar(word)));
37
+ distinctCharacters.addAll(toChar(wordResult));
38
+
39
+ return new ArrayList<>(distinctCharacters);
40
+ }
41
+
42
+ private List<Character> toChar(String toChar) {
43
+ return toChar.chars()
44
+ .mapToObj(c -> (char) c)
45
+ .collect(Collectors.toList());
46
+ }
47
+
48
+ private class AlphameticsRecursion {
49
+ private final List<Character> characters;
50
+ private LinkedHashMap<Character, Integer> validPermutation;
51
+
52
+ private AlphameticsRecursion(List<Character> characters) {
53
+ this.characters = characters;
54
+ }
55
+
56
+ private void generate() {
57
+ generate(new LinkedHashMap<>(), 0, new boolean[10]);
58
+ }
59
+
60
+ private void generate(LinkedHashMap<Character, Integer> permutation, int index, boolean[] isDigitsUsed) {
61
+ // base case
62
+ if (index == characters.size()) {
63
+ if (!isLeadingDigitZero(permutation) && isSumTally(permutation)) {
64
+ validPermutation = new LinkedHashMap<>(permutation);
65
+ }
66
+ return;
67
+ }
68
+
69
+ for (int i = 0; i <= 9; i++) { // loop through digits 0 to 9
70
+ if (isDigitsUsed[i]) {
71
+ continue;
72
+ }
73
+
74
+ permutation.put(characters.get(index), i);
75
+ isDigitsUsed[i] = true;
76
+ generate(permutation, index + 1, isDigitsUsed);
77
+ isDigitsUsed[i] = false;
78
+ }
79
+ }
80
+
81
+ private Optional<LinkedHashMap<Character, Integer>> get() {
82
+ return Optional.ofNullable(validPermutation);
83
+ }
84
+
85
+ /**
86
+ * Returns true if the mapping letters to digits using {@code letterToDigit} will result in having zero as a
87
+ * leading digit.
88
+ */
89
+ private boolean isLeadingDigitZero(Map<Character, Integer> letterToDigit) {
90
+ return letterToDigit.keySet().stream()
91
+ .filter(key -> letterToDigit.get(key) == 0) // Find the character that is mapped to digit 0
92
+ .filter(charMappedToZero -> wordResult.charAt(0) == charMappedToZero // If the first character in
93
+ // wordResult is mapped to 0
94
+ || wordsToSum.stream() // If the first character in any of wordsToSum is mapped to 0
95
+ .map(word -> word.charAt(0))
96
+ .anyMatch(character -> character == charMappedToZero))
97
+ .count() == 1; // One letter maps to zero and is a leading character
98
+ }
99
+
100
+ /**
101
+ * Returns true if the {@code letterToDigit} solves the alphametic puzzle.
102
+ */
103
+ private boolean isSumTally(Map<Character, Integer> letterToDigit) {
104
+ long actualSum = wordsToSum.stream()
105
+ .mapToLong(word -> mapToNumber(letterToDigit, word))
106
+ .sum();
107
+ long expectedSum = mapToNumber(letterToDigit, wordResult);
108
+ return actualSum == expectedSum;
109
+ }
110
+
111
+ /**
112
+ * Returns the long value of {@code word}, mapped using {@code letterToDigit}.
113
+ */
114
+ private long mapToNumber(Map<Character, Integer> letterToDigit, String word) {
115
+ StringBuilder builder = new StringBuilder();
116
+
117
+ for (int i = 0; i < word.length(); i++) {
118
+ int digit = letterToDigit.get(word.charAt(i));
119
+ builder.append(digit);
120
+ }
121
+
122
+ return Long.parseLong(builder.toString());
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,2 @@
1
+ class UnsolvablePuzzleException extends Exception {
2
+ }
@@ -0,0 +1,47 @@
1
+ # Alphametics
2
+
3
+ Write a function to solve alphametics puzzles.
4
+
5
+ [Alphametics](https://en.wikipedia.org/wiki/Alphametics) is a puzzle where
6
+ letters in words are replaced with numbers.
7
+
8
+ For example `SEND + MORE = MONEY`:
9
+
10
+ ```text
11
+ S E N D
12
+ M O R E +
13
+ -----------
14
+ M O N E Y
15
+ ```
16
+
17
+ Replacing these with valid numbers gives:
18
+
19
+ ```text
20
+ 9 5 6 7
21
+ 1 0 8 5 +
22
+ -----------
23
+ 1 0 6 5 2
24
+ ```
25
+
26
+ This is correct because every letter is replaced by a different number and the
27
+ words, translated into numbers, then make a valid sum.
28
+
29
+ Each letter must represent a different digit, and the leading digit of
30
+ a multi-digit number must not be zero.
31
+
32
+ Write a function to solve alphametics puzzles.
33
+
34
+ # Running the tests
35
+
36
+ You can run all the tests for an exercise by entering
37
+
38
+ ```sh
39
+ $ gradle test
40
+ ```
41
+
42
+ in your terminal.
43
+
44
+
45
+ ## Submitting Incomplete Solutions
46
+
47
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,18 @@
1
+ apply plugin: "java"
2
+ apply plugin: "eclipse"
3
+ apply plugin: "idea"
4
+
5
+ repositories {
6
+ mavenCentral()
7
+ }
8
+
9
+ dependencies {
10
+ testCompile "junit:junit:4.12"
11
+ }
12
+
13
+ test {
14
+ testLogging {
15
+ exceptionFormat = 'full'
16
+ events = ["passed", "failed", "skipped"]
17
+ }
18
+ }
@@ -0,0 +1,2 @@
1
+ class UnsolvablePuzzleException extends Exception {
2
+ }
@@ -0,0 +1,150 @@
1
+ import org.junit.Ignore;
2
+ import org.junit.Rule;
3
+ import org.junit.Test;
4
+ import org.junit.rules.ExpectedException;
5
+
6
+ import java.util.Arrays;
7
+ import java.util.Collections;
8
+ import java.util.LinkedHashMap;
9
+ import java.util.List;
10
+ import java.util.Map;
11
+
12
+ import static org.hamcrest.CoreMatchers.*;
13
+ import static org.junit.Assert.*;
14
+
15
+ public class AlphameticsTest {
16
+ @Rule
17
+ public ExpectedException expectedException = ExpectedException.none();
18
+
19
+ @Test
20
+ public void testThreeLetters() throws UnsolvablePuzzleException {
21
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
22
+ expected.put('I', 1);
23
+ expected.put('B', 9);
24
+ expected.put('L', 0);
25
+
26
+ assertEquals(expected, new Alphametics("I + BB == ILL").solve());
27
+ }
28
+
29
+ @Ignore("Remove to run test")
30
+ @Test
31
+ public void testUniqueValue() throws UnsolvablePuzzleException {
32
+ expectedException.expect(UnsolvablePuzzleException.class);
33
+ new Alphametics("A == B").solve();
34
+ }
35
+
36
+ @Ignore("Remove to run test")
37
+ @Test
38
+ public void testLeadingZero() throws UnsolvablePuzzleException {
39
+ expectedException.expect(UnsolvablePuzzleException.class);
40
+ assertNull(new Alphametics("ACA + DD == BD").solve());
41
+ }
42
+
43
+ @Ignore("Remove to run test")
44
+ @Test
45
+ public void testFourLetters() throws UnsolvablePuzzleException {
46
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
47
+ expected.put('A', 9);
48
+ expected.put('S', 2);
49
+ expected.put('M', 1);
50
+ expected.put('O', 0);
51
+
52
+ assertEquals(expected, new Alphametics("AS + A == MOM").solve());
53
+ }
54
+
55
+ @Ignore("Remove to run test")
56
+ @Test
57
+ public void testSixLetters() throws UnsolvablePuzzleException {
58
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
59
+ expected.put('N', 7);
60
+ expected.put('O', 4);
61
+ expected.put('T', 9);
62
+ expected.put('L', 1);
63
+ expected.put('A', 0);
64
+ expected.put('E', 2);
65
+
66
+ assertEquals(expected, new Alphametics("NO + NO + TOO == LATE").solve());
67
+ }
68
+
69
+ @Ignore("Remove to run test")
70
+ @Test
71
+ public void testSevenLetters() throws UnsolvablePuzzleException {
72
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
73
+ expected.put('E', 4);
74
+ expected.put('G', 2);
75
+ expected.put('H', 5);
76
+ expected.put('I', 0);
77
+ expected.put('L', 1);
78
+ expected.put('S', 9);
79
+ expected.put('T', 7);
80
+
81
+ assertEquals(expected, new Alphametics("HE + SEES + THE == LIGHT").solve());
82
+ }
83
+
84
+ @Ignore("Remove to run test")
85
+ @Test
86
+ public void testEightLetters() throws UnsolvablePuzzleException {
87
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
88
+ expected.put('S', 9);
89
+ expected.put('E', 5);
90
+ expected.put('N', 6);
91
+ expected.put('D', 7);
92
+ expected.put('M', 1);
93
+ expected.put('O', 0);
94
+ expected.put('R', 8);
95
+ expected.put('Y', 2);
96
+
97
+ assertEquals(expected, new Alphametics("SEND + MORE == MONEY").solve());
98
+ }
99
+
100
+ @Ignore("Remove to run test")
101
+ @Test
102
+ public void testTenLetters() throws UnsolvablePuzzleException {
103
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
104
+ expected.put('A', 5);
105
+ expected.put('D', 3);
106
+ expected.put('E', 4);
107
+ expected.put('F', 7);
108
+ expected.put('G', 8);
109
+ expected.put('N', 0);
110
+ expected.put('O', 2);
111
+ expected.put('R', 1);
112
+ expected.put('S', 6);
113
+ expected.put('T', 9);
114
+
115
+ assertEquals(expected, new Alphametics("AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE").solve());
116
+ }
117
+
118
+ @Ignore("Remove to run test")
119
+ @Test
120
+ public void testTenLetters41Addends() throws UnsolvablePuzzleException {
121
+ LinkedHashMap<Character, Integer> expected = new LinkedHashMap<>();
122
+ expected.put('A', 1);
123
+ expected.put('E', 0);
124
+ expected.put('F', 5);
125
+ expected.put('H', 8);
126
+ expected.put('I', 7);
127
+ expected.put('L', 2);
128
+ expected.put('O', 6);
129
+ expected.put('R', 3);
130
+ expected.put('S', 4);
131
+ expected.put('T', 9);
132
+
133
+ assertEquals(expected, new Alphametics("THIS + A + FIRE + THEREFORE + FOR + ALL + HISTORIES + I + TELL + A + " +
134
+ "TALE + THAT + FALSIFIES + ITS + TITLE + TIS + A + LIE + THE + TALE + OF + THE + LAST + FIRE + " +
135
+ "HORSES + LATE + AFTER + THE + FIRST + FATHERS + FORESEE + THE + HORRORS + THE + LAST + FREE + " +
136
+ "TROLL + TERRIFIES + THE + HORSES + OF + FIRE + THE + TROLL + RESTS + AT + THE + HOLE + OF + " +
137
+ "LOSSES + IT + IS + THERE + THAT + SHE + STORES + ROLES + OF + LEATHERS + AFTER + SHE + SATISFIES + " +
138
+ "HER + HATE + OFF + THOSE + FEARS + A + TASTE + RISES + AS + SHE + HEARS + THE + LEAST + FAR + " +
139
+ "HORSE + THOSE + FAST + HORSES + THAT + FIRST + HEAR + THE + TROLL + FLEE + OFF + TO + THE + " +
140
+ "FOREST + THE + HORSES + THAT + ALERTS + RAISE + THE + STARES + OF + THE + OTHERS + AS + THE + " +
141
+ "TROLL + ASSAILS + AT + THE + TOTAL + SHIFT + HER + TEETH + TEAR + HOOF + OFF + TORSO + AS + THE + " +
142
+ "LAST + HORSE + FORFEITS + ITS + LIFE + THE + FIRST + FATHERS + HEAR + OF + THE + HORRORS + THEIR + " +
143
+ "FEARS + THAT + THE + FIRES + FOR + THEIR + FEASTS + ARREST + AS + THE + FIRST + FATHERS + " +
144
+ "RESETTLE + THE + LAST + OF + THE + FIRE + HORSES + THE + LAST + TROLL + HARASSES + THE + FOREST + " +
145
+ "HEART + FREE + AT + LAST + OF + THE + LAST + TROLL + ALL + OFFER + THEIR + FIRE + HEAT + TO + THE + " +
146
+ "ASSISTERS + FAR + OFF + THE + TROLL + FASTS + ITS + LIFE + SHORTER + AS + STARS + RISE + THE + " +
147
+ "HORSES + REST + SAFE + AFTER + ALL + SHARE + HOT + FISH + AS + THEIR + AFFILIATES + TAILOR + A + " +
148
+ "ROOFS + FOR + THEIR + SAFE == FORTRESSES").solve());
149
+ }
150
+ }