trackler 2.0.0.1 → 2.0.0.2
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/bin/bump-content +3 -1
- data/bin/verify-metadata +2 -2
- data/common/exercises/alphametics/canonical-data.json +19 -9
- data/common/exercises/food-chain/canonical-data.json +7 -1
- data/common/exercises/grains/canonical-data.json +66 -0
- data/common/exercises/raindrops/description.md +4 -5
- data/common/exercises/triangle/canonical-data.json +81 -54
- data/lib/trackler/version.rb +1 -1
- data/tracks/c/config.json +26 -19
- data/tracks/c/exercises/allergies/makefile +15 -0
- data/tracks/c/exercises/allergies/src/allergies.h +21 -0
- data/tracks/c/exercises/allergies/src/example.c +32 -0
- data/tracks/c/exercises/allergies/src/example.h +26 -0
- data/tracks/c/exercises/allergies/test/test_allergies.c +203 -0
- data/tracks/c/exercises/allergies/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/allergies/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/allergies/test/vendor/unity_internals.h +701 -0
- data/tracks/c/exercises/atbash-cipher/makefile +16 -0
- data/tracks/c/exercises/atbash-cipher/src/example.c +71 -0
- data/tracks/c/exercises/atbash-cipher/src/example.h +7 -0
- data/tracks/c/exercises/atbash-cipher/test/test_atbash_cipher.c +113 -0
- data/tracks/c/exercises/atbash-cipher/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/atbash-cipher/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/atbash-cipher/test/vendor/unity_internals.h +701 -0
- data/tracks/c/exercises/phone-number/makefile +16 -0
- data/tracks/c/exercises/phone-number/src/example.c +66 -0
- data/tracks/c/exercises/phone-number/src/example.h +8 -0
- data/tracks/c/exercises/phone-number/test/test_phone_number.c +108 -0
- data/tracks/c/exercises/phone-number/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/phone-number/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/phone-number/test/vendor/unity_internals.h +701 -0
- data/tracks/csharp/config.json +8 -0
- data/tracks/csharp/exercises/bowling/BowlingTest.cs +188 -33
- data/tracks/csharp/exercises/bowling/Example.cs +38 -9
- data/tracks/csharp/exercises/rectangles/Example.cs +91 -0
- data/tracks/csharp/exercises/rectangles/RectanglesTest.cs +133 -0
- data/tracks/elisp/docs/INSTALLATION.org +1 -1
- data/tracks/elixir/config.json +8 -66
- data/tracks/elixir/docs/LEARNING.md +1 -1
- data/tracks/elixir/exercises/diamond/diamond_test.exs +12 -12
- data/tracks/elixir/exercises/grep/example.exs +92 -0
- data/tracks/elixir/exercises/grep/grep.exs +6 -0
- data/tracks/elixir/exercises/grep/grep_test.exs +259 -0
- data/tracks/elixir/exercises/markdown/markdown.exs +59 -2
- data/tracks/elixir/exercises/nucleotide-count/nucleotide_count_test.exs +4 -4
- data/tracks/elixir/exercises/phone-number/phone_number_test.exs +5 -0
- data/tracks/fsharp/exercises/bowling/BowlingTest.fs +158 -43
- data/tracks/fsharp/exercises/bowling/Example.fs +53 -24
- data/tracks/go/config.json +5 -0
- data/tracks/go/exercises/diamond/diamond_test.go +227 -0
- data/tracks/go/exercises/diamond/example.go +47 -0
- data/tracks/go/exercises/food-chain/example.go +1 -1
- data/tracks/go/exercises/food-chain/food_chain_test.go +30 -6
- data/tracks/go/exercises/nucleotide-count/example.go +21 -8
- data/tracks/go/exercises/nucleotide-count/nucleotide_count_test.go +45 -37
- data/tracks/haskell/exercises/anagram/test/Tests.hs +1 -11
- data/tracks/java/bin/journey-test.sh +165 -128
- data/tracks/java/docs/ABOUT.md +5 -8
- data/tracks/java/exercises/hello-world/build.gradle +0 -6
- data/tracks/java/exercises/hello-world/src/test/java/HelloWorldTest.java +0 -1
- data/tracks/java/exercises/meetup/build.gradle +0 -1
- data/tracks/java/exercises/meetup/src/example/java/Meetup.java +9 -7
- data/tracks/java/exercises/meetup/src/test/java/MeetupTest.java +185 -188
- data/tracks/lua/config.json +0 -73
- data/tracks/lua/exercises/bowling/bowling_spec.lua +92 -48
- data/tracks/lua/exercises/bowling/example.lua +4 -1
- data/tracks/objective-c/config.json +9 -30
- data/tracks/objective-c/exercises/pangram/PangramExample.h +7 -0
- data/tracks/objective-c/exercises/pangram/PangramExample.m +21 -0
- data/tracks/objective-c/exercises/pangram/PangramTest.m +51 -0
- data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
- data/tracks/ocaml/README.md +46 -1
- data/tracks/ocaml/SETUP.md +21 -2
- data/tracks/ocaml/config.json +48 -78
- data/tracks/perl5/README.md +15 -8
- data/tracks/perl5/testall.pl +5 -5
- data/tracks/php/config.json +26 -34
- data/tracks/php/docs/ABOUT.md +15 -0
- data/tracks/php/exercises/allergies/allergies_test.php +121 -0
- data/tracks/php/exercises/allergies/example.php +64 -0
- data/tracks/php/exercises/etl/etl_test.php +52 -0
- data/tracks/php/exercises/etl/example.php +12 -0
- data/tracks/php/exercises/nucleotide-count/example.php +25 -0
- data/tracks/php/exercises/nucleotide-count/nucleotide-count_test.php +36 -0
- data/tracks/php/exercises/pig-latin/example.php +25 -29
- data/tracks/php/exercises/pig-latin/pig-latin_test.php +26 -19
- data/tracks/php/exercises/space-age/example.php +65 -0
- data/tracks/php/exercises/space-age/space-age_test.php +70 -0
- data/tracks/php/exercises/triangle/example.php +43 -0
- data/tracks/php/exercises/triangle/triangle_test.php +140 -0
- data/tracks/pony/exercises/anagram/example.pony +6 -6
- data/tracks/pony/exercises/anagram/test.pony +3 -4
- data/tracks/pony/exercises/bob/test.pony +23 -23
- data/tracks/pony/exercises/difference-of-squares/test.pony +11 -11
- data/tracks/pony/exercises/hamming/example.pony +3 -3
- data/tracks/pony/exercises/hamming/test.pony +16 -16
- data/tracks/pony/exercises/hello-world/test.pony +5 -4
- data/tracks/pony/exercises/leap/test.pony +8 -8
- data/tracks/python/config.json +18 -0
- data/tracks/python/exercises/diamond/diamond_test.py +33 -0
- data/tracks/python/exercises/diamond/example.py +15 -0
- data/tracks/python/exercises/linked-list/example.py +47 -0
- data/tracks/python/exercises/linked-list/linked_list.py +13 -0
- data/tracks/python/exercises/linked-list/linked_list_test.py +49 -0
- data/tracks/python/exercises/list-ops/example.py +55 -0
- data/tracks/python/exercises/list-ops/list_ops.py +38 -0
- data/tracks/python/exercises/list-ops/list_ops_test.py +136 -0
- data/tracks/ruby/bin/generate +22 -2
- data/tracks/ruby/config.json +12 -83
- data/tracks/ruby/exercises/allergies/allergies_test.rb +0 -1
- data/tracks/ruby/exercises/atbash-cipher/atbash_cipher_test.rb +0 -1
- data/tracks/ruby/exercises/beer-song/beer_song_test.rb +1 -2
- data/tracks/ruby/exercises/binary/example.rb +0 -1
- data/tracks/ruby/exercises/binary-search-tree/binary_search_tree_test.rb +1 -1
- data/tracks/ruby/exercises/bowling/.version +1 -0
- data/tracks/ruby/exercises/bowling/bowling_test.rb +109 -133
- data/tracks/ruby/exercises/bowling/example.rb +7 -7
- data/tracks/ruby/exercises/bowling/example.tt +27 -0
- data/tracks/ruby/exercises/circular-buffer/circular_buffer_test.rb +0 -2
- data/tracks/ruby/exercises/clock/example.rb +0 -2
- data/tracks/ruby/exercises/connect/connect_test.rb +0 -1
- data/tracks/ruby/exercises/custom-set/custom_set_test.rb +0 -1
- data/tracks/ruby/exercises/diamond/diamond_test.rb +0 -1
- data/tracks/ruby/exercises/etl/etl_test.rb +1 -1
- data/tracks/ruby/exercises/house/house_test.rb +0 -1
- data/tracks/ruby/exercises/isogram/isogram_test.rb +2 -2
- data/tracks/ruby/exercises/largest-series-product/example.tt +0 -3
- data/tracks/ruby/exercises/largest-series-product/largest_series_product_test.rb +0 -4
- data/tracks/ruby/exercises/linked-list/linked_list_test.rb +1 -1
- data/tracks/ruby/exercises/meetup/meetup_test.rb +0 -1
- data/tracks/ruby/exercises/nth-prime/example.tt +0 -2
- data/tracks/ruby/exercises/nth-prime/nth_prime_test.rb +0 -2
- data/tracks/ruby/exercises/ocr-numbers/ocr_numbers_test.rb +1 -2
- data/tracks/ruby/exercises/protein-translation/protein_translation_test.rb +0 -1
- data/tracks/ruby/exercises/proverb/proverb_test.rb +1 -3
- data/tracks/ruby/exercises/queen-attack/example.rb +3 -1
- data/tracks/ruby/exercises/queen-attack/queen_attack_test.rb +34 -8
- data/tracks/ruby/exercises/robot-simulator/robot_simulator_test.rb +1 -1
- data/tracks/ruby/exercises/strain/strain_test.rb +2 -2
- data/tracks/ruby/exercises/tournament/.version +1 -0
- data/tracks/ruby/exercises/tournament/example.rb +54 -0
- data/tracks/ruby/exercises/tournament/example.tt +23 -0
- data/tracks/ruby/exercises/tournament/tournament_test.rb +92 -0
- data/tracks/ruby/exercises/transpose/.version +1 -0
- data/tracks/ruby/exercises/transpose/example.rb +14 -0
- data/tracks/ruby/exercises/transpose/example.tt +22 -0
- data/tracks/ruby/exercises/transpose/transpose_test.rb +303 -0
- data/tracks/ruby/lib/bowling_cases.rb +46 -0
- data/tracks/ruby/lib/isogram_cases.rb +1 -1
- data/tracks/ruby/lib/tournament_cases.rb +45 -0
- data/tracks/ruby/lib/transpose_cases.rb +45 -0
- data/tracks/rust/config.json +2 -0
- data/tracks/rust/exercises/bowling/.gitignore +7 -0
- data/tracks/rust/exercises/bowling/Cargo.toml +3 -0
- data/tracks/rust/exercises/bowling/example.rs +134 -0
- data/tracks/rust/exercises/bowling/tests/bowling.rs +373 -0
- data/tracks/rust/exercises/grains/.gitignore +7 -0
- data/tracks/rust/exercises/grains/Cargo.toml +3 -0
- data/tracks/rust/exercises/grains/example.rs +11 -0
- data/tracks/rust/exercises/grains/src/lib.rs +7 -0
- data/tracks/rust/exercises/grains/tests/grains.rs +63 -0
- data/tracks/rust/problems.md +2 -0
- data/tracks/scala/README.md +38 -0
- data/tracks/scala/config.json +20 -74
- data/tracks/scala/exercises/accumulate/src/test/scala/accumulate_test.scala +4 -0
- data/tracks/scala/exercises/allergies/src/test/scala/allergies_test.scala +11 -0
- data/tracks/scala/exercises/alphametics/build.sbt +6 -0
- data/tracks/scala/exercises/alphametics/example.scala +125 -0
- data/tracks/scala/exercises/alphametics/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/alphametics/src/test/scala/AlphameticsTest.scala +62 -0
- data/tracks/scala/exercises/atbash-cipher/src/test/scala/atbash_test.scala +8 -0
- data/tracks/scala/exercises/bank-account/src/test/scala/BankAccountTest.scala +4 -0
- data/tracks/scala/exercises/binary/src/test/scala/binary_test.scala +13 -0
- data/tracks/scala/exercises/binary-search-tree/src/test/scala/BstTest.scala +11 -0
- data/tracks/scala/exercises/bowling/Example.scala +116 -0
- data/tracks/scala/exercises/bowling/build.sbt +3 -0
- data/tracks/scala/exercises/bowling/src/main/scala/Bowling.scala +11 -0
- data/tracks/scala/exercises/bowling/src/test/scala/BowlingSuite.scala +237 -0
- data/tracks/scala/exercises/clock/src/test/scala/ClockTest.scala +50 -0
- data/tracks/scala/exercises/connect/README.md +17 -0
- data/tracks/scala/exercises/connect/src/test/scala/ConnectTest.scala +7 -0
- data/tracks/scala/exercises/crypto-square/src/test/scala/{CrytpoSquareTest.scala → CryptoSquareTest.scala} +9 -0
- data/tracks/scala/exercises/custom-set/src/test/scala/CustomSetTest.scala +36 -0
- data/tracks/scala/exercises/difference-of-squares/src/test/scala/squares_test.scala +8 -0
- data/tracks/scala/exercises/forth/src/test/scala/ForthTest.scala +22 -0
- data/tracks/scala/exercises/hexadecimal/src/test/scala/HexadecimalTest.scala +8 -0
- data/tracks/scala/exercises/kindergarten-garden/src/test/scala/GardenTest.scala +5 -0
- data/tracks/scala/exercises/largest-series-product/src/test/scala/SeriesTest.scala +2 -0
- data/tracks/scala/exercises/linked-list/src/test/scala/DequeTest.scala +4 -0
- data/tracks/scala/exercises/luhn/src/test/scala/LuhnTest.scala +4 -0
- data/tracks/scala/exercises/matrix/src/test/scala/MatrixTest.scala +2 -0
- data/tracks/scala/exercises/minesweeper/src/test/scala/MinesweeperTest.scala +6 -0
- data/tracks/scala/exercises/nth-prime/src/test/scala/PrimeTest.scala +5 -0
- data/tracks/scala/exercises/ocr-numbers/src/test/scala/OcrTest.scala +15 -0
- data/tracks/scala/exercises/octal/src/test/scala/OctalTest.scala +7 -0
- data/tracks/scala/exercises/parallel-letter-frequency/src/test/scala/FrequencyTest.scala +8 -0
- data/tracks/scala/exercises/pascals-triangle/src/test/scala/PascalsTriangleTest.scala +5 -0
- data/tracks/scala/exercises/pig-latin/src/test/scala/PigLatinTest.scala +4 -0
- data/tracks/scala/exercises/pythagorean-triplet/src/test/scala/PythagoreanTripletTest.scala +3 -0
- data/tracks/scala/exercises/queen-attack/src/test/scala/QueensTest.scala +5 -0
- data/tracks/scala/exercises/robot-simulator/src/test/scala/RobotTest.scala +16 -8
- data/tracks/scala/exercises/say/src/test/scala/SayTest.scala +34 -17
- data/tracks/scala/exercises/scrabble-score/src/test/scala/scrabble_score_test.scala +6 -0
- data/tracks/scala/exercises/secret-handshake/src/test/scala/SecretHandshakeTest.scala +18 -9
- data/tracks/scala/exercises/series/src/test/scala/SeriesTest.scala +4 -2
- data/tracks/scala/exercises/sieve/src/test/scala/SieveTest.scala +8 -4
- data/tracks/scala/exercises/simple-cipher/src/test/scala/CipherTest.scala +17 -9
- data/tracks/scala/exercises/sublist/src/test/scala/sublist_test.scala +17 -0
- data/tracks/scala/exercises/trinary/src/test/scala/TrinaryTest.scala +14 -7
- data/tracks/scala/exercises/wordy/src/test/scala/WordProblemTest.scala +28 -14
- data/tracks/scala/project/Build.scala +3 -3
- data/tracks/scala/testgen/src/main/scala/BowlingTestGenerator.scala +57 -0
- data/tracks/sml/config.json +41 -6
- data/tracks/sml/exercises/flatten-array/example.sml +6 -0
- data/tracks/sml/exercises/flatten-array/test_flatten_array.sml +10 -0
- data/tracks/sml/exercises/nth-prime/example.sml +46 -0
- data/tracks/sml/exercises/nth-prime/test_nth_prime.sml +14 -0
- data/tracks/sml/exercises/raindrops/example.sml +9 -0
- data/tracks/sml/exercises/raindrops/raindrops.sml +2 -0
- data/tracks/sml/exercises/raindrops/test_raindrops.sml +95 -0
- data/tracks/swift/config.json +269 -328
- data/tracks/swift/exercises/pangram/PangramExample.swift +17 -0
- data/tracks/swift/exercises/pangram/PangramTest.swift +43 -0
- data/tracks/swift/xcodeProject/xSwift.xcodeproj/project.pbxproj +16 -0
- metadata +95 -3
|
@@ -8,49 +8,60 @@ class AllergiesTest extends FlatSpec with Matchers {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
it should "handle is allergic to eggs" in {
|
|
11
|
+
pending
|
|
11
12
|
Allergies().isAllergicTo(Allergen.Eggs, 1) should equal (true)
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
it should "handle is allergic to eggs in addition to other stuff" in {
|
|
16
|
+
pending
|
|
15
17
|
Allergies().isAllergicTo(Allergen.Eggs, 5) should equal (true)
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
it should "handle no allergies" in {
|
|
21
|
+
pending
|
|
19
22
|
Allergies().allergies(0) should equal (List())
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
it should "handle allergic to just eggs" in {
|
|
26
|
+
pending
|
|
23
27
|
Allergies().allergies(1) should equal (List(Allergen.Eggs))
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
it should "handle allergic to just peanuts" in {
|
|
31
|
+
pending
|
|
27
32
|
Allergies().allergies(2) should equal (List(Allergen.Peanuts))
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
it should "handle allergic to just strawberries" in {
|
|
36
|
+
pending
|
|
31
37
|
Allergies().allergies(8) should equal (List(Allergen.Strawberries))
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
it should "handle allergic to eggs and peanuts" in {
|
|
41
|
+
pending
|
|
35
42
|
Allergies().allergies(3) should equal (List(Allergen.Eggs, Allergen.Peanuts))
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
it should "handle allergic to more than eggs but not peanuts" in {
|
|
46
|
+
pending
|
|
39
47
|
Allergies().allergies(5) should equal (List(Allergen.Eggs, Allergen.Shellfish))
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
it should "handle allergic to lots of stuff" in {
|
|
51
|
+
pending
|
|
43
52
|
Allergies().allergies(248) should equal (List(Allergen.Strawberries, Allergen.Tomatoes,
|
|
44
53
|
Allergen.Chocolate, Allergen.Pollen, Allergen.Cats))
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
it should "handle allergic to everything" in {
|
|
57
|
+
pending
|
|
48
58
|
Allergies().allergies(255) should equal (List(Allergen.Eggs, Allergen.Peanuts,
|
|
49
59
|
Allergen.Shellfish, Allergen.Strawberries, Allergen.Tomatoes,
|
|
50
60
|
Allergen.Chocolate, Allergen.Pollen, Allergen.Cats))
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
it should "ignore non allergen score parts" in {
|
|
64
|
+
pending
|
|
54
65
|
Allergies().allergies(509) should equal (List(Allergen.Eggs,
|
|
55
66
|
Allergen.Shellfish, Allergen.Strawberries, Allergen.Tomatoes,
|
|
56
67
|
Allergen.Chocolate, Allergen.Pollen, Allergen.Cats))
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import scala.util.parsing.combinator.RegexParsers
|
|
2
|
+
import Alphametics.Solution
|
|
3
|
+
|
|
4
|
+
object Alphametics {
|
|
5
|
+
type Puzzle = String
|
|
6
|
+
type Solution = Map[Char, Int]
|
|
7
|
+
|
|
8
|
+
def solve(puzzle: Puzzle): Option[Solution] = {
|
|
9
|
+
val expression = parse(puzzle)
|
|
10
|
+
val uniqueLetters = puzzle filter (_.isLetter) distinct
|
|
11
|
+
|
|
12
|
+
expression flatMap solveExpression(uniqueLetters)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private def parse(str: String): Option[Expression[Boolean]] =
|
|
16
|
+
ExpressionParser.parse(str)
|
|
17
|
+
|
|
18
|
+
private def solveExpression(uniqueLetters: String)(boolExpr: Expression[Boolean]): Option[Solution] = {
|
|
19
|
+
def isSolution(solution: Solution): Boolean =
|
|
20
|
+
boolExpr.eval(solution) getOrElse false
|
|
21
|
+
|
|
22
|
+
def toSolution(tenChars: String): Solution =
|
|
23
|
+
tenChars.zipWithIndex.toMap filterKeys (_.isLetter)
|
|
24
|
+
|
|
25
|
+
val tenChars = uniqueLetters ++ Seq.fill(10 - uniqueLetters.size)('.')
|
|
26
|
+
tenChars.permutations map toSolution find isSolution
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
object ExpressionParser extends RegexParsers {
|
|
32
|
+
|
|
33
|
+
private implicit def parseResultToOption[T](parseResult: ParseResult[T]): Option[T] =
|
|
34
|
+
parseResult map (Some(_)) getOrElse None
|
|
35
|
+
|
|
36
|
+
def parse(str: String): Option[Expression[Boolean]] =
|
|
37
|
+
parseAll(booleanExpression, str)
|
|
38
|
+
|
|
39
|
+
private def booleanExpression: Parser[Expression[Boolean]] =
|
|
40
|
+
intExpression ~ "==" ~ intExpression ^^ {
|
|
41
|
+
case left ~ _ ~ right => Equals(left, right)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private def intExpression: Parser[Expression[Int]] =
|
|
45
|
+
intOperation | nonOperator
|
|
46
|
+
|
|
47
|
+
private def intOperation: Parser[Expression[Int]] =
|
|
48
|
+
nonOperator ~ operator ~ intExpression ^^ {
|
|
49
|
+
case left ~ op ~ right => op(left, right)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private def operator: Parser[(Expression[Int], Expression[Int]) => Expression[Int]] =
|
|
53
|
+
plus | mult | power
|
|
54
|
+
|
|
55
|
+
private def nonOperator: Parser[Expression[Int]] =
|
|
56
|
+
word | number
|
|
57
|
+
|
|
58
|
+
private val word: Parser[Word] =
|
|
59
|
+
"[A-Z]+".r ^^ (Word(_))
|
|
60
|
+
|
|
61
|
+
private val number: Parser[Number] =
|
|
62
|
+
"[0-9]+".r ^^ (n =>(Number(n.toInt)))
|
|
63
|
+
|
|
64
|
+
private val plus: Parser[(Expression[Int], Expression[Int]) => Expression[Int]] =
|
|
65
|
+
"+" ^^ const(Plus(_, _))
|
|
66
|
+
|
|
67
|
+
private val mult: Parser[(Expression[Int], Expression[Int]) => Expression[Int]] =
|
|
68
|
+
"*" ^^ const(Mult(_, _))
|
|
69
|
+
|
|
70
|
+
private val power: Parser[(Expression[Int], Expression[Int]) => Expression[Int]] =
|
|
71
|
+
"^" ^^ const(Power(_, _))
|
|
72
|
+
|
|
73
|
+
private def const[A](a: A)(ignore: Any) = a
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
sealed trait Expression[T] {
|
|
78
|
+
def eval(solution: Solution): Option[T]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
case class Word(word: String) extends Expression[Int] {
|
|
82
|
+
override def eval(solution: Solution) =
|
|
83
|
+
if (solution(word(0)) == 0) None
|
|
84
|
+
else Some((word map solution mkString) toInt)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
case class Number(number: Int) extends Expression[Int] {
|
|
88
|
+
override def eval(solution: Solution) = Some(number)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
trait Operation[A,B] extends Expression[B] {
|
|
92
|
+
val op: (A, A) => B
|
|
93
|
+
val left: Expression[A]
|
|
94
|
+
val right: Expression[A]
|
|
95
|
+
override def eval(solution: Solution) =
|
|
96
|
+
for {
|
|
97
|
+
l <- left.eval(solution)
|
|
98
|
+
r <- right.eval(solution)
|
|
99
|
+
} yield op(l, r)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case class Equals[A](override val left: Expression[A],
|
|
103
|
+
override val right: Expression[A]) extends Operation[A, Boolean]
|
|
104
|
+
{
|
|
105
|
+
override val op: (A, A) => Boolean = (_ == _)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case class Plus(override val left: Expression[Int],
|
|
109
|
+
override val right: Expression[Int]) extends Operation[Int, Int]
|
|
110
|
+
{
|
|
111
|
+
override val op: (Int, Int) => Int = (_ + _)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
case class Mult(override val left: Expression[Int],
|
|
115
|
+
override val right: Expression[Int]) extends Operation[Int, Int]
|
|
116
|
+
{
|
|
117
|
+
override val op: (Int, Int) => Int = (_ * _)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case class Power(override val left: Expression[Int],
|
|
121
|
+
override val right: Expression[Int]) extends Operation[Int, Int]
|
|
122
|
+
{
|
|
123
|
+
override val op: (Int, Int) => Int = math.pow(_, _).toInt
|
|
124
|
+
}
|
|
125
|
+
|
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import org.scalatest.{FunSuite, Matchers}
|
|
2
|
+
|
|
3
|
+
class AlphameticsTest extends FunSuite with Matchers {
|
|
4
|
+
test("puzzle with three letters") {
|
|
5
|
+
Alphametics.solve("I + BB == ILL") should
|
|
6
|
+
be (Some(Map('I' -> 1, 'B' -> 9, 'L' -> 0)))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
test("solution must have unique value for each letter") {
|
|
10
|
+
pending
|
|
11
|
+
Alphametics.solve("A == B") should be (None)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
test("leading zero solution is invalid") {
|
|
15
|
+
pending
|
|
16
|
+
Alphametics.solve("ACA + DD == BD") should be (None)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
test("puzzle with four letters") {
|
|
20
|
+
pending
|
|
21
|
+
Alphametics.solve("AS + A == MOM") should
|
|
22
|
+
be (Some(Map('A' -> 9, 'S' -> 2, 'M' -> 1, 'O' -> 0)))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("puzzle with six letters") {
|
|
26
|
+
pending
|
|
27
|
+
Alphametics.solve("NO + NO + TOO == LATE") should
|
|
28
|
+
be (Some(Map('N' -> 7, 'O' -> 4, 'T' -> 9, 'L' -> 1, 'A' -> 0, 'E' -> 2)))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
test("puzzle with seven letters") {
|
|
32
|
+
pending
|
|
33
|
+
Alphametics.solve("HE + SEES + THE == LIGHT") should
|
|
34
|
+
be (Some(Map('E' -> 4, 'G' -> 2, 'H' -> 5, 'I' -> 0, 'L' -> 1, 'S' -> 9, 'T' -> 7)))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test("puzzle with eight letters") {
|
|
38
|
+
pending
|
|
39
|
+
Alphametics.solve("SEND + MORE == MONEY") should
|
|
40
|
+
be (Some(Map('S' -> 9, 'E' -> 5, 'N' -> 6, 'D' -> 7, 'M' -> 1,
|
|
41
|
+
'O' -> 0, 'R' -> 8, 'Y' -> 2)))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test("puzzle with ten letters") {
|
|
45
|
+
pending
|
|
46
|
+
Alphametics.solve("AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE") should
|
|
47
|
+
be (Some(Map('A' -> 5, 'D' -> 3, 'E' -> 4, 'F' -> 7, 'G' -> 8,
|
|
48
|
+
'N' -> 0, 'O' -> 2, 'R' -> 1, 'S' -> 6, 'T' -> 9)))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test("solve puzzle with multiplication") {
|
|
52
|
+
pending
|
|
53
|
+
Alphametics.solve("IF * DR == DORI") should
|
|
54
|
+
be (Some(Map('I' -> 8, 'F' -> 2, 'D' -> 3, 'R' -> 9, 'O' -> 1)))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
test("solve puzzle with exponents") {
|
|
58
|
+
pending
|
|
59
|
+
Alphametics.solve("PI * R ^ 2 == AREA") should
|
|
60
|
+
be (Some(Map('P' -> 9, 'I' -> 6, 'R' -> 7, 'A' -> 4, 'E' -> 0)))
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -6,34 +6,42 @@ class AtbashTest extends FlatSpec with Matchers {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
it should "encode yes" in {
|
|
9
|
+
pending
|
|
9
10
|
Atbash().encode("yes") should equal("bvh")
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
it should "encode OMG" in {
|
|
14
|
+
pending
|
|
13
15
|
Atbash().encode("OMG") should equal("lnt")
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
it should "encode lowercase omg" in {
|
|
19
|
+
pending
|
|
17
20
|
Atbash().encode("omg") should equal("lnt")
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
it should "encode O M G" in {
|
|
24
|
+
pending
|
|
21
25
|
Atbash().encode("O M G ") should equal("lnt")
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
it should "encode and group string " in {
|
|
29
|
+
pending
|
|
25
30
|
Atbash().encode("mindblowingly") should equal("nrmwy oldrm tob")
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
it should "encode string with digits and punctuation" in {
|
|
34
|
+
pending
|
|
29
35
|
Atbash().encode("Testing, 1 2 3, testing. ") should equal("gvhgr mt123 gvhgr mt")
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
it should "encode \"Truth is fiction.\"" in {
|
|
39
|
+
pending
|
|
33
40
|
Atbash().encode("Truth is fiction.") should equal("gifgs rhurx grlm")
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
it should "encode a long string" in {
|
|
44
|
+
pending
|
|
37
45
|
Atbash().encode("The quick brown fox jumps over the lazy dog.") should
|
|
38
46
|
equal("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt")
|
|
39
47
|
}
|
|
@@ -7,6 +7,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
test("incrementing and checking balance") {
|
|
10
|
+
pending
|
|
10
11
|
val acct = BankAccount()
|
|
11
12
|
acct.getBalance should be (Some(0))
|
|
12
13
|
acct.incrementBalance(10) should be (Some(10))
|
|
@@ -16,6 +17,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
test("closed account should hold no balance") {
|
|
20
|
+
pending
|
|
19
21
|
val acct = BankAccount()
|
|
20
22
|
acct.closeAccount()
|
|
21
23
|
acct.incrementBalance(10)
|
|
@@ -24,6 +26,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
test("incrementing balance from multiple threads") {
|
|
29
|
+
pending
|
|
27
30
|
val conductor = new Conductor
|
|
28
31
|
import conductor._
|
|
29
32
|
|
|
@@ -47,6 +50,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
test("incrementing balance from multiple threads - concurrent updates") {
|
|
53
|
+
pending
|
|
50
54
|
val conductor = new Conductor
|
|
51
55
|
import conductor._
|
|
52
56
|
|
|
@@ -6,54 +6,67 @@ class BinaryTest extends FunSuite with Matchers {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
test("invalid string - all chars invalid") {
|
|
9
|
+
pending
|
|
9
10
|
Binary("carrot").toDecimal should be (0)
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
test("invalid string - leading char invalid") {
|
|
14
|
+
pending
|
|
13
15
|
Binary("a1111").toDecimal should be (0)
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
test("invalid string - trailing char invalid") {
|
|
19
|
+
pending
|
|
17
20
|
Binary("1111a").toDecimal should be (0)
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
test("invalid string - middle char invalid") {
|
|
24
|
+
pending
|
|
21
25
|
Binary("0101F0").toDecimal should be (0)
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
test("invalid string - invalid digits") {
|
|
29
|
+
pending
|
|
25
30
|
Binary("22").toDecimal should be (0)
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
test("1") {
|
|
34
|
+
pending
|
|
29
35
|
Binary("1").toDecimal should be (1)
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
test("2") {
|
|
39
|
+
pending
|
|
33
40
|
Binary("10").toDecimal should be (2)
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
test("3") {
|
|
44
|
+
pending
|
|
37
45
|
Binary("11").toDecimal should be (3)
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
test("4") {
|
|
49
|
+
pending
|
|
41
50
|
Binary("100").toDecimal should be (4)
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
test("9") {
|
|
54
|
+
pending
|
|
45
55
|
Binary("1001").toDecimal should be (9)
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
test("26") {
|
|
59
|
+
pending
|
|
49
60
|
Binary("11010").toDecimal should be (26)
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
test("Ultimate answer to everything") {
|
|
64
|
+
pending
|
|
53
65
|
Binary("101010").toDecimal should be (42)
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
test("1128") {
|
|
69
|
+
pending
|
|
57
70
|
Binary("10001101000").toDecimal should be (1128)
|
|
58
71
|
}
|
|
59
72
|
}
|
|
@@ -8,26 +8,32 @@ class BstTest extends FlatSpec with Matchers {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
it should "retain data - char" in {
|
|
11
|
+
pending
|
|
11
12
|
Bst('d').value should equal('d')
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
it should "insert less" in {
|
|
16
|
+
pending
|
|
15
17
|
bst4.insert(2).left.get.value should equal(2)
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
it should "insert less - char" in {
|
|
21
|
+
pending
|
|
19
22
|
Bst('d').insert('a').left.get.value should equal('a')
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
it should "insert same" in {
|
|
26
|
+
pending
|
|
23
27
|
bst4.insert(4).left.get.value should equal(4)
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
it should "insert greater than" in {
|
|
31
|
+
pending
|
|
27
32
|
bst4.insert(5).right.get.value should equal(5)
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
it should "handle complex tree - sort out of order list" in {
|
|
36
|
+
pending
|
|
31
37
|
val bst = Bst.fromList(List(4, 2, 6, 1, 3, 7, 5))
|
|
32
38
|
Bst.toList(bst) should equal((1 to 7).toList)
|
|
33
39
|
|
|
@@ -41,22 +47,27 @@ class BstTest extends FlatSpec with Matchers {
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
it should "iterating one element" in {
|
|
50
|
+
pending
|
|
44
51
|
Bst.toList(bst4) should equal(List(4))
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
it should "iterating over smaller element" in {
|
|
55
|
+
pending
|
|
48
56
|
Bst.toList(Bst.fromList(List(4, 2))) should equal(List(2, 4))
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
it should "iterating over larger element" in {
|
|
60
|
+
pending
|
|
52
61
|
Bst.toList(Bst.fromList(List(4, 5))) should equal(List(4, 5))
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
it should "iterating over complex tree" in {
|
|
65
|
+
pending
|
|
56
66
|
Bst.toList(Bst.fromList(List(4, 2, 1, 3, 6, 7, 5))) should equal((1 to 7).toList)
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
it should "iterating over complex tree - chars" in {
|
|
70
|
+
pending
|
|
60
71
|
Bst.toList(Bst.fromList(List('d', 'b', 'a', 'c', 'f', 'g', 'e'))) should
|
|
61
72
|
equal(('a' to 'g').toList)
|
|
62
73
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import scala.annotation.tailrec
|
|
2
|
+
|
|
3
|
+
sealed trait Bowling {
|
|
4
|
+
def roll(pins: Int): Bowling
|
|
5
|
+
|
|
6
|
+
def score(): Either[Error, Int]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
object Bowling {
|
|
10
|
+
def apply(): Bowling = new BowlingImpl(List.empty)
|
|
11
|
+
|
|
12
|
+
private class BowlingImpl(rolls: List[Int]) extends Bowling {
|
|
13
|
+
override def roll(pins: Int): Bowling = new BowlingImpl(rolls ++ List(pins))
|
|
14
|
+
|
|
15
|
+
override def score(): Either[Error, Int] =
|
|
16
|
+
if (rolls.isEmpty) {
|
|
17
|
+
Left(Error("Unstarted game cannot be scored"))
|
|
18
|
+
} else {
|
|
19
|
+
val fs = frames(rolls, 1)
|
|
20
|
+
if (fs.length != 10) {
|
|
21
|
+
Left(Error("Invalid number of frames - 10 expected"))
|
|
22
|
+
} else {
|
|
23
|
+
score(fs, 0)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@tailrec
|
|
28
|
+
private def score(frames: List[List[Int]], acc: Int): Either[Error, Int] =
|
|
29
|
+
frames match {
|
|
30
|
+
case x::xs => val frameScore = scoreFrame(x, xs, acc)
|
|
31
|
+
frameScore match {
|
|
32
|
+
case Right(sum) => score(xs, sum)
|
|
33
|
+
case error => error
|
|
34
|
+
}
|
|
35
|
+
case _ => Right(acc)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private def scoreFrame(frame: List[Int], remainingFrames: List[List[Int]], acc: Int): Either[Error, Int] = {
|
|
39
|
+
if (frame.exists(s => s < 0)) {
|
|
40
|
+
Left(Error("rolls can not score negative points"))
|
|
41
|
+
} else if (frame.exists(s => s > 10)) {
|
|
42
|
+
Left(Error("a roll can not score more than 10 points"))
|
|
43
|
+
} else if (remainingFrames.nonEmpty && frame.sum > 10) {
|
|
44
|
+
Left(Error("two rolls in a frame can not score more than 10 points"))
|
|
45
|
+
} else if (remainingFrames.isEmpty && !isValidFinalFrame(frame)) {
|
|
46
|
+
Left(Error("invalid final frame"))
|
|
47
|
+
} else {
|
|
48
|
+
val score = if (strike(frame)) {
|
|
49
|
+
acc + frame.sum + strikeBonus(remainingFrames)
|
|
50
|
+
} else if (spare(frame)) {
|
|
51
|
+
acc + frame.sum + spareBonus(remainingFrames)
|
|
52
|
+
} else {
|
|
53
|
+
acc + frame.sum
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Right(score)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private def frames(rolls: List[Int], i: Int): List[List[Int]] = {
|
|
61
|
+
if (rolls.isEmpty) {
|
|
62
|
+
List.empty
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
val throws = numThrows(rolls, i)
|
|
66
|
+
rolls.take(throws)::frames(rolls.drop(throws), i + 1)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private def numThrows(rolls: List[Int], frameNum: Int): Int = {
|
|
71
|
+
if (frameNum == 10) {
|
|
72
|
+
if (strike(rolls) || spare(rolls)) 3
|
|
73
|
+
else 2
|
|
74
|
+
} else if (strike(rolls)) {
|
|
75
|
+
1
|
|
76
|
+
} else {
|
|
77
|
+
2
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private def strike(rolls: List[Int]): Boolean =
|
|
82
|
+
rolls.headOption.getOrElse(0) == 10
|
|
83
|
+
|
|
84
|
+
private def spare(rolls: List[Int]): Boolean =
|
|
85
|
+
rolls.take(2).sum == 10
|
|
86
|
+
|
|
87
|
+
private def strikeBonus(frames: List[List[Int]]): Int =
|
|
88
|
+
frames.take(2).flatten.take(2).sum
|
|
89
|
+
|
|
90
|
+
private def spareBonus(frames: List[List[Int]]): Int =
|
|
91
|
+
frames match {
|
|
92
|
+
case x::xs => x.head
|
|
93
|
+
case _ => 0
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private def isValidFinalFrame(rolls: List[Int]): Boolean = {
|
|
97
|
+
val isStrike = strike(rolls)
|
|
98
|
+
val isSpare = spare(rolls)
|
|
99
|
+
|
|
100
|
+
if (rolls.length == 2) {
|
|
101
|
+
!isStrike && !isSpare
|
|
102
|
+
} else if (rolls.length == 3) {
|
|
103
|
+
(isStrike || isSpare) &&
|
|
104
|
+
(if (isStrike) {
|
|
105
|
+
rolls(1) == 10 || (rolls(1) + rolls(2) <= 10)
|
|
106
|
+
} else {
|
|
107
|
+
isSpare || rolls(1) + rolls(2) <= 10
|
|
108
|
+
})
|
|
109
|
+
} else {
|
|
110
|
+
false
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
case class Error(errorText: String)
|