trackler 1.0.4.0 → 1.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/common/CONTRIBUTING.md +17 -2
  3. data/common/exercises/anagram/canonical-data.json +0 -14
  4. data/common/exercises/pig-latin/canonical-data.json +6 -1
  5. data/common/exercises/raindrops/description.md +4 -4
  6. data/common/exercises/raindrops/metadata.yml +1 -1
  7. data/common/exercises/roman-numerals/metadata.yml +1 -1
  8. data/lib/trackler/version.rb +1 -1
  9. data/tracks/c/config.json +12 -1
  10. data/tracks/c/exercises/roman-numerals/makefile +16 -0
  11. data/tracks/c/exercises/roman-numerals/src/example.c +43 -0
  12. data/tracks/c/exercises/roman-numerals/src/example.h +6 -0
  13. data/tracks/c/exercises/roman-numerals/test/test_roman_numerals.c +126 -0
  14. data/tracks/c/exercises/roman-numerals/test/vendor/unity.c +1300 -0
  15. data/tracks/c/exercises/roman-numerals/test/vendor/unity.h +274 -0
  16. data/tracks/c/exercises/roman-numerals/test/vendor/unity_internals.h +701 -0
  17. data/tracks/clojure/exercises/flatten-array/project.clj +4 -0
  18. data/tracks/csharp/exercises/protein-translation/ProteinTranslationTest.cs +1 -1
  19. data/tracks/elixir/exercises/bowling/bowling_test.exs +157 -62
  20. data/tracks/elixir/exercises/bowling/example.exs +33 -4
  21. data/tracks/erlang/config.json +176 -36
  22. data/tracks/go/.travis.yml +7 -1
  23. data/tracks/go/bin/test-without-stubs +29 -0
  24. data/tracks/go/exercises/robot-simulator/defs.go +1 -1
  25. data/tracks/go/exercises/variable-length-quantity/variable_length_quantity_test.go +31 -25
  26. data/tracks/haskell/.travis.yml +9 -5
  27. data/tracks/haskell/config.json +127 -121
  28. data/tracks/haskell/exercises/leap/src/LeapYear.hs +1 -1
  29. data/tracks/haskell/exercises/space-age/HINTS.md +14 -2
  30. data/tracks/haskell/exercises/space-age/{src/Example.hs → examples/success-double/SpaceAge.hs} +0 -0
  31. data/tracks/haskell/exercises/space-age/examples/success-double/package.yaml +19 -0
  32. data/tracks/haskell/exercises/space-age/examples/success-rational/SpaceAge.hs +24 -0
  33. data/tracks/haskell/exercises/space-age/examples/success-rational/package.yaml +19 -0
  34. data/tracks/haskell/exercises/space-age/src/SpaceAge.hs +4 -1
  35. data/tracks/haskell/exercises/space-age/test/Tests.hs +12 -5
  36. data/tracks/haskell/exercises/word-count/HINTS.md +21 -0
  37. data/tracks/haskell/exercises/word-count/examples/success-newtype/WordCount.hs +31 -0
  38. data/tracks/haskell/exercises/word-count/examples/success-newtype/package.yaml +21 -0
  39. data/tracks/haskell/exercises/word-count/examples/success-simple/WordCount.hs +13 -0
  40. data/tracks/haskell/exercises/word-count/examples/success-simple/package.yaml +20 -0
  41. data/tracks/haskell/exercises/word-count/package.yaml +0 -2
  42. data/tracks/haskell/exercises/word-count/src/WordCount.hs +2 -1
  43. data/tracks/haskell/exercises/word-count/test/Tests.hs +15 -6
  44. data/tracks/haskell/exercises/zebra-puzzle/package.yaml +19 -0
  45. data/tracks/haskell/exercises/zebra-puzzle/src/Example.hs +113 -0
  46. data/tracks/haskell/exercises/zebra-puzzle/src/ZebraPuzzle.hs +12 -0
  47. data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -0
  48. data/tracks/haskell/exercises/zebra-puzzle/test/Tests.hs +13 -0
  49. data/tracks/javascript/exercises/beer-song/beer-song.spec.js +5 -0
  50. data/tracks/lisp/config.json +147 -0
  51. data/tracks/ocaml/config.json +12 -0
  52. data/tracks/ocaml/exercises/atbash-cipher/.merlin +5 -0
  53. data/tracks/ocaml/exercises/atbash-cipher/HINTS.md +17 -0
  54. data/tracks/ocaml/exercises/atbash-cipher/Makefile +11 -0
  55. data/tracks/ocaml/exercises/atbash-cipher/atbash_cipher.mli +5 -0
  56. data/tracks/ocaml/exercises/atbash-cipher/example.ml +47 -0
  57. data/tracks/ocaml/exercises/atbash-cipher/test.ml +37 -0
  58. data/tracks/ocaml/exercises/meetup/.merlin +5 -0
  59. data/tracks/ocaml/exercises/meetup/Makefile +11 -0
  60. data/tracks/ocaml/exercises/meetup/example.ml +63 -0
  61. data/tracks/ocaml/exercises/meetup/meetup.mli +7 -0
  62. data/tracks/ocaml/exercises/meetup/test.ml +786 -0
  63. data/tracks/php/exercises/bowling/bowling_test.php +233 -10
  64. data/tracks/php/exercises/bowling/example.php +49 -6
  65. data/tracks/python/.travis.yml +5 -0
  66. data/tracks/python/config.json +33 -1
  67. data/tracks/python/exercises/flatten-array/example.py +18 -0
  68. data/tracks/python/exercises/flatten-array/flatten_array_test.py +40 -0
  69. data/tracks/python/exercises/robot-name/robot_name_test.py +8 -2
  70. data/tracks/r/config.json +32 -8
  71. data/tracks/ruby/bin/enable-executable +9 -5
  72. data/tracks/ruby/bin/executable-tests-check +7 -3
  73. data/tracks/ruby/bin/local-status-check +4 -4
  74. data/tracks/ruby/config.json +8 -1
  75. data/tracks/ruby/exercises/acronym/acronym_test.rb +0 -1
  76. data/tracks/ruby/exercises/anagram/.version +1 -0
  77. data/tracks/ruby/exercises/anagram/anagram_test.rb +101 -31
  78. data/tracks/ruby/exercises/anagram/example.rb +4 -0
  79. data/tracks/ruby/exercises/anagram/example.tt +19 -0
  80. data/tracks/ruby/exercises/gigasecond/.version +1 -1
  81. data/tracks/ruby/exercises/gigasecond/example.rb +1 -1
  82. data/tracks/ruby/exercises/gigasecond/gigasecond_test.rb +2 -2
  83. data/tracks/ruby/exercises/isogram/.version +1 -0
  84. data/tracks/ruby/exercises/isogram/example.rb +10 -0
  85. data/tracks/ruby/exercises/isogram/example.tt +20 -0
  86. data/tracks/ruby/exercises/isogram/isogram_test.rb +90 -0
  87. data/tracks/ruby/exercises/poker/example.rb +97 -39
  88. data/tracks/ruby/exercises/poker/poker_test.rb +67 -36
  89. data/tracks/ruby/exercises/sieve/.version +1 -0
  90. data/tracks/ruby/exercises/sieve/example.rb +4 -0
  91. data/tracks/ruby/exercises/sieve/example.tt +21 -0
  92. data/tracks/ruby/exercises/sieve/sieve_test.rb +36 -13
  93. data/tracks/ruby/exercises/word-count/example.tt +4 -3
  94. data/tracks/ruby/exercises/word-count/word_count_test.rb +38 -48
  95. data/tracks/ruby/lib/anagram_cases.rb +42 -0
  96. data/tracks/ruby/lib/isogram_cases.rb +24 -0
  97. data/tracks/ruby/lib/sieve_cases.rb +33 -0
  98. data/tracks/ruby/lib/word_count_cases.rb +19 -0
  99. data/tracks/scala/config.json +21 -0
  100. data/tracks/scala/docs/RESOURCES.md +1 -0
  101. data/tracks/scala/exercises/bracket-push/build.sbt +4 -0
  102. data/tracks/scala/exercises/bracket-push/example.scala +23 -0
  103. data/tracks/scala/exercises/bracket-push/src/main/scala/.keep +0 -0
  104. data/tracks/scala/exercises/bracket-push/src/test/scala/BracketsTest.scala +68 -0
  105. data/tracks/scala/exercises/change/src/test/scala/ChangeTest.scala +7 -0
  106. data/tracks/scala/exercises/sgf-parsing/build.sbt +7 -0
  107. data/tracks/scala/exercises/sgf-parsing/example.scala +66 -0
  108. data/tracks/scala/exercises/sgf-parsing/src/main/scala/.keep +0 -0
  109. data/tracks/scala/exercises/sgf-parsing/src/main/scala/Sgf.scala +17 -0
  110. data/tracks/scala/exercises/sgf-parsing/src/test/scala/SgfTest.scala +66 -0
  111. data/tracks/scala/exercises/zebra-puzzle/build.sbt +3 -0
  112. data/tracks/scala/exercises/zebra-puzzle/example.scala +152 -0
  113. data/tracks/scala/exercises/zebra-puzzle/src/main/scala/.keep +0 -0
  114. data/tracks/scala/exercises/zebra-puzzle/src/main/scala/ZebraPuzzle.scala +14 -0
  115. data/tracks/scala/exercises/zebra-puzzle/src/test/scala/ZebraPuzzleTest.scala +11 -0
  116. data/tracks/scala/testgen/src/main/scala/BracketPushTestGenerator.scala +44 -0
  117. metadata +63 -3
  118. data/tracks/haskell/exercises/word-count/src/Example.hs +0 -8
