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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/alphametics/canonical-data.json +29 -11
- data/problem-specifications/exercises/binary-search-tree/canonical-data.json +177 -0
- data/problem-specifications/package.json +2 -2
- data/problem-specifications/yarn.lock +61 -51
- data/tracks/bash/CONTRIBUTING.md +10 -6
- data/tracks/bash/README.md +1 -0
- data/tracks/bash/exercises/acronym/README.md +1 -1
- data/tracks/bash/exercises/anagram/README.md +1 -1
- data/tracks/bash/exercises/anagram/{anagram_tests.sh → anagram_test.sh} +0 -0
- data/tracks/bash/exercises/armstrong-numbers/armstrong_numbers_test.sh +25 -17
- data/tracks/bash/exercises/armstrong-numbers/example.sh +18 -12
- data/tracks/bash/exercises/atbash-cipher/README.md +1 -1
- data/tracks/bash/exercises/atbash-cipher/{atbash_cipher_tests.sh → atbash_cipher_test.sh} +0 -0
- data/tracks/bash/exercises/difference-of-squares/README.md +1 -1
- data/tracks/bash/exercises/gigasecond/README.md +1 -1
- data/tracks/bash/exercises/hamming/README.md +1 -1
- data/tracks/bash/exercises/hello-world/README.md +1 -1
- data/tracks/bash/exercises/leap/README.md +1 -1
- data/tracks/bash/exercises/luhn/README.md +1 -1
- data/tracks/bash/exercises/nucleotide-count/README.md +1 -1
- data/tracks/bash/exercises/pangram/README.md +1 -1
- data/tracks/bash/exercises/pangram/{pangram_tests.sh → pangram_test.sh} +0 -0
- data/tracks/bash/exercises/phone-number/README.md +1 -1
- data/tracks/bash/exercises/phone-number/{phone_number_tests.sh → phone_number_test.sh} +0 -0
- data/tracks/bash/exercises/raindrops/README.md +1 -1
- data/tracks/bash/exercises/rna-transcription/README.md +1 -1
- data/tracks/bash/exercises/triangle/example.sh +23 -4
- data/tracks/bash/exercises/triangle/triangle_test.sh +17 -0
- data/tracks/bash/exercises/two-fer/README.md +1 -1
- data/tracks/bash/exercises/word-count/README.md +1 -1
- data/tracks/c/config.json +11 -0
- data/tracks/c/exercises/complex-numbers/README.md +67 -0
- data/tracks/c/exercises/complex-numbers/makefile +27 -0
- data/tracks/c/exercises/complex-numbers/src/complex_numbers.c +46 -0
- data/tracks/c/exercises/complex-numbers/src/complex_numbers.h +19 -0
- data/tracks/c/exercises/complex-numbers/src/example.c +80 -0
- data/tracks/c/exercises/complex-numbers/test/test_complex_numbers.c +397 -0
- data/tracks/c/exercises/complex-numbers/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/complex-numbers/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/complex-numbers/test/vendor/unity_internals.h +701 -0
- data/tracks/crystal/.github/stale.yml +18 -0
- data/tracks/csharp/exercises/bob/README.md +3 -2
- data/tracks/ecmascript/config.json +4 -4
- data/tracks/fsharp/exercises/bob/README.md +4 -2
- data/tracks/fsharp/exercises/react/ReactTest.fs +137 -74
- data/tracks/fsharp/generators/Generators.fs +76 -0
- data/tracks/go/exercises/tree-building/tree_test.go +15 -0
- data/tracks/haskell/.travis.yml +1 -1
- data/tracks/haskell/exercises/accumulate/stack.yaml +1 -1
- data/tracks/haskell/exercises/acronym/package.yaml +1 -1
- data/tracks/haskell/exercises/acronym/stack.yaml +1 -1
- data/tracks/haskell/exercises/all-your-base/package.yaml +1 -1
- data/tracks/haskell/exercises/all-your-base/stack.yaml +1 -1
- data/tracks/haskell/exercises/all-your-base/test/Tests.hs +6 -6
- data/tracks/haskell/exercises/allergies/package.yaml +1 -1
- data/tracks/haskell/exercises/allergies/stack.yaml +1 -1
- data/tracks/haskell/exercises/alphametics/stack.yaml +1 -1
- data/tracks/haskell/exercises/anagram/package.yaml +1 -1
- data/tracks/haskell/exercises/anagram/stack.yaml +1 -1
- data/tracks/haskell/exercises/atbash-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/atbash-cipher/stack.yaml +1 -1
- data/tracks/haskell/exercises/bank-account/stack.yaml +1 -1
- data/tracks/haskell/exercises/beer-song/stack.yaml +1 -1
- data/tracks/haskell/exercises/binary-search-tree/package.yaml +1 -1
- data/tracks/haskell/exercises/binary-search-tree/stack.yaml +1 -1
- data/tracks/haskell/exercises/binary-search-tree/test/Tests.hs +3 -0
- data/tracks/haskell/exercises/binary/stack.yaml +1 -1
- data/tracks/haskell/exercises/bob/package.yaml +1 -1
- data/tracks/haskell/exercises/bob/stack.yaml +1 -1
- data/tracks/haskell/exercises/bowling/stack.yaml +1 -1
- data/tracks/haskell/exercises/bracket-push/package.yaml +1 -1
- data/tracks/haskell/exercises/bracket-push/stack.yaml +1 -1
- data/tracks/haskell/exercises/change/package.yaml +1 -1
- data/tracks/haskell/exercises/change/stack.yaml +1 -1
- data/tracks/haskell/exercises/clock/stack.yaml +1 -1
- data/tracks/haskell/exercises/collatz-conjecture/package.yaml +1 -1
- data/tracks/haskell/exercises/collatz-conjecture/stack.yaml +1 -1
- data/tracks/haskell/exercises/complex-numbers/stack.yaml +1 -1
- data/tracks/haskell/exercises/connect/package.yaml +1 -1
- data/tracks/haskell/exercises/connect/stack.yaml +1 -1
- data/tracks/haskell/exercises/crypto-square/package.yaml +1 -1
- data/tracks/haskell/exercises/crypto-square/stack.yaml +1 -1
- data/tracks/haskell/exercises/custom-set/stack.yaml +1 -1
- data/tracks/haskell/exercises/diamond/package.yaml +1 -1
- data/tracks/haskell/exercises/diamond/stack.yaml +1 -1
- data/tracks/haskell/exercises/difference-of-squares/package.yaml +1 -1
- data/tracks/haskell/exercises/difference-of-squares/stack.yaml +1 -1
- data/tracks/haskell/exercises/dominoes/package.yaml +1 -1
- data/tracks/haskell/exercises/dominoes/stack.yaml +1 -1
- data/tracks/haskell/exercises/etl/stack.yaml +1 -1
- data/tracks/haskell/exercises/food-chain/stack.yaml +1 -1
- data/tracks/haskell/exercises/forth/stack.yaml +1 -1
- data/tracks/haskell/exercises/gigasecond/stack.yaml +1 -1
- data/tracks/haskell/exercises/go-counting/stack.yaml +1 -1
- data/tracks/haskell/exercises/grade-school/stack.yaml +1 -1
- data/tracks/haskell/exercises/grains/stack.yaml +1 -1
- data/tracks/haskell/exercises/hamming/stack.yaml +1 -1
- data/tracks/haskell/exercises/hello-world/stack.yaml +1 -1
- data/tracks/haskell/exercises/hexadecimal/stack.yaml +1 -1
- data/tracks/haskell/exercises/house/stack.yaml +1 -1
- data/tracks/haskell/exercises/isbn-verifier/examples/success-standard/src/IsbnVerifier.hs +1 -0
- data/tracks/haskell/exercises/isbn-verifier/package.yaml +1 -1
- data/tracks/haskell/exercises/isbn-verifier/stack.yaml +1 -1
- data/tracks/haskell/exercises/isbn-verifier/test/Tests.hs +4 -0
- data/tracks/haskell/exercises/isogram/stack.yaml +1 -1
- data/tracks/haskell/exercises/kindergarten-garden/stack.yaml +1 -1
- data/tracks/haskell/exercises/largest-series-product/stack.yaml +1 -1
- data/tracks/haskell/exercises/leap/stack.yaml +1 -1
- data/tracks/haskell/exercises/lens-person/stack.yaml +1 -1
- data/tracks/haskell/exercises/linked-list/stack.yaml +1 -1
- data/tracks/haskell/exercises/list-ops/stack.yaml +1 -1
- data/tracks/haskell/exercises/luhn/package.yaml +1 -1
- data/tracks/haskell/exercises/luhn/stack.yaml +1 -1
- data/tracks/haskell/exercises/luhn/test/Tests.hs +1 -1
- data/tracks/haskell/exercises/matrix/stack.yaml +1 -1
- data/tracks/haskell/exercises/meetup/package.yaml +1 -1
- data/tracks/haskell/exercises/meetup/stack.yaml +1 -1
- data/tracks/haskell/exercises/minesweeper/stack.yaml +1 -1
- data/tracks/haskell/exercises/nth-prime/stack.yaml +1 -1
- data/tracks/haskell/exercises/nucleotide-count/stack.yaml +1 -1
- data/tracks/haskell/exercises/ocr-numbers/stack.yaml +1 -1
- data/tracks/haskell/exercises/octal/stack.yaml +1 -1
- data/tracks/haskell/exercises/palindrome-products/stack.yaml +1 -1
- data/tracks/haskell/exercises/pangram/stack.yaml +1 -1
- data/tracks/haskell/exercises/parallel-letter-frequency/stack.yaml +1 -1
- data/tracks/haskell/exercises/pascals-triangle/stack.yaml +1 -1
- data/tracks/haskell/exercises/perfect-numbers/stack.yaml +1 -1
- data/tracks/haskell/exercises/phone-number/stack.yaml +1 -1
- data/tracks/haskell/exercises/pig-latin/stack.yaml +1 -1
- data/tracks/haskell/exercises/pov/stack.yaml +1 -1
- data/tracks/haskell/exercises/prime-factors/stack.yaml +1 -1
- data/tracks/haskell/exercises/pythagorean-triplet/stack.yaml +1 -1
- data/tracks/haskell/exercises/queen-attack/stack.yaml +1 -1
- data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/rail-fence-cipher/stack.yaml +1 -1
- data/tracks/haskell/exercises/raindrops/stack.yaml +1 -1
- data/tracks/haskell/exercises/rna-transcription/package.yaml +1 -1
- data/tracks/haskell/exercises/rna-transcription/stack.yaml +1 -1
- data/tracks/haskell/exercises/rna-transcription/test/Tests.hs +0 -12
- data/tracks/haskell/exercises/robot-name/stack.yaml +1 -1
- data/tracks/haskell/exercises/robot-simulator/stack.yaml +1 -1
- data/tracks/haskell/exercises/roman-numerals/stack.yaml +1 -1
- data/tracks/haskell/exercises/rotational-cipher/stack.yaml +1 -1
- data/tracks/haskell/exercises/run-length-encoding/stack.yaml +1 -1
- data/tracks/haskell/exercises/saddle-points/stack.yaml +1 -1
- data/tracks/haskell/exercises/say/stack.yaml +1 -1
- data/tracks/haskell/exercises/scrabble-score/stack.yaml +1 -1
- data/tracks/haskell/exercises/secret-handshake/stack.yaml +1 -1
- data/tracks/haskell/exercises/series/stack.yaml +1 -1
- data/tracks/haskell/exercises/sgf-parsing/stack.yaml +1 -1
- data/tracks/haskell/exercises/sieve/stack.yaml +1 -1
- data/tracks/haskell/exercises/simple-cipher/stack.yaml +1 -1
- data/tracks/haskell/exercises/simple-linked-list/stack.yaml +1 -1
- data/tracks/haskell/exercises/space-age/stack.yaml +1 -1
- data/tracks/haskell/exercises/spiral-matrix/stack.yaml +1 -1
- data/tracks/haskell/exercises/strain/stack.yaml +1 -1
- data/tracks/haskell/exercises/sublist/stack.yaml +1 -1
- data/tracks/haskell/exercises/sum-of-multiples/stack.yaml +1 -1
- data/tracks/haskell/exercises/triangle/stack.yaml +1 -1
- data/tracks/haskell/exercises/trinary/stack.yaml +1 -1
- data/tracks/haskell/exercises/twelve-days/stack.yaml +1 -1
- data/tracks/haskell/exercises/word-count/stack.yaml +1 -1
- data/tracks/haskell/exercises/wordy/stack.yaml +1 -1
- data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -1
- data/tracks/haskell/exercises/zipper/stack.yaml +1 -1
- data/tracks/java/config.json +12 -0
- data/tracks/java/exercises/alphametics/.meta/src/reference/java/Alphametics.java +125 -0
- data/tracks/java/exercises/alphametics/.meta/src/reference/java/UnsolvablePuzzleException.java +2 -0
- data/tracks/java/exercises/alphametics/.meta/src/version +1 -0
- data/tracks/java/exercises/alphametics/README.md +47 -0
- data/tracks/java/exercises/alphametics/build.gradle +18 -0
- data/tracks/java/exercises/alphametics/src/main/java/.keep +0 -0
- data/tracks/java/exercises/alphametics/src/main/java/UnsolvablePuzzleException.java +2 -0
- data/tracks/java/exercises/alphametics/src/test/java/AlphameticsTest.java +150 -0
- data/tracks/java/exercises/beer-song/.meta/src/reference/java/BeerSong.java +5 -4
- data/tracks/java/exercises/beer-song/.meta/version +1 -0
- data/tracks/java/exercises/beer-song/src/test/java/BeerSongTest.java +24 -16
- data/tracks/java/exercises/binary-search/.meta/version +1 -0
- data/tracks/java/exercises/book-store/.meta/version +1 -0
- data/tracks/java/exercises/book-store/src/test/java/BookStoreTest.java +15 -8
- data/tracks/java/exercises/circular-buffer/.meta/version +1 -0
- data/tracks/java/exercises/list-ops/.meta/version +1 -1
- data/tracks/java/exercises/list-ops/src/test/java/ListOpsTest.java +1 -1
- data/tracks/java/exercises/nth-prime/.meta/version +1 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/java/exercises/tournament/.meta/version +1 -0
- data/tracks/java/exercises/transpose/.meta/version +1 -0
- data/tracks/java/exercises/transpose/src/test/java/TransposeTest.java +29 -74
- data/tracks/java/exercises/wordy/.meta/version +1 -0
- data/tracks/javascript/.eslintignore +0 -1
- data/tracks/javascript/config.json +13 -3
- data/tracks/javascript/exercises/bowling/example.js +24 -10
- data/tracks/javascript/exercises/forth/README.md +56 -0
- data/tracks/javascript/exercises/forth/example.js +66 -0
- data/tracks/javascript/exercises/forth/forth.spec.js +259 -0
- data/tracks/lua/config.json +92 -81
- data/tracks/lua/exercises/accumulate/README.md +42 -0
- data/tracks/lua/exercises/beer-song/README.md +1 -1
- data/tracks/lua/exercises/bob/README.md +2 -0
- data/tracks/lua/exercises/crypto-square/README.md +6 -4
- data/tracks/lua/exercises/house/README.md +1 -1
- data/tracks/lua/exercises/isbn-verifier/README.md +25 -20
- data/tracks/lua/exercises/kindergarten-garden/README.md +3 -3
- data/tracks/lua/exercises/meetup/README.md +16 -12
- data/tracks/lua/exercises/nucleotide-count/README.md +2 -2
- data/tracks/lua/exercises/phone-number/README.md +1 -1
- data/tracks/lua/exercises/pov/README.md +0 -2
- data/tracks/lua/exercises/queen-attack/README.md +22 -22
- data/tracks/lua/exercises/rectangles/README.md +9 -9
- data/tracks/lua/exercises/reverse-string/README.md +23 -0
- data/tracks/lua/exercises/reverse-string/example.lua +7 -0
- data/tracks/lua/exercises/reverse-string/reverse-string_spec.lua +24 -0
- data/tracks/lua/exercises/secret-handshake/README.md +1 -1
- data/tracks/lua/exercises/space-age/README.md +1 -2
- data/tracks/lua/exercises/sum-of-multiples/README.md +3 -3
- data/tracks/perl6/exercises/two-fer/README.md +1 -1
- data/tracks/python/exercises/luhn/luhn_test.py +1 -1
- metadata +39 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
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-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
resolver: lts-
|
|
1
|
+
resolver: lts-10.2
|
data/tracks/java/config.json
CHANGED
|
@@ -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 @@
|
|
|
1
|
+
1.1.0
|
|
@@ -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
|
+
}
|
|
File without changes
|
|
@@ -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
|
+
}
|