trackler 2.0.0.3 → 2.0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/common/CONTRIBUTING.md +1 -1
  3. data/common/README.md +4 -4
  4. data/common/exercises/bowling/canonical-data.json +8 -0
  5. data/common/exercises/hello-world/description.md +1 -1
  6. data/lib/trackler/version.rb +1 -1
  7. data/tracks/c/.gitignore +1 -0
  8. data/tracks/c/bin/run-tests +3 -0
  9. data/tracks/c/config.json +9 -0
  10. data/tracks/c/exercises/clock/makefile +16 -0
  11. data/tracks/c/exercises/clock/src/clock.h +11 -0
  12. data/tracks/c/exercises/clock/src/example.c +31 -0
  13. data/tracks/c/exercises/clock/test/test_clock.c +489 -0
  14. data/tracks/c/exercises/clock/test/vendor/unity.c +1300 -0
  15. data/tracks/c/exercises/clock/test/vendor/unity.h +274 -0
  16. data/tracks/c/exercises/clock/test/vendor/unity_internals.h +701 -0
  17. data/tracks/coldfusion/config.json +2 -1
  18. data/tracks/coldfusion/img/icon.png +0 -0
  19. data/tracks/crystal/Makefile +11 -15
  20. data/tracks/crystal/SETUP.md +1 -1
  21. data/tracks/crystal/docs/LEARNING.md +5 -3
  22. data/tracks/crystal/docs/TESTS.md +24 -3
  23. data/tracks/crystal/exercises/anagram/{anagram_spec.cr → spec/anagram_spec.cr} +1 -1
  24. data/tracks/crystal/exercises/anagram/{example.cr → src/example.cr} +0 -0
  25. data/tracks/crystal/exercises/atbash-cipher/{atbash_cipher_spec.cr → spec/atbash_cipher_spec.cr} +1 -1
  26. data/tracks/crystal/exercises/atbash-cipher/{example.cr → src/example.cr} +0 -0
  27. data/tracks/crystal/exercises/bob/{bob_spec.cr → spec/bob_spec.cr} +1 -1
  28. data/tracks/crystal/exercises/bob/{example.cr → src/example.cr} +0 -0
  29. data/tracks/crystal/exercises/bracket-push/{bracket_push_spec.cr → spec/bracket_push_spec.cr} +1 -1
  30. data/tracks/crystal/exercises/bracket-push/{example.cr → src/example.cr} +0 -0
  31. data/tracks/crystal/exercises/gigasecond/{gigasecond_spec.cr → spec/gigasecond_spec.cr} +1 -1
  32. data/tracks/crystal/exercises/gigasecond/{example.cr → src/example.cr} +0 -0
  33. data/tracks/crystal/exercises/hamming/{hamming_spec.cr → spec/hamming_spec.cr} +1 -1
  34. data/tracks/crystal/exercises/hamming/{example.cr → src/example.cr} +0 -0
  35. data/tracks/crystal/exercises/hello-world/HINTS.md +32 -0
  36. data/tracks/crystal/exercises/hello-world/{hello_world_spec.cr → spec/hello_world_spec.cr} +1 -1
  37. data/tracks/crystal/exercises/hello-world/{example.cr → src/example.cr} +0 -0
  38. data/tracks/crystal/exercises/largest-series-product/{largest_series_product_spec.cr → spec/largest_series_product_spec.cr} +1 -1
  39. data/tracks/crystal/exercises/largest-series-product/{example.cr → src/example.cr} +0 -0
  40. data/tracks/crystal/exercises/leap/{leap_spec.cr → spec/leap_spec.cr} +1 -1
  41. data/tracks/crystal/exercises/leap/{example.cr → src/example.cr} +0 -0
  42. data/tracks/crystal/exercises/pangram/{pangram_spec.cr → spec/pangram_spec.cr} +1 -1
  43. data/tracks/crystal/exercises/pangram/{example.cr → src/example.cr} +0 -0
  44. data/tracks/crystal/exercises/raindrops/{raindrops_spec.cr → spec/raindrops_spec.cr} +1 -1
  45. data/tracks/crystal/exercises/raindrops/{example.cr → src/example.cr} +0 -0
  46. data/tracks/crystal/exercises/react/{react_spec.cr → spec/react_spec.cr} +1 -1
  47. data/tracks/crystal/exercises/react/{example.cr → src/example.cr} +0 -0
  48. data/tracks/crystal/exercises/rna-transcription/{rna_transcription_spec.cr → spec/rna_transcription_spec.cr} +1 -1
  49. data/tracks/crystal/exercises/rna-transcription/{example.cr → src/example.cr} +0 -0
  50. data/tracks/crystal/exercises/roman-numerals/{roman_numerals_spec.cr → spec/roman_numerals_spec.cr} +1 -1
  51. data/tracks/crystal/exercises/roman-numerals/{example.cr → src/example.cr} +0 -0
  52. data/tracks/crystal/exercises/sieve/{sieve_spec.cr → spec/sieve_spec.cr} +1 -1
  53. data/tracks/crystal/exercises/sieve/{example.cr → src/example.cr} +0 -0
  54. data/tracks/haskell/.travis.yml +4 -2
  55. data/tracks/haskell/config.json +6 -6
  56. data/tracks/haskell/exercises/alphametics/package.yaml +0 -1
  57. data/tracks/haskell/exercises/atbash-cipher/package.yaml +0 -1
  58. data/tracks/haskell/exercises/bank-account/package.yaml +0 -1
  59. data/tracks/haskell/exercises/binary-search-tree/HINTS.md +3 -2
  60. data/tracks/haskell/exercises/binary-search-tree/src/BST.hs +2 -0
  61. data/tracks/haskell/exercises/change/test/Tests.hs +2 -1
  62. data/tracks/haskell/exercises/connect/package.yaml +0 -1
  63. data/tracks/haskell/exercises/crypto-square/package.yaml +0 -1
  64. data/tracks/haskell/exercises/custom-set/HINTS.md +3 -2
  65. data/tracks/haskell/exercises/custom-set/src/CustomSet.hs +3 -2
  66. data/tracks/haskell/exercises/food-chain/package.yaml +0 -1
  67. data/tracks/haskell/exercises/forth/HINTS.md +3 -2
  68. data/tracks/haskell/exercises/forth/src/Forth.hs +2 -0
  69. data/tracks/haskell/exercises/go-counting/package.yaml +0 -1
  70. data/tracks/haskell/exercises/grade-school/package.yaml +0 -1
  71. data/tracks/haskell/exercises/grains/src/Grains.hs +3 -1
  72. data/tracks/haskell/exercises/kindergarten-garden/package.yaml +0 -1
  73. data/tracks/haskell/exercises/largest-series-product/package.yaml +0 -1
  74. data/tracks/haskell/exercises/lens-person/package.yaml +0 -1
  75. data/tracks/haskell/exercises/linked-list/package.yaml +0 -1
  76. data/tracks/haskell/exercises/ocr-numbers/package.yaml +0 -2
  77. data/tracks/haskell/exercises/parallel-letter-frequency/package.yaml +0 -1
  78. data/tracks/haskell/exercises/rna-transcription/package.yaml +0 -1
  79. data/tracks/haskell/exercises/robot-name/package.yaml +0 -1
  80. data/tracks/haskell/exercises/saddle-points/package.yaml +0 -1
  81. data/tracks/haskell/exercises/say/package.yaml +0 -1
  82. data/tracks/haskell/exercises/scrabble-score/package.yaml +0 -1
  83. data/tracks/haskell/exercises/series/HINTS.md +23 -0
  84. data/tracks/haskell/exercises/series/examples/success-byteseqs/package.yaml +19 -0
  85. data/tracks/haskell/exercises/series/examples/success-byteseqs/src/Series.hs +26 -0
  86. data/tracks/haskell/exercises/series/src/Series.hs +2 -1
  87. data/tracks/haskell/exercises/series/test/Tests.hs +16 -11
  88. data/tracks/haskell/exercises/sgf-parsing/package.yaml +0 -1
  89. data/tracks/haskell/exercises/sieve/package.yaml +0 -1
  90. data/tracks/haskell/exercises/simple-cipher/package.yaml +0 -1
  91. data/tracks/haskell/exercises/triangle/package.yaml +0 -1
  92. data/tracks/haskell/exercises/word-count/examples/success-newtype/src/WordCount.hs +7 -4
  93. data/tracks/haskell/exercises/word-count/examples/success-simple/src/WordCount.hs +6 -2
  94. data/tracks/haskell/exercises/word-count/test/Tests.hs +30 -1
  95. data/tracks/haskell/exercises/wordy/package.yaml +0 -2
  96. data/tracks/java/docs/INSTALLATION.md +2 -0
  97. data/tracks/java/exercises/_template/build.gradle +1 -1
  98. data/tracks/java/exercises/accumulate/build.gradle +1 -1
  99. data/tracks/java/exercises/acronym/build.gradle +1 -1
  100. data/tracks/java/exercises/allergies/build.gradle +1 -1
  101. data/tracks/java/exercises/anagram/build.gradle +1 -1
  102. data/tracks/java/exercises/atbash-cipher/build.gradle +1 -1
  103. data/tracks/java/exercises/beer-song/build.gradle +1 -1
  104. data/tracks/java/exercises/binary/build.gradle +1 -1
  105. data/tracks/java/exercises/bob/build.gradle +1 -1
  106. data/tracks/java/exercises/crypto-square/build.gradle +1 -1
  107. data/tracks/java/exercises/etl/build.gradle +1 -1
  108. data/tracks/java/exercises/gigasecond/build.gradle +1 -1
  109. data/tracks/java/exercises/grade-school/build.gradle +1 -1
  110. data/tracks/java/exercises/hamming/build.gradle +1 -1
  111. data/tracks/java/exercises/hello-world/build.gradle +1 -1
  112. data/tracks/java/exercises/hexadecimal/build.gradle +1 -1
  113. data/tracks/java/exercises/linked-list/build.gradle +1 -1
  114. data/tracks/java/exercises/luhn/build.gradle +1 -1
  115. data/tracks/java/exercises/meetup/build.gradle +1 -1
  116. data/tracks/java/exercises/nth-prime/build.gradle +1 -1
  117. data/tracks/java/exercises/nucleotide-count/build.gradle +1 -1
  118. data/tracks/java/exercises/octal/build.gradle +1 -1
  119. data/tracks/java/exercises/pangram/build.gradle +1 -1
  120. data/tracks/java/exercises/pascals-triangle/build.gradle +1 -1
  121. data/tracks/java/exercises/phone-number/build.gradle +1 -1
  122. data/tracks/java/exercises/pig-latin/build.gradle +1 -1
  123. data/tracks/java/exercises/raindrops/build.gradle +1 -1
  124. data/tracks/java/exercises/rna-transcription/build.gradle +1 -1
  125. data/tracks/java/exercises/robot-name/build.gradle +1 -1
  126. data/tracks/java/exercises/roman-numerals/build.gradle +1 -1
  127. data/tracks/java/exercises/scrabble-score/build.gradle +1 -1
  128. data/tracks/java/exercises/sieve/build.gradle +1 -1
  129. data/tracks/java/exercises/simple-cipher/build.gradle +1 -1
  130. data/tracks/java/exercises/simple-linked-list/build.gradle +1 -1
  131. data/tracks/java/exercises/space-age/build.gradle +1 -1
  132. data/tracks/java/exercises/strain/build.gradle +1 -1
  133. data/tracks/java/exercises/triangle/build.gradle +1 -1
  134. data/tracks/java/exercises/trinary/build.gradle +1 -1
  135. data/tracks/java/exercises/word-count/build.gradle +1 -1
  136. data/tracks/ocaml/.travis-ci.sh +1 -1
  137. data/tracks/ocaml/.travis.yml +1 -1
  138. data/tracks/ocaml/README.md +1 -1
  139. data/tracks/ocaml/exercises/hamming/hamming.mli +1 -3
  140. data/tracks/ruby/exercises/leap/.version +1 -1
  141. data/tracks/ruby/exercises/leap/example.tt +3 -3
  142. data/tracks/ruby/exercises/leap/leap_test.rb +3 -4
  143. data/tracks/ruby/lib/leap_cases.rb +2 -2
  144. data/tracks/rust/exercises/bowling/tests/bowling.rs +29 -0
  145. data/tracks/swift/.gitignore +1 -0
  146. data/tracks/swift/.swift-version +1 -0
  147. data/tracks/swift/exercises/bowling/BowlingExample.swift +2 -2
  148. data/tracks/swift/exercises/bowling/BowlingTest.swift +84 -94
  149. data/tracks/swift/exercises/palindrome-products/PalindromeProductsExample.swift +19 -16
  150. data/tracks/tcl/README.md +3 -0
  151. data/tracks/tcl/config.json +2 -1
  152. data/tracks/tcl/img/icon.png +0 -0
  153. metadata +46 -33
  154. data/tracks/crystal/exercises/hello-world/GETTING_STARTED.md +0 -10