@@ -16,43 +16,163 @@ class GameTest extends \PHPUnit_Framework_TestCase
16
16
  $this->game = new Game();
17
17
  }
18
18
 
19
- public function testGutterGame()
19
+ public function testShouldBeAbleToScoreAGameWithAllZeros()
20
20
  {
21
21
  $this->rollMany(20, 0);
22
22
 
23
23
  $this->assertEquals(0, $this->game->score());
24
24
  }
25
25
 
26
- public function testAllOnes()
26
+ public function testShouldBeAbleToScoreAGameWithNoStrikesOrSpares()
27
27
  {
28
28
  $this->markTestSkipped();
29
- $this->rollMany(20, 1);
29
+ $this->game->roll(3);
30
+ $this->game->roll(6);
31
+ $this->game->roll(3);
32
+ $this->game->roll(6);
33
+ $this->game->roll(3);
34
+ $this->game->roll(6);
35
+ $this->game->roll(3);
36
+ $this->game->roll(6);
37
+ $this->game->roll(3);
38
+ $this->game->roll(6);
39
+ $this->game->roll(3);
40
+ $this->game->roll(6);
41
+ $this->game->roll(3);
42
+ $this->game->roll(6);
43
+ $this->game->roll(3);
44
+ $this->game->roll(6);
45
+ $this->game->roll(3);
46
+ $this->game->roll(6);
47
+ $this->game->roll(3);
48
+ $this->game->roll(6);
30
49
 
31
- $this->assertEquals(20, $this->game->score());
50
+ $this->assertEquals(90, $this->game->score());
51
+ }
52
+
53
+ public function testASpareFollowedByZerosIsWorthTenPoints()
54
+ {
55
+ $this->markTestSkipped();
56
+ $this->game->roll(6);
57
+ $this->game->roll(4);
58
+ $this->rollMany(18, 0);
59
+
60
+ $this->assertEquals(10, $this->game->score());
32
61
  }
