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.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bump-content +3 -1
  3. data/bin/verify-metadata +2 -2
  4. data/common/exercises/alphametics/canonical-data.json +19 -9
  5. data/common/exercises/food-chain/canonical-data.json +7 -1
  6. data/common/exercises/grains/canonical-data.json +66 -0
  7. data/common/exercises/raindrops/description.md +4 -5
  8. data/common/exercises/triangle/canonical-data.json +81 -54
  9. data/lib/trackler/version.rb +1 -1
  10. data/tracks/c/config.json +26 -19
  11. data/tracks/c/exercises/allergies/makefile +15 -0
  12. data/tracks/c/exercises/allergies/src/allergies.h +21 -0
  13. data/tracks/c/exercises/allergies/src/example.c +32 -0
  14. data/tracks/c/exercises/allergies/src/example.h +26 -0
  15. data/tracks/c/exercises/allergies/test/test_allergies.c +203 -0
  16. data/tracks/c/exercises/allergies/test/vendor/unity.c +1300 -0
  17. data/tracks/c/exercises/allergies/test/vendor/unity.h +274 -0
  18. data/tracks/c/exercises/allergies/test/vendor/unity_internals.h +701 -0
  19. data/tracks/c/exercises/atbash-cipher/makefile +16 -0
  20. data/tracks/c/exercises/atbash-cipher/src/example.c +71 -0
  21. data/tracks/c/exercises/atbash-cipher/src/example.h +7 -0
  22. data/tracks/c/exercises/atbash-cipher/test/test_atbash_cipher.c +113 -0
  23. data/tracks/c/exercises/atbash-cipher/test/vendor/unity.c +1300 -0
  24. data/tracks/c/exercises/atbash-cipher/test/vendor/unity.h +274 -0
  25. data/tracks/c/exercises/atbash-cipher/test/vendor/unity_internals.h +701 -0
  26. data/tracks/c/exercises/phone-number/makefile +16 -0
  27. data/tracks/c/exercises/phone-number/src/example.c +66 -0
  28. data/tracks/c/exercises/phone-number/src/example.h +8 -0
  29. data/tracks/c/exercises/phone-number/test/test_phone_number.c +108 -0
  30. data/tracks/c/exercises/phone-number/test/vendor/unity.c +1300 -0
  31. data/tracks/c/exercises/phone-number/test/vendor/unity.h +274 -0
  32. data/tracks/c/exercises/phone-number/test/vendor/unity_internals.h +701 -0
  33. data/tracks/csharp/config.json +8 -0
  34. data/tracks/csharp/exercises/bowling/BowlingTest.cs +188 -33
  35. data/tracks/csharp/exercises/bowling/Example.cs +38 -9
  36. data/tracks/csharp/exercises/rectangles/Example.cs +91 -0
  37. data/tracks/csharp/exercises/rectangles/RectanglesTest.cs +133 -0
  38. data/tracks/elisp/docs/INSTALLATION.org +1 -1
  39. data/tracks/elixir/config.json +8 -66
  40. data/tracks/elixir/docs/LEARNING.md +1 -1
  41. data/tracks/elixir/exercises/diamond/diamond_test.exs +12 -12
  42. data/tracks/elixir/exercises/grep/example.exs +92 -0
  43. data/tracks/elixir/exercises/grep/grep.exs +6 -0
  44. data/tracks/elixir/exercises/grep/grep_test.exs +259 -0
  45. data/tracks/elixir/exercises/markdown/markdown.exs +59 -2
  46. data/tracks/elixir/exercises/nucleotide-count/nucleotide_count_test.exs +4 -4
  47. data/tracks/elixir/exercises/phone-number/phone_number_test.exs +5 -0
  48. data/tracks/fsharp/exercises/bowling/BowlingTest.fs +158 -43
  49. data/tracks/fsharp/exercises/bowling/Example.fs +53 -24
  50. data/tracks/go/config.json +5 -0
  51. data/tracks/go/exercises/diamond/diamond_test.go +227 -0
  52. data/tracks/go/exercises/diamond/example.go +47 -0
  53. data/tracks/go/exercises/food-chain/example.go +1 -1
  54. data/tracks/go/exercises/food-chain/food_chain_test.go +30 -6
  55. data/tracks/go/exercises/nucleotide-count/example.go +21 -8
  56. data/tracks/go/exercises/nucleotide-count/nucleotide_count_test.go +45 -37
  57. data/tracks/haskell/exercises/anagram/test/Tests.hs +1 -11
  58. data/tracks/java/bin/journey-test.sh +165 -128
  59. data/tracks/java/docs/ABOUT.md +5 -8
  60. data/tracks/java/exercises/hello-world/build.gradle +0 -6
  61. data/tracks/java/exercises/hello-world/src/test/java/HelloWorldTest.java +0 -1
  62. data/tracks/java/exercises/meetup/build.gradle +0 -1
  63. data/tracks/java/exercises/meetup/src/example/java/Meetup.java +9 -7
  64. data/tracks/java/exercises/meetup/src/test/java/MeetupTest.java +185 -188
  65. data/tracks/lua/config.json +0 -73
  66. data/tracks/lua/exercises/bowling/bowling_spec.lua +92 -48
  67. data/tracks/lua/exercises/bowling/example.lua +4 -1
  68. data/tracks/objective-c/config.json +9 -30
  69. data/tracks/objective-c/exercises/pangram/PangramExample.h +7 -0
  70. data/tracks/objective-c/exercises/pangram/PangramExample.m +21 -0
  71. data/tracks/objective-c/exercises/pangram/PangramTest.m +51 -0
  72. data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
  73. data/tracks/ocaml/README.md +46 -1
  74. data/tracks/ocaml/SETUP.md +21 -2
  75. data/tracks/ocaml/config.json +48 -78
  76. data/tracks/perl5/README.md +15 -8
  77. data/tracks/perl5/testall.pl +5 -5
  78. data/tracks/php/config.json +26 -34
  79. data/tracks/php/docs/ABOUT.md +15 -0
  80. data/tracks/php/exercises/allergies/allergies_test.php +121 -0
  81. data/tracks/php/exercises/allergies/example.php +64 -0
  82. data/tracks/php/exercises/etl/etl_test.php +52 -0
  83. data/tracks/php/exercises/etl/example.php +12 -0
  84. data/tracks/php/exercises/nucleotide-count/example.php +25 -0
  85. data/tracks/php/exercises/nucleotide-count/nucleotide-count_test.php +36 -0
  86. data/tracks/php/exercises/pig-latin/example.php +25 -29
  87. data/tracks/php/exercises/pig-latin/pig-latin_test.php +26 -19
  88. data/tracks/php/exercises/space-age/example.php +65 -0
  89. data/tracks/php/exercises/space-age/space-age_test.php +70 -0
  90. data/tracks/php/exercises/triangle/example.php +43 -0
  91. data/tracks/php/exercises/triangle/triangle_test.php +140 -0
  92. data/tracks/pony/exercises/anagram/example.pony +6 -6
  93. data/tracks/pony/exercises/anagram/test.pony +3 -4
  94. data/tracks/pony/exercises/bob/test.pony +23 -23
  95. data/tracks/pony/exercises/difference-of-squares/test.pony +11 -11
  96. data/tracks/pony/exercises/hamming/example.pony +3 -3
  97. data/tracks/pony/exercises/hamming/test.pony +16 -16
  98. data/tracks/pony/exercises/hello-world/test.pony +5 -4
  99. data/tracks/pony/exercises/leap/test.pony +8 -8
  100. data/tracks/python/config.json +18 -0
  101. data/tracks/python/exercises/diamond/diamond_test.py +33 -0
  102. data/tracks/python/exercises/diamond/example.py +15 -0
  103. data/tracks/python/exercises/linked-list/example.py +47 -0
  104. data/tracks/python/exercises/linked-list/linked_list.py +13 -0
  105. data/tracks/python/exercises/linked-list/linked_list_test.py +49 -0
  106. data/tracks/python/exercises/list-ops/example.py +55 -0
  107. data/tracks/python/exercises/list-ops/list_ops.py +38 -0
  108. data/tracks/python/exercises/list-ops/list_ops_test.py +136 -0
  109. data/tracks/ruby/bin/generate +22 -2
  110. data/tracks/ruby/config.json +12 -83
  111. data/tracks/ruby/exercises/allergies/allergies_test.rb +0 -1
  112. data/tracks/ruby/exercises/atbash-cipher/atbash_cipher_test.rb +0 -1
  113. data/tracks/ruby/exercises/beer-song/beer_song_test.rb +1 -2
  114. data/tracks/ruby/exercises/binary/example.rb +0 -1
  115. data/tracks/ruby/exercises/binary-search-tree/binary_search_tree_test.rb +1 -1
  116. data/tracks/ruby/exercises/bowling/.version +1 -0
  117. data/tracks/ruby/exercises/bowling/bowling_test.rb +109 -133
  118. data/tracks/ruby/exercises/bowling/example.rb +7 -7
  119. data/tracks/ruby/exercises/bowling/example.tt +27 -0
  120. data/tracks/ruby/exercises/circular-buffer/circular_buffer_test.rb +0 -2
  121. data/tracks/ruby/exercises/clock/example.rb +0 -2
  122. data/tracks/ruby/exercises/connect/connect_test.rb +0 -1
  123. data/tracks/ruby/exercises/custom-set/custom_set_test.rb +0 -1
  124. data/tracks/ruby/exercises/diamond/diamond_test.rb +0 -1
  125. data/tracks/ruby/exercises/etl/etl_test.rb +1 -1
  126. data/tracks/ruby/exercises/house/house_test.rb +0 -1
  127. data/tracks/ruby/exercises/isogram/isogram_test.rb +2 -2
  128. data/tracks/ruby/exercises/largest-series-product/example.tt +0 -3
  129. data/tracks/ruby/exercises/largest-series-product/largest_series_product_test.rb +0 -4
  130. data/tracks/ruby/exercises/linked-list/linked_list_test.rb +1 -1
  131. data/tracks/ruby/exercises/meetup/meetup_test.rb +0 -1
  132. data/tracks/ruby/exercises/nth-prime/example.tt +0 -2
  133. data/tracks/ruby/exercises/nth-prime/nth_prime_test.rb +0 -2
  134. data/tracks/ruby/exercises/ocr-numbers/ocr_numbers_test.rb +1 -2
  135. data/tracks/ruby/exercises/protein-translation/protein_translation_test.rb +0 -1
  136. data/tracks/ruby/exercises/proverb/proverb_test.rb +1 -3
  137. data/tracks/ruby/exercises/queen-attack/example.rb +3 -1
  138. data/tracks/ruby/exercises/queen-attack/queen_attack_test.rb +34 -8
  139. data/tracks/ruby/exercises/robot-simulator/robot_simulator_test.rb +1 -1
  140. data/tracks/ruby/exercises/strain/strain_test.rb +2 -2
  141. data/tracks/ruby/exercises/tournament/.version +1 -0
  142. data/tracks/ruby/exercises/tournament/example.rb +54 -0
  143. data/tracks/ruby/exercises/tournament/example.tt +23 -0
  144. data/tracks/ruby/exercises/tournament/tournament_test.rb +92 -0
  145. data/tracks/ruby/exercises/transpose/.version +1 -0
  146. data/tracks/ruby/exercises/transpose/example.rb +14 -0
  147. data/tracks/ruby/exercises/transpose/example.tt +22 -0
  148. data/tracks/ruby/exercises/transpose/transpose_test.rb +303 -0
  149. data/tracks/ruby/lib/bowling_cases.rb +46 -0
  150. data/tracks/ruby/lib/isogram_cases.rb +1 -1
  151. data/tracks/ruby/lib/tournament_cases.rb +45 -0
  152. data/tracks/ruby/lib/transpose_cases.rb +45 -0
  153. data/tracks/rust/config.json +2 -0
  154. data/tracks/rust/exercises/bowling/.gitignore +7 -0
  155. data/tracks/rust/exercises/bowling/Cargo.toml +3 -0
  156. data/tracks/rust/exercises/bowling/example.rs +134 -0
  157. data/tracks/rust/exercises/bowling/tests/bowling.rs +373 -0
  158. data/tracks/rust/exercises/grains/.gitignore +7 -0
  159. data/tracks/rust/exercises/grains/Cargo.toml +3 -0
  160. data/tracks/rust/exercises/grains/example.rs +11 -0
  161. data/tracks/rust/exercises/grains/src/lib.rs +7 -0
  162. data/tracks/rust/exercises/grains/tests/grains.rs +63 -0
  163. data/tracks/rust/problems.md +2 -0
  164. data/tracks/scala/README.md +38 -0
  165. data/tracks/scala/config.json +20 -74
  166. data/tracks/scala/exercises/accumulate/src/test/scala/accumulate_test.scala +4 -0
  167. data/tracks/scala/exercises/allergies/src/test/scala/allergies_test.scala +11 -0
  168. data/tracks/scala/exercises/alphametics/build.sbt +6 -0
  169. data/tracks/scala/exercises/alphametics/example.scala +125 -0
  170. data/tracks/scala/exercises/alphametics/src/main/scala/.keep +0 -0
  171. data/tracks/scala/exercises/alphametics/src/test/scala/AlphameticsTest.scala +62 -0
  172. data/tracks/scala/exercises/atbash-cipher/src/test/scala/atbash_test.scala +8 -0
  173. data/tracks/scala/exercises/bank-account/src/test/scala/BankAccountTest.scala +4 -0
  174. data/tracks/scala/exercises/binary/src/test/scala/binary_test.scala +13 -0
  175. data/tracks/scala/exercises/binary-search-tree/src/test/scala/BstTest.scala +11 -0
  176. data/tracks/scala/exercises/bowling/Example.scala +116 -0
  177. data/tracks/scala/exercises/bowling/build.sbt +3 -0
  178. data/tracks/scala/exercises/bowling/src/main/scala/Bowling.scala +11 -0
  179. data/tracks/scala/exercises/bowling/src/test/scala/BowlingSuite.scala +237 -0
  180. data/tracks/scala/exercises/clock/src/test/scala/ClockTest.scala +50 -0
  181. data/tracks/scala/exercises/connect/README.md +17 -0
  182. data/tracks/scala/exercises/connect/src/test/scala/ConnectTest.scala +7 -0
  183. data/tracks/scala/exercises/crypto-square/src/test/scala/{CrytpoSquareTest.scala → CryptoSquareTest.scala} +9 -0
  184. data/tracks/scala/exercises/custom-set/src/test/scala/CustomSetTest.scala +36 -0
  185. data/tracks/scala/exercises/difference-of-squares/src/test/scala/squares_test.scala +8 -0
  186. data/tracks/scala/exercises/forth/src/test/scala/ForthTest.scala +22 -0
  187. data/tracks/scala/exercises/hexadecimal/src/test/scala/HexadecimalTest.scala +8 -0
  188. data/tracks/scala/exercises/kindergarten-garden/src/test/scala/GardenTest.scala +5 -0
  189. data/tracks/scala/exercises/largest-series-product/src/test/scala/SeriesTest.scala +2 -0
  190. data/tracks/scala/exercises/linked-list/src/test/scala/DequeTest.scala +4 -0
  191. data/tracks/scala/exercises/luhn/src/test/scala/LuhnTest.scala +4 -0
  192. data/tracks/scala/exercises/matrix/src/test/scala/MatrixTest.scala +2 -0
  193. data/tracks/scala/exercises/minesweeper/src/test/scala/MinesweeperTest.scala +6 -0
  194. data/tracks/scala/exercises/nth-prime/src/test/scala/PrimeTest.scala +5 -0
  195. data/tracks/scala/exercises/ocr-numbers/src/test/scala/OcrTest.scala +15 -0
  196. data/tracks/scala/exercises/octal/src/test/scala/OctalTest.scala +7 -0
  197. data/tracks/scala/exercises/parallel-letter-frequency/src/test/scala/FrequencyTest.scala +8 -0
  198. data/tracks/scala/exercises/pascals-triangle/src/test/scala/PascalsTriangleTest.scala +5 -0
  199. data/tracks/scala/exercises/pig-latin/src/test/scala/PigLatinTest.scala +4 -0
  200. data/tracks/scala/exercises/pythagorean-triplet/src/test/scala/PythagoreanTripletTest.scala +3 -0
  201. data/tracks/scala/exercises/queen-attack/src/test/scala/QueensTest.scala +5 -0
  202. data/tracks/scala/exercises/robot-simulator/src/test/scala/RobotTest.scala +16 -8
  203. data/tracks/scala/exercises/say/src/test/scala/SayTest.scala +34 -17
  204. data/tracks/scala/exercises/scrabble-score/src/test/scala/scrabble_score_test.scala +6 -0
  205. data/tracks/scala/exercises/secret-handshake/src/test/scala/SecretHandshakeTest.scala +18 -9
  206. data/tracks/scala/exercises/series/src/test/scala/SeriesTest.scala +4 -2
  207. data/tracks/scala/exercises/sieve/src/test/scala/SieveTest.scala +8 -4
  208. data/tracks/scala/exercises/simple-cipher/src/test/scala/CipherTest.scala +17 -9
  209. data/tracks/scala/exercises/sublist/src/test/scala/sublist_test.scala +17 -0
  210. data/tracks/scala/exercises/trinary/src/test/scala/TrinaryTest.scala +14 -7
  211. data/tracks/scala/exercises/wordy/src/test/scala/WordProblemTest.scala +28 -14
  212. data/tracks/scala/project/Build.scala +3 -3
  213. data/tracks/scala/testgen/src/main/scala/BowlingTestGenerator.scala +57 -0
  214. data/tracks/sml/config.json +41 -6
  215. data/tracks/sml/exercises/flatten-array/example.sml +6 -0
  216. data/tracks/sml/exercises/flatten-array/test_flatten_array.sml +10 -0
  217. data/tracks/sml/exercises/nth-prime/example.sml +46 -0
  218. data/tracks/sml/exercises/nth-prime/test_nth_prime.sml +14 -0
  219. data/tracks/sml/exercises/raindrops/example.sml +9 -0
  220. data/tracks/sml/exercises/raindrops/raindrops.sml +2 -0
  221. data/tracks/sml/exercises/raindrops/test_raindrops.sml +95 -0
  222. data/tracks/swift/config.json +269 -328
  223. data/tracks/swift/exercises/pangram/PangramExample.swift +17 -0
  224. data/tracks/swift/exercises/pangram/PangramTest.swift +43 -0
  225. data/tracks/swift/xcodeProject/xSwift.xcodeproj/project.pbxproj +16 -0
  226. 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,6 @@
1
+ scalaVersion := "2.11.8"
2
+
3
+ libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.5" % "test"
4
+
5
+ libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4"
6
+
@@ -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
+
@@ -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)
@@ -0,0 +1,3 @@
1
+ scalaVersion := "2.11.7"
2
+
3
+ libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.5" % "test"
@@ -0,0 +1,11 @@
1
+ sealed trait Bowling {
2
+ def roll(pins: Int): Bowling
3
+
4
+ def score(): Either[Error, Int]
5
+ }
6
+
7
+ object Bowling {
8
+ def apply(): Bowling = ???
9
+ }
10
+
11
+ case class Error(errorText: String)