trackler 2.1.0.27 → 2.1.0.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/common/CONTRIBUTING.md +9 -349
  3. data/common/exercises/forth/canonical-data.json +1 -7
  4. data/lib/trackler/version.rb +1 -1
  5. data/tracks/bash/config.json +5 -0
  6. data/tracks/bash/exercises/anagram/anagram_tests.sh +99 -0
  7. data/tracks/bash/exercises/anagram/example.sh +23 -0
  8. data/tracks/delphi/config.json +8 -1
  9. data/tracks/delphi/exercises/two-fer/twofer.dpr +60 -0
  10. data/tracks/delphi/exercises/two-fer/utwoferExample.pas +17 -0
  11. data/tracks/delphi/exercises/two-fer/utwoferTest.pas +71 -0
  12. data/tracks/dlang/README.md +9 -5
  13. data/tracks/dlang/bin/test-exercise +14 -5
  14. data/tracks/dlang/docs/INSTALLATION.md +24 -0
  15. data/tracks/dlang/docs/TESTS.md +6 -6
  16. data/tracks/dlang/exercises/bob/dub.sdl +2 -0
  17. data/tracks/dlang/exercises/bob/{bob_example.d → example/bob.d} +0 -5
  18. data/tracks/dlang/exercises/bob/{bob.d → source/bob.d} +0 -5
  19. data/tracks/dlang/exercises/circular-buffer/dub.sdl +2 -0
  20. data/tracks/dlang/exercises/circular-buffer/{circular_buffer_example.d → example/circular_buffer.d} +0 -5
  21. data/tracks/dlang/exercises/circular-buffer/{circular_buffer.d → source/circular_buffer.d} +0 -5
  22. data/tracks/dlang/exercises/crypto-square/dub.sdl +2 -0
  23. data/tracks/dlang/exercises/crypto-square/{crypto_square_example.d → example/crypto_square.d} +0 -5
  24. data/tracks/dlang/exercises/crypto-square/{crypto_square.d → source/crypto_square.d} +0 -5
  25. data/tracks/dlang/exercises/difference-of-squares/dub.sdl +2 -0
  26. data/tracks/dlang/exercises/difference-of-squares/{difference_of_squares_example.d → example/difference_of_squares.d} +0 -2
  27. data/tracks/dlang/exercises/difference-of-squares/{difference_of_squares.d → source/difference_of_squares.d} +0 -2
  28. data/tracks/dlang/exercises/etl/dub.sdl +2 -0
  29. data/tracks/dlang/exercises/etl/{etl_example.d → example/etl.d} +0 -5
  30. data/tracks/dlang/exercises/etl/{etl.d → source/etl.d} +0 -5
  31. data/tracks/dlang/exercises/gigasecond/dub.sdl +2 -0
  32. data/tracks/dlang/exercises/gigasecond/{gigasecond_example.d → example/gigasecond.d} +0 -2
  33. data/tracks/dlang/exercises/gigasecond/{gigasecond.d → source/gigasecond.d} +0 -2
  34. data/tracks/dlang/exercises/hamming/dub.sdl +2 -0
  35. data/tracks/dlang/exercises/hamming/{hamming_example.d → example/hamming.d} +0 -5
  36. data/tracks/dlang/exercises/hamming/{hamming.d → source/hamming.d} +0 -5
  37. data/tracks/dlang/exercises/hello-world/dub.sdl +2 -0
  38. data/tracks/dlang/exercises/hello-world/{hello_world_example.d → example/hello_world.d} +0 -2
  39. data/tracks/dlang/exercises/hello-world/{hello_world.d → source/hello_world.d} +0 -0
  40. data/tracks/dlang/exercises/leap/dub.sdl +2 -0
  41. data/tracks/dlang/exercises/leap/{leap_example.d → example/leap.d} +0 -2
  42. data/tracks/dlang/exercises/leap/{leap.d → source/leap.d} +0 -2
  43. data/tracks/dlang/exercises/nucleotide-count/dub.sdl +2 -0
  44. data/tracks/dlang/exercises/nucleotide-count/{nucleotide_count_example.d → example/nucleotide_count.d} +0 -4
  45. data/tracks/dlang/exercises/nucleotide-count/{nucleotide_count.d → source/nucleotide_count.d} +0 -4
  46. data/tracks/dlang/exercises/pangram/dub.sdl +2 -0
  47. data/tracks/dlang/exercises/pangram/{pangram_example.d → example/pangram.d} +0 -2
  48. data/tracks/dlang/exercises/pangram/{pangram.d → source/pangram.d} +0 -2
  49. data/tracks/dlang/exercises/raindrops/dub.sdl +2 -0
  50. data/tracks/dlang/exercises/raindrops/{raindrops_example.d → example/raindrops.d} +0 -2
  51. data/tracks/dlang/exercises/raindrops/{raindrops.d → source/raindrops.d} +0 -2
  52. data/tracks/dlang/exercises/react/dub.sdl +2 -0
  53. data/tracks/dlang/exercises/react/{react_example.d → example/react.d} +0 -2
  54. data/tracks/dlang/exercises/react/{react.d → source/react.d} +0 -2
  55. data/tracks/dlang/exercises/rna-transcription/dub.sdl +2 -0
  56. data/tracks/dlang/exercises/rna-transcription/{rna_transcription_example.d → example/rna_transcription.d} +0 -2
  57. data/tracks/dlang/exercises/rna-transcription/{rna_transcription.d → source/rna_transcription.d} +0 -2
  58. data/tracks/dlang/exercises/robot-name/dub.sdl +2 -0
  59. data/tracks/dlang/exercises/robot-name/{robot_name_example.d → example/robot_name.d} +0 -5
  60. data/tracks/dlang/exercises/robot-name/{robot_name.d → source/robot_name.d} +0 -4
  61. data/tracks/dlang/exercises/roman-numerals/dub.sdl +2 -0
  62. data/tracks/dlang/exercises/roman-numerals/{roman_numerals_example.d → example/roman_numerals.d} +0 -4
  63. data/tracks/dlang/exercises/roman-numerals/{roman_numerals.d → source/roman_numerals.d} +0 -4
  64. data/tracks/dlang/exercises/series/dub.sdl +2 -0
  65. data/tracks/dlang/exercises/series/{series_example.d → example/series.d} +0 -5
  66. data/tracks/dlang/exercises/series/{series.d → source/series.d} +0 -5
  67. data/tracks/dlang/exercises/triangle/dub.sdl +2 -0
  68. data/tracks/dlang/exercises/triangle/{triangle_example.d → example/triangle.d} +0 -5
  69. data/tracks/dlang/exercises/triangle/{triangle.d → source/triangle.d} +0 -5
  70. data/tracks/elisp/.github/stale.yml +0 -0
  71. data/tracks/elisp/exercises/grains/grains-test.el +12 -12
  72. data/tracks/elisp/exercises/robot-name/robot-name-test.el +8 -19
  73. data/tracks/elisp/exercises/word-count/word-count-test.el +27 -27
  74. data/tracks/fortran/Makefile +3 -2
  75. data/tracks/fortran/config.json +21 -2
  76. data/tracks/fortran/exercises/difference-of-squares/difference_of_squares.fun +42 -0
  77. data/tracks/fortran/exercises/difference-of-squares/example.f90 +35 -0
  78. data/tracks/fortran/exercises/{hello_world → hello-world}/example.f90 +0 -0
  79. data/tracks/fortran/exercises/{hello_world → hello-world}/hello_world.fun +0 -0
  80. data/tracks/fortran/exercises/raindrops/example.f90 +26 -0
  81. data/tracks/fortran/exercises/raindrops/raindrops.fun +78 -0
  82. data/tracks/fortran/exercises/rna-transcription/example.f90 +27 -0
  83. data/tracks/fortran/exercises/rna-transcription/rna_transcription.fun +38 -0
  84. data/tracks/go/exercises/acronym/.meta/gen.go +51 -0
  85. data/tracks/go/exercises/acronym/acronym_test.go +1 -15
  86. data/tracks/go/exercises/acronym/cases_test.go +37 -0
  87. data/tracks/go/exercises/acronym/example.go +1 -1
  88. data/tracks/go/exercises/secret-handshake/.meta/gen.go +49 -0
  89. data/tracks/go/exercises/secret-handshake/cases_test.go +24 -0
  90. data/tracks/go/exercises/secret-handshake/example.go +1 -1
  91. data/tracks/go/exercises/secret-handshake/secret_handshake_test.go +1 -17
  92. data/tracks/java/config.json +23 -23
  93. data/tracks/java/exercises/book-store/src/example/java/{Bookstore.java → BookStore.java} +5 -12
  94. data/tracks/java/exercises/book-store/src/test/java/BookStoreTest.java +113 -0
  95. data/tracks/java/exercises/saddle-points/src/example/java/Matrix.java +5 -4
  96. data/tracks/java/exercises/saddle-points/src/example/java/MatrixCoordinate.java +5 -5
  97. data/tracks/java/exercises/saddle-points/src/main/java/MatrixCoordinate.java +5 -5
  98. data/tracks/java/exercises/saddle-points/src/test/java/MatrixTest.java +10 -10
  99. data/tracks/purescript/config.json +7 -0
  100. data/tracks/purescript/exercises/hamming/bower.json +16 -0
  101. data/tracks/purescript/exercises/hamming/examples/src/Hamming.purs +14 -0
  102. data/tracks/purescript/exercises/hamming/test/Main.purs +46 -0
  103. data/tracks/scala/config.json +7 -0
  104. data/tracks/scala/exercises/bob/example.scala +3 -3
  105. data/tracks/scala/exercises/bob/src/main/scala/Bob.scala +2 -2
  106. data/tracks/scala/exercises/bob/src/test/scala/BobTest.scala +83 -53
  107. data/tracks/scala/exercises/book-store/build.sbt +3 -0
  108. data/tracks/scala/exercises/book-store/example.scala +49 -0
  109. data/tracks/scala/exercises/book-store/src/main/scala/.keep +0 -0
  110. data/tracks/scala/exercises/book-store/src/test/scala/BookStoreTest.scala +70 -0
  111. data/tracks/scala/exercises/difference-of-squares/example.scala +3 -3
  112. data/tracks/scala/exercises/difference-of-squares/src/main/scala/DifferenceOfSquares.scala +8 -0
  113. data/tracks/scala/exercises/difference-of-squares/src/test/scala/DifferenceOfSquaresTest.scala +49 -0
  114. data/tracks/scala/exercises/leap/example.scala +4 -3
  115. data/tracks/scala/exercises/leap/src/main/scala/Leap.scala +2 -2
  116. data/tracks/scala/exercises/leap/src/test/scala/LeapTest.scala +12 -20
  117. data/tracks/scala/exercises/raindrops/src/test/scala/RaindropsTest.scala +46 -35
  118. data/tracks/scala/testgen/src/main/scala/BobTestGenerator.scala +15 -0
  119. data/tracks/scala/testgen/src/main/scala/BookStoreTestGenerator.scala +15 -0
  120. data/tracks/scala/testgen/src/main/scala/DifferenceOfSquaresTestGenerator.scala +17 -0
  121. data/tracks/scala/testgen/src/main/scala/LeapTestGenerator.scala +15 -0
  122. data/tracks/scala/testgen/src/main/scala/RaindropsTestGenerator.scala +15 -0
  123. data/tracks/vimscript/config.json +5 -0
  124. data/tracks/vimscript/exercises/triangle/example.vim +28 -0
  125. data/tracks/vimscript/exercises/triangle/triangle.vader +92 -0
  126. data/tracks/vimscript/exercises/triangle/triangle.vim +24 -0
  127. metadata +93 -44
  128. data/tracks/java/exercises/book-store/src/test/java/BookstoreTest.java +0 -119
  129. data/tracks/scala/exercises/difference-of-squares/src/main/scala/Squares.scala +0 -8
  130. data/tracks/scala/exercises/difference-of-squares/src/test/scala/SquaresTest.scala +0 -56
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "hamming",
3
+ "ignore": [
4
+ "**/.*",
5
+ "node_modules",
6
+ "bower_components",
7
+ "output"
8
+ ],
9
+ "dependencies": {
10
+ "purescript-prelude": "^3.0.0"
11
+ },
12
+ "devDependencies": {
13
+ "purescript-psci-support": "^3.0.0",
14
+ "purescript-test-unit": "^11.0.0"
15
+ }
16
+ }
@@ -0,0 +1,14 @@
1
+ module Hamming
2
+ ( distance
3
+ ) where
4
+
5
+ import Prelude
6
+ import Data.Maybe (Maybe(Just, Nothing))
7
+ import Data.Tuple (Tuple(..))
8
+ import Data.String (uncons)
9
+
10
+ distance :: String -> String -> Maybe Int
11
+ distance dna1 dna2 = case Tuple (uncons dna1) (uncons dna2) of
12
+ Tuple (Just {head: h1, tail: t1}) (Just {head: h2, tail: t2}) -> (if h1 /= h2 then ((+) 1) else id) <$> distance t1 t2
13
+ Tuple Nothing Nothing -> Just 0
14
+ Tuple _ _ -> Nothing
@@ -0,0 +1,46 @@
1
+ -- Test/exercise version: "1.0.0"
2
+
3
+ module Test.Main where
4
+
5
+ import Prelude
6
+ import Control.Monad.Eff (Eff)
7
+ import Test.Unit (suite, test)
8
+ import Test.Unit.Main (runTest)
9
+ import Test.Unit.Assert as Assert
10
+ import Data.String as String
11
+ import Data.Maybe (Maybe(Just, Nothing))
12
+ import Hamming (distance)
13
+
14
+ main :: Eff _ Unit
15
+ main = runTest do
16
+ suite "hamming" do
17
+ test "identical strands" $
18
+ Assert.equal (Just 0) (distance "A" "A")
19
+ test "long identical strands" $
20
+ Assert.equal (Just 0) (distance "GGACTGA" "GGACTGA")
21
+ test "complete distance in single nucleotide strands" $
22
+ Assert.equal (Just 1) (distance "A" "G")
23
+ test "complete distance in small strands" $
24
+ Assert.equal (Just 2) (distance "AG" "CT")
25
+ test "small distance in small strands" $
26
+ Assert.equal (Just 1) (distance "AT" "CT")
27
+ test "small distance" $
28
+ Assert.equal (Just 1) (distance "GGACG" "GGTCG")
29
+ test "small distance in long strands" $
30
+ Assert.equal (Just 2) (distance "ACCAGGG" "ACTATGG")
31
+ test "non-unique character in first strand" $
32
+ Assert.equal (Just 1) (distance "AGA" "AGG")
33
+ test "non-unique character in second strand" $
34
+ Assert.equal (Just 1) (distance "AGG" "AGA")
35
+ test "same nucleotides in different positions" $
36
+ Assert.equal (Just 2) (distance "TAG" "GAT")
37
+ test "large distance" $
38
+ Assert.equal (Just 4) (distance "GATACA" "GCATAA")
39
+ test "large distance in off-by-one strand" $
40
+ Assert.equal (Just 9) (distance "GGACGGATTCTG" "AGGACGGATTCT")
41
+ test "empty strands" $
42
+ Assert.equal (Just 0) (distance "" "")
43
+ test "disallow first strand longer" $
44
+ Assert.equal Nothing (distance "AATG" "AAA")
45
+ test "disallow second strand longer" $
46
+ Assert.equal Nothing (distance "ATA" "AGTG")
@@ -532,6 +532,13 @@
532
532
  "Dictionaries"