33
62
 
34
- public function testOneSpare()
63
+ public function testPointsScoredInTheRollAfterASpareAreCountedTwice()
35
64
  {
36
65
  $this->markTestSkipped();
37
- $this->rollSpare();
66
+ $this->game->roll(6);
67
+ $this->game->roll(4);
38
68
  $this->game->roll(3);
39
69
  $this->rollMany(17, 0);
40
70
 
41
71
  $this->assertEquals(16, $this->game->score());
42
72
  }
43
73
 
44
- public function testOneStrike()
74
+ public function testConsecutiveSparesEachGetAOneRollBonus()
45
75
  {
46
76
  $this->markTestSkipped();
47
- $this->rollStrike();
77
+ $this->game->roll(5);
78
+ $this->game->roll(5);
48
79
  $this->game->roll(3);
80
+ $this->game->roll(7);
49
81
  $this->game->roll(4);
82
+ $this->rollMany(15, 0);
83
+
84
+ $this->assertEquals(31, $this->game->score());
85
+ }
86
+
87
+ public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce()
88
+ {
89
+ $this->markTestSkipped();
90
+ $this->rollMany(18, 0);
91
+ $this->game->roll(7);
92
+ $this->game->roll(3);
93
+ $this->game->roll(7);
94
+
95
+ $this->assertEquals(17, $this->game->score());
96
+ }
97
+
98
+ public function testAStrikeEarnsTenPointsInFrameWithASingleRoll()
99
+ {
100
+ $this->markTestSkipped();
101
+ $this->game->roll(10);
102
+ $this->rollMany(18, 0);
103
+
104
+ $this->assertEquals(10, $this->game->score());
105
+ }
106
+
107
+ public function testPointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus()
108
+ {
109
+ $this->markTestSkipped();
110
+ $this->game->roll(10);
111
+ $this->game->roll(5);
112
+ $this->game->roll(3);
50
113
  $this->rollMany(16, 0);
51
114
 
52
- $this->assertEquals(24, $this->game->score());
115
+ $this->assertEquals(26, $this->game->score());
116
+ }
117
+
118
+ public function testConsecutiveStrikesEachGetTheTwoRollBonus()
119
+ {
120
+ $this->markTestSkipped();
121
+ $this->game->roll(10);
122
+ $this->game->roll(10);
123
+ $this->game->roll(10);
124
+ $this->game->roll(5);
125
+ $this->game->roll(3);
126
+ $this->rollMany(12, 0);
127
+
128
+ $this->assertEquals(81, $this->game->score());
129
+ }
130
+
131
+ public function testAStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce()
132
+ {
133
+ $this->markTestSkipped();
134
+ $this->rollMany(18, 0);
135
+ $this->game->roll(10);
136
+ $this->game->roll(7);
137
+ $this->game->roll(1);
138
+
139
+ $this->assertEquals(18, $this->game->score());
140
+ }
141
+
142
+ public function testRollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll()
143
+ {
144
+ $this->markTestSkipped();
145
+ $this->rollMany(18, 0);
146
+ $this->game->roll(10);
147
+ $this->game->roll(10);
148
+ $this->game->roll(10);
149
+
150
+ $this->assertEquals(30, $this->game->score());
151
+ }
152
+
153
+ public function testAStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGetABonus()
154
+ {
155
+ $this->markTestSkipped();
156
+ $this->rollMany(18, 0);
157
+ $this->game->roll(7);
158
+ $this->game->roll(3);
159
+ $this->game->roll(10);
160
+
161
+ $this->assertEquals(20, $this->game->score());
162
+ }
163
+
164
+ public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls()
165
+ {
166
+ $this->markTestSkipped();
167
+ $this->rollMany(18, 0);
168
+ $this->game->roll(10);
169
+ $this->game->roll(7);
170
+ $this->game->roll(3);
171
+
172
+ $this->assertEquals(20, $this->game->score());
53
173
  }