@@ -7,7 +7,7 @@ repositories {
7
7
  }
8
8
 
9
9
  dependencies {
10
- testCompile "junit:junit:4.10"
10
+ testCompile "junit:junit:4.12"
11
11
  }
12
12
  test {
13
13
  testLogging {
@@ -7,7 +7,7 @@ repositories {
7
7
  }
8
8
 
9
9
  dependencies {
10
- testCompile "junit:junit:4.10"
10
+ testCompile "junit:junit:4.12"
11
11
  }
12
12
  test {
13
13
  testLogging {
@@ -2,7 +2,7 @@
2
2
  OPAM_DEPENDS="ocamlfind core ounit react"
3
3
 
4
4
  case "$OCAML_VERSION,$OPAM_VERSION" in
5
- 4.03.0,1.2.2) ppa=avsm/ocaml42+opam12 ;;
5
+ 4.04.0,1.2.2) ppa=avsm/ocaml42+opam12 ;;
6
6
  *) echo Unknown $OCAML_VERSION,$OPAM_VERSION; exit 1 ;;
7
7
  esac
8
8
 
@@ -6,4 +6,4 @@ script:
6
6
  - bin/configlet .
7
7
 
8
8
  env:
9
- - OCAML_VERSION=4.03.0 OPAM_VERSION=1.2.2
9
+ - OCAML_VERSION=4.04.0 OPAM_VERSION=1.2.2
@@ -11,7 +11,7 @@ notes contain a few details specific to Ocaml.
11
11
 
12
12
  ## Prerequisites
13
13
 
14
- The OCaml track assumes installation of OCaml version 4.03.0, and installation of Core, OUnit, and React (for the Hangman exercise).
14
+ The OCaml track assumes installation of OCaml version 4.04.0, and installation of Core, OUnit, and React (for the Hangman exercise).
15
15
  Assuming you have opam, these can be installed with
16
16
  ```bash
17
17
  opam install core ounit react
@@ -1,6 +1,4 @@
1
- (** Point-mutation exercise *)
2
-
3
1
  type nucleotide = A | C | G | T
4
2
 
5
- (** Compute the hammning distance between the two lists. *)
3
+ (** Compute the hamming distance between the two lists. *)
6
4
  val hamming_distance : nucleotide list -> nucleotide list -> int option
@@ -1 +1 @@
1
- 2
1
+ 2
@@ -7,7 +7,7 @@ require_relative 'leap'
7
7
  # <%= sha1 %>
8
8
  class Date
9
9
  def leap?
10
- throw "Implement this yourself instead of using Ruby's implementation."
10
+ raise RuntimeError, "Implement this yourself instead of using Ruby's implementation."
11
11
  end
12
12
 
13
13
  alias gregorian_leap? leap?
@@ -15,8 +15,8 @@ class Date
15
15
  end
16
16
 
17
17
  class YearTest < Minitest::Test<% test_cases.each do |test_case| %>
18
- def <%= test_case.name %><% if test_case.skipped? %>
19
- skip<% end %><% if test_case.expected%>
18
+ def <%= test_case.name %>
19
+ <%= test_case.skip %><% if test_case.expected%>
20
20
  assert <%= test_case.do %>, "<%= test_case.failure_message%>"<% else %>
21
21
  refute <%= test_case.do %>, "<%= test_case.failure_message%>"<% end%>
22
22
  end
@@ -4,10 +4,10 @@ require 'minitest/autorun'
4
4
  require_relative 'leap'
5
5
 
6
6
  # Test data version:
7
- # 9b8b80c
7
+ # 7b0949e
8
8
  class Date
9
9
  def leap?
10
- throw "Implement this yourself instead of using Ruby's implementation."
10
+ raise RuntimeError, "Implement this yourself instead of using Ruby's implementation."
11
11
  end
12
12
 
13
13
  alias gregorian_leap? leap?
@@ -16,6 +16,7 @@ end
16
16
 
17
17
  class YearTest < Minitest::Test
18
18
  def test_leap_year
19
+ # skip
19
20
  assert Year.leap?(1996), "Expected 'true', 1996 is a leap year."
20
21
  end
21
22
 
@@ -48,7 +49,6 @@ class YearTest < Minitest::Test
48
49
  skip
49
50
  assert Year.leap?(2000), "Expected 'true', 2000 is a leap year."
50
51
  end
51
-
52
52
  # Problems in exercism evolve over time, as we find better ways to ask
53
53
  # questions.
54
54
  # The version number refers to the version of the problem you solved,
@@ -65,7 +65,6 @@ class YearTest < Minitest::Test
65
65
  #
66
66
  # If you are curious, read more about constants on RubyDoc:
67
67
  # http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html
68
-
69
68
  def test_bookkeeping
70
69
  skip
71
70
  assert_equal 2, BookKeeping::VERSION
@@ -7,8 +7,8 @@ class LeapCase < OpenStruct
7
7
  "Year.leap?(#{input})"
8
8
  end
9
9
 
10
- def skipped?
11
- index > 0
10
+ def skip
11
+ index.zero? ? '# skip' : 'skip'
12
12
  end
13
13
 
14
14
  def failure_message
@@ -286,6 +286,20 @@ fn you_can_not_roll_more_than_ten_pins_in_a_single_frame() {
286
286
  assert!(game.roll(6).is_err());
287
287
  }
288
288
 
289
+ #[test]
290
+ #[ignore]
291
+ fn first_bonus_ball_after_a_final_strike_can_not_score_an_invalid_number_of_pins() {
292
+ let mut game = BowlingGame::new();
293
+
294
+ for _ in 0..18 {
295
+ let _ = game.roll(0);
296
+ }
297
+
298
+ let _ = game.roll(10);
299
+
300
+ assert!(game.roll(11).is_err());
301
+ }
302
+
289
303
  #[test]
290
304
  #[ignore]
291
305
  fn the_two_balls_after_a_final_strike_can_not_score_an_invalid_number_of_pins() {
@@ -331,6 +345,21 @@ fn the_two_balls_after_a_final_strike_can_not_be_a_non_strike_followed_by_a_stri
331
345
  assert!(game.roll(10).is_err());
332
346
  }
333
347
 
348
+ #[test]
349
+ #[ignore]
350
+ fn second_bonus_ball_after_a_final_strike_can_not_score_an_invalid_number_of_pins_even_if_first_is_strike() {
351
+ let mut game = BowlingGame::new();
352
+
353
+ for _ in 0..18 {
354
+ let _ = game.roll(0);
355
+ }
356
+
357
+ let _ = game.roll(10);
358
+
359
+ assert!(game.roll(10).is_ok());
360
+ assert!(game.roll(11).is_err());
361
+ }
362
+
334
363
  #[test]
335
364
  #[ignore]
336
365
  fn if_the_last_frame_is_a_strike_you_can_not_score_before_the_extra_rolls_are_taken() {
@@ -19,3 +19,4 @@ DerivedData
19
19
  *.hmap
20
20
  *.ipa
21
21
  *.xcuserstate
22
+ .DS_Store
@@ -0,0 +1 @@
1
+ 3.0
@@ -78,7 +78,7 @@ struct Bowling {
78
78
  if isLastFrame {
79
79
  let lastRollWasStrike = scoreCard[currentFrame]?.last == 10
80
80
 
81
- if lastRollWasStrike {
81
+ if lastRollWasStrike || isSpare() {
82
82
  return true
83
83
  }
84
84
  }
@@ -94,7 +94,7 @@ struct Bowling {
94
94
 
95
95
  private func frameComplete() -> Bool {
96
96
  if isLastFrame {
97
- return frameFilled(rolls: 3) || isOpenFrame() && frameFilled()
97
+ return isOpenFrame() && frameFilled() || frameFilled(rolls: 3)
98
98
  }
99
99
 
100
100
  return frameFilled() || isStrike()
@@ -2,7 +2,6 @@
2
2
  import XCTest
3
3
  #endif
4
4
 
5
- // swiftlint:disable force_try
6
5
  class BowlingTest: XCTestCase {
7
6
 
8
7
  var game: Bowling!
@@ -11,170 +10,161 @@ class BowlingTest: XCTestCase {
11
10
  game = Bowling()
12
11
  }
13
12
 
14
- func testOpenFrame() {
15
- try! game.roll(pins: 3)
16
- try! game.roll(pins: 4)
17
- rollNTimes(rolls: 18, pins: 0)
18
- XCTAssertEqual(try? game.score(), 7)
19
- }
20
-
21
- func testMultipleFrames() {
22
- [3, 4, 2, 3, 5, 2].forEach {
23
- try? game.roll(pins: $0)
13
+ func roll(_ seriesOfPins: [Int]) throws {
14
+ for pins in seriesOfPins {
15
+ try game.roll(pins: pins)
24
16
  }
25
- rollNTimes(rolls: 14, pins: 0)
26
- XCTAssertEqual(try? game.score(), 19)
27
17
  }
28
18
 
29
- func testAllGutterballs() {
30
- rollNTimes(rolls: 20, pins: 0)
19
+ func testAllZeros() {
20
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
21
+
31
22
  XCTAssertEqual(try? game.score(), 0)
32
23
  }
33
24
 
34
- func testAllSinglePinRolls() {
35
- rollNTimes(rolls: 20, pins: 1)
36
- XCTAssertEqual(try? game.score(), 20)
37
- }
25
+ func testNoStrikesOrSpares() {
26
+ try? roll([3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6])
38
27
 
39
- func testAllOpenFrames() {
40
- rollNTimes(rolls: 10, pins: 3, 6)
41
28
  XCTAssertEqual(try? game.score(), 90)
42
29
  }
43
30
 
44
- func testStrikeNotLastFrame() {
45
- try? game.roll(pins: 10)
46
- try? game.roll(pins: 5)
47
- try? game.roll(pins: 3)
48
- rollNTimes(rolls: 16, pins: 0)
31
+ func testSpareFollowedByZeros() {
32
+ try? roll([6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
49
33
 
50
- XCTAssertEqual(try? game.score(), 26)
34
+ XCTAssertEqual(try? game.score(), 10)
51
35
  }
52
36
 
53
- func testSpareNotLastFrame() {
54
- try? game.roll(pins: 5)
55
- try? game.roll(pins: 5)
56
- try? game.roll(pins: 3)
57
- try? game.roll(pins: 4)
58
- rollNTimes(rolls: 16, pins: 0)
37
+ func testPointsScoredInRollAfterSpare() {
38
+ try? roll([6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
59
39
 
60
- XCTAssertEqual(try? game.score(), 20)
40
+ XCTAssertEqual(try? game.score(), 16)
61
41
  }
62
42
 
63
- func testMultipleStrikesInARow() {
64
- try? game.roll(pins: 10)
65
- try? game.roll(pins: 10)
66
- try? game.roll(pins: 10)
67
- try? game.roll(pins: 5)
68
- try? game.roll(pins: 3)
69
- rollNTimes(rolls: 12, pins: 0)
43
+ func testConsecutiveSpares() {
44
+ try? roll([5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
70
45
 
71
- XCTAssertEqual(try? game.score(), 81)
46
+ XCTAssertEqual(try? game.score(), 31)
47
+ }
48
+
49
+ func testSpareInLastFrame() {
50
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7])
51
+
52
+ XCTAssertEqual(try? game.score(), 17)
53
+ }
54
+
55
+ func testStrikeWithSingleRoll() {
56
+ try? roll([10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
57
+
58
+ XCTAssertEqual(try? game.score(), 10)
59
+ }
60
+
61
+ func testTwoRollsAfterAStrike() {
62
+ try? roll([10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
63
+
64
+ XCTAssertEqual(try? game.score(), 26)
72
65
  }
73
66
 
74
- func testMultipleSparesInARow() {
75
- try? game.roll(pins: 5)
76
- try? game.roll(pins: 5)
77
- try? game.roll(pins: 3)
78
- try? game.roll(pins: 7)
79
- try? game.roll(pins: 4)
80
- try? game.roll(pins: 1)
81
- rollNTimes(rolls: 14, pins: 0)
67
+ func testConsecutiveStrikes() {
68
+ try? roll([10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
82
69
 
83
- XCTAssertEqual(try? game.score(), 32)
70
+ XCTAssertEqual(try? game.score(), 81)
84
71
  }
85
72
 
86
- func testStrikeInFinalFrame() {
87
- rollNTimes(rolls: 18, pins: 0)
88
- try? game.roll(pins: 10)
89
- try? game.roll(pins: 7)
90
- try? game.roll(pins: 1)
73
+ func testStrikeInLastFrame() {
74
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1])
91
75
 
92
76
  XCTAssertEqual(try? game.score(), 18)
93
77
  }
94
78
 
95
- func testSpareInFinalFrame() {
96
- rollNTimes(rolls: 18, pins: 0)
97
- try? game.roll(pins: 9)
98
- try? game.roll(pins: 1)
99
- try? game.roll(pins: 7)
79
+ func testSpareWithTwoRollBonus() {
80
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3])
100
81
 
101
- XCTAssertEqual(try? game.score(), 17)
82
+ XCTAssertEqual(try? game.score(), 20)
102
83
  }
103
84
 
104
- func testFillBallsStrikes() {
105
- rollNTimes(rolls: 18, pins: 0)
106
- try? game.roll(pins: 10)
107
- try? game.roll(pins: 10)
108
- try? game.roll(pins: 10)
85
+ func testStrikesWithTwoRollBonus() {
86
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10])
109
87
 
110
88
  XCTAssertEqual(try? game.score(), 30)
111
89
  }
112
90
 
113
- func testPerfectGame() {
114
- rollNTimes(rolls: 12, pins: 10)
91
+ func testStrikeAfterSpareInLastFrame() {
92
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10])
93
+
94
+ XCTAssertEqual(try? game.score(), 20)
95
+ }
96
+
97
+ func testAllStrikes() {
98
+ try? roll([10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
99
+
115
100
  XCTAssertEqual(try? game.score(), 300)
116
101
  }
117
102
 
118
- func testNegativePins() {
119
- XCTAssertThrowsError(try game.roll(pins: -1)) { error in
103
+ func testNegativePoints() {
104
+ XCTAssertThrowsError(try roll([-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { error in
120
105
  XCTAssertEqual(error as? Bowling.BowlingError, .invalidNumberOfPins)
121
106
  }
122
107
  }
123
108
 
124
- func testRollsBetterThanStrike() {
125
- XCTAssertThrowsError(try game.roll(pins: 11)) { error in
109
+ func testNoMoreThan10PinsPerRoll() {
110
+ XCTAssertThrowsError(try roll([11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { error in
126
111
  XCTAssertEqual(error as? Bowling.BowlingError, .invalidNumberOfPins)
127
112
  }
128
113
  }
129
114
 
130
- func testTwoNormalRollsBetterThanStrike() {
131
- try? game.roll(pins: 5)
132
- XCTAssertThrowsError(try game.roll(pins: 6)) { error in
115
+ func testTwoRollsGreaterThan10() {
116
+ XCTAssertThrowsError(try roll([5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { error in
133
117
  XCTAssertEqual(error as? Bowling.BowlingError, .tooManyPinsInFrame)
134
118
  }
135
119
  }
136
120
 
137
- func testTwoNormalRollsBetterThanStrikeInLastFrame() {
138
- rollNTimes(rolls: 18, pins: 0)
139
- try? game.roll(pins: 10)
140
- try? game.roll(pins: 5)
141
- XCTAssertThrowsError(try game.roll(pins: 6)) { error in
121
+ func testTwoBonusRollsAfterStrike() {
122
+ XCTAssertThrowsError(try roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6])) { error in
142
123
  XCTAssertEqual(error as? Bowling.BowlingError, .tooManyPinsInFrame)
143
124
  }
144
125
  }
145
126
 
146
- func testTakeScoreAtBeginning() {
127
+ func testUnstartedGameCanNotBeScored() {
147
128
  XCTAssertThrowsError(try game.score()) { error in
148
129
  XCTAssertEqual(error as? Bowling.BowlingError, .gameInProgress)
149
130
  }
150
131
  }
151
132
 
152
- func testTakeScoreBeforeGameHasEnded() {
153
- rollNTimes(rolls: 19, pins: 5)
133
+ func testIncompleteGameCanNotBeScored() {
134
+ try? roll([0, 0])
135
+
154
136
  XCTAssertThrowsError(try game.score()) { error in
155
137
  XCTAssertEqual(error as? Bowling.BowlingError, .gameInProgress)
156
138
  }
157
139
  }
158
140
 
159
- func testRollsAfterTheTenthFrame() {
160
- rollNTimes(rolls: 20, pins: 0)
161
- XCTAssertThrowsError(try game.roll(pins: 0)) { error in
141
+ func testMoreThanTenFrames() {
142
+ XCTAssertThrowsError(try roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { error in
162
143
  XCTAssertEqual(error as? Bowling.BowlingError, .gameIsOver)
163
144
  }
164
145
  }
165
146
 
166
- func testCalculateScoreBeforeFillBallsHaveBeenPlayed() {
167
- rollNTimes(rolls: 10, pins: 10)
147
+ func testBonusRollsNotRolled() {
148
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10])
149
+
168
150
  XCTAssertThrowsError(try game.score()) { error in
169
151
  XCTAssertEqual(error as? Bowling.BowlingError, .gameInProgress)
170
152
  }
171
153
  }
172
154
 
173
- private func rollNTimes(rolls: Int, pins: Int...) {
174
- for _ in 1...rolls {
175
- pins.forEach {
176
- try? game.roll(pins: $0)
177
- }
155
+ func testSecondBonusRollNotRolled() {
156
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10])
157
+
158
+ XCTAssertThrowsError(try game.score()) { error in
159
+ XCTAssertEqual(error as? Bowling.BowlingError, .gameInProgress)
160
+ }
161
+ }
162
+
163
+ func testBonusRollForSpareNotRolled() {
164
+ try? roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3])
165
+
166
+ XCTAssertThrowsError(try game.score()) { error in
167
+ XCTAssertEqual(error as? Bowling.BowlingError, .gameInProgress)
178
168
  }
179
169
  }
180
170
 
@@ -2,14 +2,10 @@ import Foundation
2
2
 
3
3
  private extension String {
4
4
 
5
- var length: Int {return self.characters.count}
5
+ var length: Int { return self.characters.count }
6
6
 
7
7
  func reverse() -> String {
8
- var result: String = ""
9
- for char in self.characters {
10
- result = "\(char)\(result)"
11
- }
12
- return result
8
+ return characters.reversed().map { String($0) }.joined()
13
9
  }
14
10
  }
15
11
 
@@ -19,8 +15,8 @@ struct PalindromeProducts {
19
15
  private let maxFactor: Int
20
16
  private let minFactor: Int
21
17
 
22
- var largest: Palindrome {return calculate(.max)}
23
- var smallest: Palindrome {return calculate(.min)}
18
+ var largest: Palindrome { return calculate(.max) }
19
+ var smallest: Palindrome { return calculate(.min) }
24
20
 
25
21
  init(maxFactor: Int, minFactor: Int = 1) {
26
22
  self.maxFactor = maxFactor
@@ -31,10 +27,11 @@ struct PalindromeProducts {
31
27
  private func calculate(_ upTo: Mode) -> Palindrome {
32
28
 
33
29
  let rangeOuter = minFactor...maxFactor
34
- var multiplications = [Palindrome]()
35
30
 
36
31
  //Multithreaded code
37
32
  var results = [[Palindrome]](repeating: [Palindrome](), count: rangeOuter.count)
33
+ // use this queue to read and write from results
34
+ let resultsRWQueue = DispatchQueue.init(label: "exercism.resultsRWQueue")
38
35
 
39
36
  DispatchQueue.concurrentPerform(iterations: rangeOuter.count) {
40
37
  advanceByIndex in
@@ -49,19 +46,25 @@ struct PalindromeProducts {
49
46
  multiplicationsTemp.append((multiplied, [each, eaInside]))
50
47
  }
51
48
  }
52
- results[advanceByIndex] = multiplicationsTemp
49
+ // prevent data race conditions
50
+ resultsRWQueue.async {
51
+ results[advanceByIndex] = multiplicationsTemp
52
+ }
53
+ }
54
+ var multiplications = [Palindrome]()
55
+ // prevent data race conditions
56
+ resultsRWQueue.sync {
57
+ multiplications = results.joined().sorted(by: { $0.value > $1.value })
53
58
  }
54
- multiplications = results.joined().sorted(by: {$0.0 > $1.0})
55
-
56
59
  if let large = multiplications.first, let small = multiplications.last {
57
60
  switch upTo {
58
- case .max : return large
59
- case .min : return small
61
+ case .max: return large
62
+ case .min: return small
60
63
  }
61
64
  } else {
62
65
  switch upTo {
63
- case .max : return (self.maxFactor, [self.maxFactor, 1])
64
- case .min : return (self.minFactor, [self.minFactor, 1])
66
+ case .max: return (maxFactor, [maxFactor, 1])
67
+ case .min: return (minFactor, [minFactor, 1])
65
68
  }
66
69
  }
67
70
  }
data/tracks/tcl/README.md CHANGED
@@ -16,3 +16,6 @@ The MIT License (MIT)
16
16
 
17
17
  Copyright (c) 2015 Katrina Owen, _@kytrinyx.com
18
18
 
19
+ ### Tcl icon
20
+ The Tcl icon was created by [Fant0men at en.wikipedia](https://en.wikipedia.org/wiki/User:Fant0men) and released under the [Creative Commons Attribution-ShareAlike 3.0 Unported](https://creativecommons.org/licenses/by-sa/3.0/) license.
21
+ We adapted the icon, creating a black, pink and white version of it to use on Exercism.
@@ -8,7 +8,8 @@
8
8
 
9
9
  ],
10
10
  "ignored": [
11
- "bin"
11
+ "bin",
12
+ "img"
12
13
  ],
13
14
  "foregone": [
14
15
 
Binary file