trackler 2.0.0.1 → 2.0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|