54
174
 
55
- public function testPerfectGame()
175
+ public function testAllStrikesIsAPerfectGame()
56
176
  {
57
177
  $this->markTestSkipped();
58
178
  $this->rollMany(12, 10);
@@ -60,6 +180,109 @@ class GameTest extends \PHPUnit_Framework_TestCase
60
180
  $this->assertEquals(300, $this->game->score());
61
181
  }
62
182
 
183
+ public function testRollsCanNotScoreNegativePoints()
184
+ {
185
+ $this->markTestSkipped();
186
+ $this->expectException(Exception::class);
187
+
188
+ $this->game->roll(-1);
189
+ }
190
+
191
+ public function testARollCanNotScoreMoreThan10Points()
192
+ {
193
+ $this->markTestSkipped();
194
+ $this->expectException(Exception::class);
195
+ $this->game->roll(11);
196
+ $this->rollMany(19, 0);
197
+
198
+ $this->game->score();
199
+ }
200
+
201
+ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points()
202
+ {
203
+ $this->markTestSkipped();
204
+
205
+ $this->expectException(Exception::class);
206
+ $this->game->roll(5);
207
+ $this->game->roll(6);
208
+ $this->rollMany(18, 0);
209
+
210
+ $this->game->score();
211
+ }
212
+
213
+ public function testTwoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points()
214
+ {
215
+ $this->markTestSkipped();
216
+ $this->expectException(Exception::class);
217
+
218
+ $this->rollMany(18, 0);
219
+ $this->game->roll(10);
220
+ $this->game->roll(5);
221
+ $this->game->roll(6);
222
+
223
+ $this->game->score();
224
+ }
225
+
226
+ public function testAnUnstartedGameCanNotBeScored()
227
+ {
228
+ $this->markTestSkipped();
229
+
230
+ $this->expectException(Exception::class);
231
+
232
+ $this->game->score();
233
+ }
234
+
235
+ public function testAnIncompleteGameCanNotBeScored()
236
+ {
237
+ $this->markTestSkipped();
238
+ $this->expectException(Exception::class);
239
+ $this->game->roll(0);
240
+ $this->game->roll(0);
241
+
242
+ $this->game->score();
243
+ }
244
+
245
+ public function testAGameWithMoreThanTenFramesCanNotBeScored()
246
+ {
247
+ $this->markTestSkipped();
248
+ $this->expectException(Exception::class);
249
+ $this->rollMany(21, 0);
250
+
251
+ $this->game->score();
252
+ }
253
+
254
+ public function testBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated()
255
+ {
256
+ $this->markTestSkipped();
257
+ $this->expectException(Exception::class);
258
+ $this->rollMany(18, 0);
259
+ $this->game->roll(10);
260
+
261
+ $this->game->score();
262
+ }
263
+
264
+ public function testBothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated()
265
+ {
266
+ $this->markTestSkipped();
267
+ $this->expectException(Exception::class);
268
+ $this->rollMany(18, 0);
269
+ $this->game->roll(10);
270
+ $this->game->roll(10);
271
+
272
+ $this->game->score();
273
+ }
274
+
275
+ public function testBonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated()
276
+ {
277
+ $this->markTestSkipped();
278
+ $this->expectException(Exception::class);
279
+ $this->rollMany(18, 0);
280
+ $this->game->roll(7);
281
+ $this->game->roll(3);
282
+
283
+ $this->game->score();
284
+ }
285
+
63
286
  private function rollStrike()
