trackler 2.2.1.85 → 2.2.1.86

Sign up to get free protection for your applications and to get access to all the features.
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
+ }