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.
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)