533
533
  ]
534
534
  },
535
+ {
536
+ "slug":"book-store",
537
+ "difficulty":5,
538
+ "topics":[
539
+ "Recursion"
540
+ ]
541
+ },
535
542
  {
536
543
  "slug":"nth-prime",
537
544
  "difficulty":6,
@@ -1,5 +1,5 @@
1
- class Bob {
2
- def hey(statement: String): String = statement match {
1
+ object Bob {
2
+ def response(statement: String): String = statement match {
3
3
  case Shouting() => "Whoa, chill out!"
4
4
  case Question() => "Sure."
5
5
  case Silence() => "Fine. Be that way!"
@@ -16,7 +16,7 @@ class Bob {
16
16
  }
17
17
 
18
18
  case object Question {
19
- def unapply(statement: String) = statement.endsWith("?")
19
+ def unapply(statement: String) = statement.trim.endsWith("?")
20
20
  }
21
21
 
22
22
  case object Silence {
@@ -1,3 +1,3 @@
1
- class Bob {
2
- def hey(statement: String): String = ???
1
+ object Bob {
2
+ def response(statement: String): String = ???
3
3
  }
@@ -1,102 +1,132 @@
1
- import org.scalatest._
1
+ import org.scalatest.{Matchers, FunSuite}
2
2
 
3
- class BobTest extends FlatSpec with Matchers {
4
- def teenager = new Bob
3
+ /** @version 1.0.0 */
4
+ class BobTest extends FunSuite with Matchers {
5
5
 
6
- it should "respond to a statement" in {
7
- val response = teenager.hey("Tom-ay-to, tom-aaaah-to.")
8
- response should be ("Whatever.")
6
+ test("stating something") {
7
+ Bob.response("Tom-ay-to, tom-aaaah-to.") should be ("Whatever.")
9
8
  }
10
9
 
11
- it should "respond to shouting" in {
10
+ test("shouting") {
12
11
  pending
13
- val response = teenager.hey("WATCH OUT!")
14
- response should be ("Whoa, chill out!")
12
+ Bob.response("WATCH OUT!") should be ("Whoa, chill out!")
15
13
  }
16
14
 
17
- it should "respond to questions" in {
15
+ test("shouting gibberish") {
18
16
  pending
19
- val response = teenager.hey("Does this cryogenic chamber make me look fat?")
20
- response should be ("Sure.")
17
+ Bob.response("FCECDFCAAB") should be ("Whoa, chill out!")
21
18
  }
22
19
 
23
- it should "allow questions to end with numbers" in {
20
+ test("asking a question") {
24
21
  pending
25
- val response = teenager.hey("You are what, like 15?")
26
- response should be ("Sure.")
22
+ Bob.response("Does this cryogenic chamber make me look fat?") should be ("Sure.")
27
23
  }
28
24
 
29
- it should "respond to talking forcefully" in {
25
+ test("asking a numeric question") {
30
26
  pending
31
- val response = teenager.hey("Let's go work out at the gym!")
32
- response should be ("Whatever.")
27
+ Bob.response("You are, what, like 15?") should be ("Sure.")
33
28
  }
34
29
 
35
- it should "allow acroynms in regular speech" in {
30
+ test("asking gibberish") {
36
31
  pending
37
- val response = teenager.hey("It's OK if you don't want to go to the DMV.")
38
- response should be ("Whatever.")
32
+ Bob.response("fffbbcbeab?") should be ("Sure.")
39
33
  }
40
34
 
41
- it should "see forceful questions as shouting" in {
35
+ test("talking forcefully") {
42
36
  pending
43
- val response = teenager.hey("WHAT THE HELL WERE YOU THINKING?")
44
- response should be ("Whoa, chill out!")
37
+ Bob.response("Let's go make out behind the gym!") should be ("Whatever.")
45
38
  }
46
39
 
47
- it should "allow numbers when shouting" in {
40
+ test("using acronyms in regular speech") {
48
41
  pending
49
- val response = teenager.hey("1, 2, 3, GO!")
50
- response should be ("Whoa, chill out!")
42
+ Bob.response("It's OK if you don't want to go to the DMV.") should be ("Whatever.")
51
43
  }
52
44
 
53
- it should "see only numbers as speech" in {
45
+ test("forceful question") {
54
46
  pending
55
- val response = teenager.hey("1, 2, 3")
56
- response should be ("Whatever.")
47
+ Bob.response("WHAT THE HELL WERE YOU THINKING?") should be ("Whoa, chill out!")
57
48
  }
58
49
 
59
- it should "respond to questions with only numbers" in {
50
+ test("shouting numbers") {
60
51
  pending
61
- val response = teenager.hey("4?")
62
- response should be ("Sure.")
52
+ Bob.response("1, 2, 3 GO!") should be ("Whoa, chill out!")
63
53
  }
64
54
 
65
- it should "respond to shouting with no exclamation mark" in {
55
+ test("only numbers") {
66
56
  pending
67
- val response = teenager.hey("I HATE YOU")
68
- response should be ("Whoa, chill out!")
57
+ Bob.response("1, 2, 3") should be ("Whatever.")
69
58
  }
70
59
 
71
- it should "respond to statements with ? in the middle" in {
60
+ test("question with only numbers") {
72
61
  pending
73
- val response = teenager.hey("Ending with ? means a question.")
74
- response should be ("Whatever.")
62
+ Bob.response("4?") should be ("Sure.")
75
63
  }
76
64
 
77
- it should "respond to prattling on" in {
65
+ test("shouting with special characters") {
78
66
  pending
79
- val response = teenager.hey("Wait! Hang on. Are you going to be OK?")
80
- response should be ("Sure.")
67
+ Bob.response("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!") should be ("Whoa, chill out!")
81
68
  }
82
69
 
83
- it should "respond to silence" in {
70
+ test("shouting with no exclamation mark") {
84
71
  pending
85
- val response = teenager.hey("")
86
- response should be ("Fine. Be that way!")
72
+ Bob.response("I HATE YOU") should be ("Whoa, chill out!")
87
73
  }
88
74
 
89
- it should "respond to prolonged silence" in {
75
+ test("statement containing question mark") {
90
76
  pending
91
- val response = teenager.hey(" ")
92
- response should be ("Fine. Be that way!")
77
+ Bob.response("Ending with ? means a question.") should be ("Whatever.")
93
78
  }
94
79
 
95
- it should "respond to multiple line questions" in {
80
+ test("non-letters with question") {
96
81
  pending
97
- val response = teenager.hey("""
82
+ Bob.response(":) ?") should be ("Sure.")
83
+ }
84
+
85
+ test("prattling on") {
86
+ pending
87
+ Bob.response("Wait! Hang on. Are you going to be OK?") should be ("Sure.")
88
+ }
89
+
90
+ test("silence") {
91
+ pending
92
+ Bob.response("") should be ("Fine. Be that way!")
93
+ }
94
+
95
+ test("prolonged silence") {
96
+ pending
97
+ Bob.response(" ") should be ("Fine. Be that way!")
98
+ }
99
+
100
+ test("alternate silence") {
101
+ pending
102
+ Bob.response(" ") should be ("Fine. Be that way!")
103
+ }
104
+
105
+ test("multiple line question") {
106
+ pending
107
+ Bob.response("""
98
108
  Does this cryogenic chamber make me look fat?
99
- no""")
100
- response should be ("Whatever.")
109
+ no""") should be ("Whatever.")
110
+ }
111
+
112
+ test("starting with whitespace") {
113
+ pending
114
+ Bob.response(" hmmmmmmm...") should be ("Whatever.")
115
+ }
116
+
117
+ test("ending with whitespace") {
118
+ pending
119
+ Bob.response("Okay if like my spacebar quite a bit? ") should be ("Sure.")
120
+ }
121
+
122
+ test("other whitespace") {
123
+ pending
124
+ Bob.response("""
125
+ """) should be ("Fine. Be that way!")
126
+ }
127
+
128
+ test("non-question ending with whitespace") {
129
+ pending
130
+ Bob.response("This is a statement ending with whitespace ") should be ("Whatever.")
101
131
  }
102
- }
132
+ }
@@ -0,0 +1,3 @@
1
+ scalaVersion := "2.12.1"
2
+
3
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
@@ -0,0 +1,49 @@
1
+ object BookStore {
2
+ private val bookPrice = 8
3
+ private val discounts =
4
+ Map((1, 0.0),
5
+ (2, 5.0),
6
+ (3, 10.0),
7
+ (4, 20.0),
8
+ (5, 25.0))
9
+
10
+ def total(books: List[Int]): Double = total(books, 0)
11
+
12
+ private def total(books: List[Int], acc: Double): Double = {
13
+ if (books.isEmpty) {
14
+ acc
15
+ } else {
16
+ val bookNums = books.distinct
17
+
18
+ (1 to bookNums.size).foldLeft(Double.MaxValue)((minPrice, groupSize) => {
19
+ val itemsToRemove = bookNums.take(groupSize)
20
+ val remainingBooks = getRemainingBooks(books, itemsToRemove)
21
+ val price = total(remainingBooks, acc + groupCost(groupSize))
22
+ scala.math.min(price, minPrice)
23
+ })
24
+ }
25
+ }
26
+
27
+ private def groupCost(groupSize: Int): Double = {
28
+ discounts get groupSize match {
29
+ case Some(discount) => bookPrice * groupSize * (100.0 - discount) / 100.0
30
+ case _ => bookPrice * groupSize
31
+ }
32
+ }
33
+
34
+ private def getRemainingBooks(books: List[Int], itemsToRemove: List[Int]): List[Int] = {
35
+ var remainingBooks = books
36
+
37
+ for (item <- itemsToRemove) {
38
+ remainingBooks = removeFirst(remainingBooks)(_ == item)
39
+ }
40
+
41
+ remainingBooks
42
+ }
43
+
44
+ // drops the first item in the passed in list that matches the predicate.
45
+ private def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
46
+ val (before, atAndAfter) = list span (x => !pred(x))
47
+ before ::: atAndAfter.drop(1)
48
+ }
49
+ }
@@ -0,0 +1,70 @@
1
+
2
+ import org.scalatest.{Matchers, FunSuite}
3
+
4
+ /** @version 1.0.1 */
5
+ class BookStoreTest extends FunSuite with Matchers {
6
+
7
+ test("Only a single book") {
8
+ BookStore.total(List(1)) should be (8)
9
+ }
10
+
11
+ test("Two of the same book") {
12
+ pending
13
+ BookStore.total(List(2, 2)) should be (16)
14
+ }
15
+
16
+ test("Empty basket") {
17
+ pending
18
+ BookStore.total(List()) should be (0)
19
+ }
20
+
21
+ test("Two different books") {
22
+ pending
23
+ BookStore.total(List(1, 2)) should be (15.2)
24
+ }
25
+
26
+ test("Three different books") {
27
+ pending
28
+ BookStore.total(List(1, 2, 3)) should be (21.6)
29
+ }
30
+
31
+ test("Four different books") {
32
+ pending
33
+ BookStore.total(List(1, 2, 3, 4)) should be (25.6)
34
+ }
35
+
36
+ test("Five different books") {
37
+ pending
38
+ BookStore.total(List(1, 2, 3, 4, 5)) should be (30)
39
+ }
40
+
41
+ test("Two groups of four is cheaper than group of five plus group of three") {
42
+ pending
43
+ BookStore.total(List(1, 1, 2, 2, 3, 3, 4, 5)) should be (51.2)
44
+ }
45
+
46
+ test("Group of four plus group of two is cheaper than two groups of three") {
47
+ pending
48
+ BookStore.total(List(1, 1, 2, 2, 3, 4)) should be (40.8)
49
+ }
50
+
51
+ test("Two each of first 4 books and 1 copy each of rest") {
52
+ pending
53
+ BookStore.total(List(1, 1, 2, 2, 3, 3, 4, 4, 5)) should be (55.6)
54
+ }
55
+
56
+ test("Two copies of each book") {
57
+ pending
58
+ BookStore.total(List(1, 1, 2, 2, 3, 3, 4, 4, 5, 5)) should be (60)
59
+ }
60
+
61
+ test("Three copies of first book and 2 each of remaining") {
62
+ pending
63
+ BookStore.total(List(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1)) should be (68)
64
+ }
65
+
66
+ test("Three each of first 2 books and 2 each of remaining books") {
67
+ pending
68
+ BookStore.total(List(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1, 2)) should be (75.2)
69
+ }
70
+ }
@@ -1,10 +1,10 @@
1
1
  import scala.math.pow
2
2
 
3
- object Squares {
3
+ object DifferenceOfSquares {
4
4
 
5
5
  def sumOfSquares(n: Int): Int = n * (n + 1) * (2 * n + 1) / 6
6
6
 
7
- def squareOfSums(n: Int): Int = pow((n * (n + 1) / 2), 2).toInt
7
+ def squareOfSum(n: Int): Int = pow((n * (n + 1) / 2), 2).toInt
8
8
 
9
- def difference(n: Int): Int = squareOfSums(n) - sumOfSquares(n)
9
+ def differenceOfSquares(n: Int): Int = squareOfSum(n) - sumOfSquares(n)
10
10
  }