64
287
  {
65
288
  $this->game->roll(10);
@@ -6,19 +6,22 @@
6
6
  */
7
7
  class Game
8
8
  {
9
- private $rolls = array();
10
- private $currentRoll = 0;
9
+ private $rolls = [];
11
10
 
12
11
  public function roll($pins)
13
12
  {
14
- $this->rolls[$this->currentRoll++] = $pins;
13
+ if ($pins < 0 || $pins > 10) {
14
+ throw new Exception('Pins must be between 0 and 10');
15
+ }
16
+ $this->rolls[] = $pins;
15
17
  }
16
18
 
17
19
  public function score()
18
20
  {
19
21
  $score = 0;
20
22
  $frameIndex = 0;
21
- for ($frame = 0; $frame < 10; $frame++) {
23
+ foreach (range(1, 10) as $frame) {
24
+ $this->guardAgainstIncompleteGame($frameIndex);
22
25
  if ($this->isStrike($frameIndex)) {
23
26
  $score += 10 + $this->strikeBonus($frameIndex);
24
27
  $frameIndex++;
@@ -30,6 +33,7 @@ class Game
30
33
  $frameIndex += 2;
31
34
  }
32
35
  }
36
+ $this->guardAgainstTooManyFrames($frameIndex);
33
37
 
34
38
  return $score;
35
39
  }
@@ -41,7 +45,16 @@ class Game
41
45
 
42
46
  private function strikeBonus($frameIndex)
43
47
  {
44
- return $this->rolls[$frameIndex + 1] + $this->rolls[$frameIndex + 2];
48
+ if (!isset($this->rolls[$frameIndex + 1]) || !isset($this->rolls[$frameIndex + 2])) {
49
+ throw new Exception('Incomplete game');
50
+ }
51
+ $bonus1 = $this->rolls[$frameIndex + 1];
52
+ $bonus2 = $this->rolls[$frameIndex + 2];
53
+ $sum = $bonus1 + $bonus2;
54
+ if ($sum > 10 && $frameIndex = 10 && $bonus1 != 10) {
55
+ throw new Exception('Cannot score more than 10');
56
+ }
57
+ return $sum;
45
58
  }
46
59
 
47
60
  private function isSpare($frameIndex)
@@ -51,11 +64,41 @@ class Game
51
64
 
52
65
  private function spareBonus($frameIndex)
53
66
  {
67
+ if (!isset($this->rolls[$frameIndex + 2])) {
68
+ throw new Exception('Incomplete game');
69
+ }
54
70
  return $this->rolls[$frameIndex + 2];
55
71
  }
56
72
 
57
73
  private function sumOfBallsInFrame($frameIndex)
58
74
  {
59
- return $this->rolls[$frameIndex] + $this->rolls[$frameIndex + 1];
75
+ $sum = $this->rolls[$frameIndex] + $this->rolls[$frameIndex + 1];
76
+ if ($sum > 10) {
77
+ throw new Exception('Cannot score more than ten in single frame');
78
+ }
79
+ return $sum;
80
+ }
81
+
82
+ private function guardAgainstIncompleteGame($frameIndex)
83
+ {
84
+ if (!isset($this->rolls[$frameIndex])) {
85
+ throw new Exception('Incomplete game');
86
+ }
87
+ }
88
+
89
+ private function guardAgainstTooManyFrames($frameIndex)
90
+ {
91
+ $rollsCount = count($this->rolls);
92
+ if ($this->isStrike($frameIndex - 1)) {
93
+ if ($rollsCount > $frameIndex + 2) {
94
+ throw new Exception('Too many frames in game');
95
+ }
96
+ } elseif ($this->isSpare($frameIndex - 2)) {
97
+ if ($rollsCount > $frameIndex + 1) {
98
+ throw new Exception('Too many frames in game');
99
+ }
100
+ } elseif ($rollsCount > $frameIndex) {
101
+ throw new Exception('Too many frames in game');
102
+ }
60
103
  }
61
104
  }
@@ -7,6 +7,11 @@ python:
7
7
  - 3.3
8
8
  - 3.4
9
9
  - 3.5
10
+ - nightly
11
+
12
+ matrix:
13
+ allow_failures:
14
+ - python: nightly
10
15
 
11
16
  install:
12
17
  - pip install -r requirements-travis.txt
@@ -28,6 +28,7 @@
28
28
  "largest-series-product",
29
29
  "kindergarten-garden",
30
30
  "grade-school",
31
+ "flatten-array",
31
32
  "roman-numerals",
32
33
  "space-age",
33
34
  "grains",
@@ -100,24 +101,49 @@
100
101
  "slug": "pangram",
101
102
  "difficulty": 1,
102
103
  "topics": [
104
+ "control-flow (loops)",
105
+ "control-flow (if-else statements)",
106
+ "strings",
107
+ "algorithms",
108
+ "filtering",
109
+ "logic"
103
110
  ]
104
111
  },
105
112
  {
106
113
  "slug": "rna-transcription",
107
114
  "difficulty": 1,
108
115
  "topics": [
116
+ "control-flow (if-else statements)",
117
+ "control-flow (loops)",
118
+ "maps",
119
+ "strings",
120
+ "logic",
121
+ "transforming"
109
122
  ]
110
123
  },
111
124
  {
112
125
  "slug": "hamming",
113
126
  "difficulty": 1,
114
127
  "topics": [
128
+ "control-flow (if-else statements)",
129
+ "control-flow (loops)",
130
+ "sequences",
131
+ "sets",
132
+ "strings",
133
+ "algorithms",
134
+ "filtering",
135
+ "logic"
115
136
  ]
116
137
  },
117
138
  {
118
139
  "slug": "word-count",
119
- "difficulty": 1,
140
+ "difficulty": 3,
120
141
  "topics": [
142
+ "strings",
143
+ "algorithms",
144
+ "logic",
145
+ "pattern recognition",
146
+ "text formatting"
121
147
  ]
122
148
  },
123
149
  {
@@ -222,6 +248,12 @@
222
248
  "topics": [
223
249
  ]
224
250
  },
251
+ {
252
+ "slug": "flatten-array",
253
+ "difficulty": 1,
254
+ "topics": [
255
+ ]
256
+ },
225
257
  {
226
258
  "slug": "roman-numerals",
227
259
  "difficulty": 1,