trackler 2.0.8.10 → 2.0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9dceda62cf5804961190a45bdb1674e22beb903a
4
- data.tar.gz: 1591edf17af892e711aecb9d1b2cabc1b472a5cc
3
+ metadata.gz: 7985975e695c967206c6399587638d7b92f6ddeb
4
+ data.tar.gz: f605cb15bcc556c8f153ebf0aa71768b773709c5
5
5
  SHA512:
6
- metadata.gz: abe7d5a9af5ae04d307b468618acb433fda74fb9266d8df78a6ca015cdcec513b95f47e39d584c8228f4785607b60bf4defcc3a08fa1569f9ffc069883a82a8f
7
- data.tar.gz: 9294b813acecd5b4831e7585e3d7ce271b13da1cf49259b79a9ff188505c01820c2f8dea5c28ce0705ffa7a6d6df657a0012485bbd7841d453e4f400393b9789
6
+ metadata.gz: 3f6cd5026c972237c9495b8acd567fa1ac65fc949bcf2da45c797526fe5057cea00c78bd433f840c8003da55f729e675c184a65d4d6510aa589f31288b22350f
7
+ data.tar.gz: 8687e2946dec0948f8a7800850103074d894c24aba6d92a530ea452672788f7014abf9a3e5d03fcffb619a5e1cbd845f51784451eaad4444a0493c7240a40ba9
@@ -27,4 +27,4 @@ The largest product is `9`. It's factors are `(1, 9)`, `(3, 3)`, and `(9, 1)`.
27
27
  Given the range `[10, 99]` (both inclusive)...
28
28
 
29
29
  The smallest palindrome product is `121`. It's factors are `(11, 11)`.
30
- The largest palindrome product is `9009`. It's factors are `(93, 99)` and `(99, 91)`.
30
+ The largest palindrome product is `9009`. It's factors are `(91, 99)` and `(99, 91)`.
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.8.10"
2
+ VERSION = "2.0.8.11"
3
3
  end
@@ -1,7 +1,6 @@
1
1
  unit uBowling;
2
2
 
3
3
  interface
4
- uses System.Generics.Collections;
5
4
 
6
5
  type
7
6
  IBowlingGame = interface(IInvokable)
@@ -13,18 +12,22 @@ type
13
12
  function NewBowlingGame: IBowlingGame;
14
13
 
15
14
  implementation
15
+ uses System.SysUtils, System.Math, System.Generics.Collections;
16
16
 
17
17
  type
18
18
  TBowlingGame = class(TInterfacedObject, IBowlingGame)
19
19
  private
20
- fRolls: TList<integer>;
21
- fNumberOfFrames: integer;
22
- fMaximumFrameScore: integer;
20
+ var
21
+ fRolls: TList<integer>;
22
+ const
23
+ fNumberOfFrames = 10;
24
+ fMaximumFrameScore = 10;
23
25
  function IsStrike(aFrameIndex: integer): Boolean;
24
26
  function IsSpare(aFrameIndex: integer): Boolean;
25
27
  function StrikeBonus(aFrameIndex: integer): integer;
26
28
  function SpareBonus(aFrameIndex: integer): integer;
27
29
  function SumOfPinsInFrame(aFrameIndex: integer): integer;
30
+ function CorrectNumberOfRolls(aFrameIndex: integer): boolean;
28
31
  public
29
32
  constructor create;
30
33
  function Score: integer;
@@ -38,8 +41,6 @@ end;
38
41
 
39
42
  constructor TBowlingGame.create;
40
43
  begin
41
- fNumberOfFrames := 10;
42
- fMaximumFrameScore := 10;
43
44
  fRolls := TList<integer>.Create;
44
45
  end;
45
46
 
@@ -52,29 +53,52 @@ function TBowlingGame.Score: integer;
52
53
  var lFrameIndex: integer;
53
54
  i: integer;
54
55
  lScore: integer;
56
+ lStrikeBonus: integer;
57
+ lFrameScore: integer;
55
58
  begin
56
59
  lScore := 0;
57
60
  lFrameIndex := 0;
58
- for i := 0 to fNumberOfFrames - 1 do
59
- begin
60
- if IsStrike(lFrameIndex) then
61
+ try
62
+ for i := 1 to fNumberOfFrames do
61
63
  begin
62
- lScore := lScore + 10 + StrikeBonus(lFrameIndex);
63
- inc(lFrameIndex);
64
- end
65
- else
66
- if IsSpare(lFrameIndex) then
67
- begin
68
- lScore := lScore + 10 + SpareBonus(lFrameIndex);
69
- inc(lFrameIndex, 2);
70
- end
71
- else
72
- begin
73
- lScore := lScore + SumOfPinsInFrame(lFrameIndex);
74
- inc(lFrameIndex, 2);
64
+ if fRolls.Count <= lFrameIndex then
65
+ raise EArgumentException.Create('Not a proper game');
66
+
67
+ if IsStrike(lFrameIndex) then
68
+ begin
69
+ if (fRolls.Count <= lFrameIndex + 2) then
70
+ raise EArgumentException.Create('Not a proper game');
71
+
72
+ lStrikeBonus := StrikeBonus(lFrameIndex);
73
+ if (lStrikeBonus > fMaximumFrameScore) and not IsStrike(lFrameIndex + 1) then
74
+ raise EArgumentException.Create('Not a proper game');
75
+
76
+ lScore := lScore + 10 + lStrikeBonus;
77
+ inc(lFrameIndex, ifthen(i = fNumberOfFrames, 3, 1));
78
+ end
79
+ else
80
+ if IsSpare(lFrameIndex) then
81
+ begin
82
+ if (fRolls.Count <= lFrameIndex + 2) then
83
+ raise EArgumentException.Create('Not a proper game');
84
+
85
+ lScore := lScore + 10 + SpareBonus(lFrameIndex);
86
+ inc(lFrameIndex, ifthen(i = fNumberOfFrames, 3, 2));
87
+ end
88
+ else
89
+ begin
90
+ lFrameScore := SumOfPinsInFrame(lFrameIndex);
91
+ if (lFrameScore < 0) or (lFrameScore > 10) then
92
+ raise EArgumentException.Create('Not a proper game');
93
+
94
+ lScore := lScore + lFrameScore;
95
+ inc(lFrameIndex, 2);
96
+ end;
75
97
  end;
98
+ result := ifthen(CorrectNumberOfRolls(lFrameIndex), lScore, -1);
99
+ except
100
+ result := -1;
76
101
  end;
77
- result := lScore;
78
102
  end;
79
103
 
80
104
  function TBowlingGame.IsStrike(aFrameIndex: Integer): Boolean;
@@ -102,4 +126,9 @@ begin
102
126
  result := fRolls[aFrameIndex] + fRolls[aFrameIndex + 1];
103
127
  end;
104
128
 
129
+ function TBowlingGame.CorrectNumberOfRolls(aFrameIndex: Integer): boolean;
130
+ begin
131
+ result := aFrameIndex = fRolls.Count;
132
+ end;
133
+
105
134
  end.
@@ -10,90 +10,281 @@ type
10
10
  [TestFixture]
11
11
  BowlingTests = class(TObject)
12
12
  private
13
- class procedure RollMany(pins: integer; count: integer; game: IBowlingGame); static;
14
- class procedure RollSpare(game: IBowlingGame); static;
15
- class procedure RollStrike(game: IBowlingGame); static;
13
+ class function RollMany(pins: array of integer; game: IBowlingGame): IBowlingGame; static;
16
14
  public
17
15
  [Test]
18
- [Ignore]
19
- procedure Gutter_game;
16
+ procedure Should_be_able_to_score_a_game_with_all_zeros;
17
+
18
+ [Test]
19
+ [Ignore('Comment this line to run this test')]
20
+ procedure Should_be_able_to_score_a_game_with_no_strikes_or_spares;
21
+
22
+ [Test]
23
+ [Ignore('Comment this line to run this test')]
24
+ procedure A_spare_followed_by_zeros_is_worth_ten_points;
25
+
26
+ [Test]
27
+ [Ignore('Comment this line to run this test')]
28
+ procedure Points_scored_in_the_roll_after_a_spare_are_counted_twice;
29
+
30
+ [Test]
31
+ [Ignore('Comment this line to run this test')]
32
+ procedure Consecutive_spares_each_get_a_one_roll_bonus;
33
+
34
+ [Test]
35
+ [Ignore('Comment this line to run this test')]
36
+ procedure A_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once;
37
+
38
+ [Test]
39
+ [Ignore('Comment this line to run this test')]
40
+ procedure A_strike_earns_ten_points_in_frame_with_a_single_roll;
41
+
42
+ [Test]
43
+ [Ignore('Comment this line to run this test')]
44
+ procedure Points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus;
45
+
46
+ [Test]
47
+ [Ignore('Comment this line to run this test')]
48
+ procedure Consecutive_strikes_each_get_the_two_roll_bonus;
49
+
50
+ [Test]
51
+ [Ignore('Comment this line to run this test')]
52
+ procedure A_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once;
53
+
54
+ [Test]
55
+ [Ignore('Comment this line to run this test')]
56
+ procedure Rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll;
57
+
58
+ [Test]
59
+ [Ignore('Comment this line to run this test')]
60
+ procedure Strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls;
61
+
62
+ [Test]
63
+ [Ignore('Comment this line to run this test')]
64
+ procedure A_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus;
65
+
66
+ [Test]
67
+ [Ignore('Comment this line to run this test')]
68
+ procedure All_strikes_is_a_perfect_game;
69
+
70
+ [Test]
71
+ [Ignore('Comment this line to run this test')]
72
+ procedure Rolls_can_not_score_negative_points;
73
+
74
+ [Test]
75
+ [Ignore('Comment this line to run this test')]
76
+ procedure A_roll_can_not_score_more_than_10_points;
77
+
78
+ [Test]
79
+ [Ignore('Comment this line to run this test')]
80
+ procedure Two_rolls_in_a_frame_can_not_score_more_than_10_points;
81
+
82
+ [Test]
83
+ [Ignore('Comment this line to run this test')]
84
+ procedure Two_bonus_rolls_after_a_strike_in_the_last_frame_can_not_score_more_than_10_points;
85
+
20
86
  [Test]
21
- [Ignore]
22
- procedure All_ones_game;
87
+ [Ignore('Comment this line to run this test')]
88
+ procedure An_unstarted_game_can_not_be_scored;
89
+
90
+ [Test]
91
+ [Ignore('Comment this line to run this test')]
92
+ procedure An_incomplete_game_can_not_be_scored;
93
+
23
94
  [Test]
24
- [Ignore]
25
- procedure One_spare_game;
95
+ [Ignore('Comment this line to run this test')]
96
+ procedure A_game_with_more_than_ten_frames_can_not_be_scored;
97
+
26
98
  [Test]
27
- [Ignore]
28
- procedure One_strike_game;
99
+ [Ignore('Comment this line to run this test')]
100
+ procedure Bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
101
+
102
+ [Test]
103
+ [Ignore('Comment this line to run this test')]
104
+ procedure Both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
105
+
29
106
  [Test]
30
- [Ignore]
31
- procedure Perfect_game;
107
+ [Ignore('Comment this line to run this test')]
108
+ procedure Bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
32
109
  end;
33
110
 
34
111
  implementation
112
+ uses System.SysUtils;
35
113
 
36
- procedure BowlingTests.Gutter_game;
114
+ procedure BowlingTests.Should_be_able_to_score_a_game_with_all_zeros;
37
115
  var game: IBowlingGame;
38
116
  begin
39
- game := NewBowlingGame;
40
- RollMany(0,20,game);
41
- assert.AreEqual(0,game.Score);
117
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
118
+ assert.AreEqual(0, game.Score);
42
119
  end;
43
120
 
44
- procedure BowlingTests.All_ones_game;
121
+ procedure BowlingTests.Should_be_able_to_score_a_game_with_no_strikes_or_spares;
45
122
  var game: IBowlingGame;
46
123
  begin
47
- game := NewBowlingGame;
48
- RollMany(1, 20, game);
49
- assert.AreEqual(20,game.Score);
124
+ game := RollMany([3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6], NewBowlingGame);
125
+ assert.AreEqual(90, game.Score);
50
126
  end;
51
127
 
52
- procedure BowlingTests.One_spare_game;
128
+ procedure BowlingTests.A_spare_followed_by_zeros_is_worth_ten_points;
53
129
  var game: IBowlingGame;
54
130
  begin
55
- game := NewBowlingGame;
56
- RollSpare(game);
57
- game.Roll(3);
58
- RollMany(0, 17, game);
131
+ game := RollMany([6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
132
+ assert.AreEqual(10, game.Score);
133
+ end;
134
+
135
+ procedure BowlingTests.Points_scored_in_the_roll_after_a_spare_are_counted_twice;
136
+ var game: IBowlingGame;
137
+ begin
138
+ game := RollMany([6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
59
139
  assert.AreEqual(16, game.Score);
60
140
  end;
61
141
 
62
- procedure BowlingTests.One_strike_game;
142
+ procedure BowlingTests.Consecutive_spares_each_get_a_one_roll_bonus;
143
+ var game: IBowlingGame;
144
+ begin
145
+ game := RollMany([5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
146
+ assert.AreEqual(31, game.Score);
147
+ end;
148
+
149
+ procedure BowlingTests.A_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once;
150
+ var game: IBowlingGame;
151
+ begin
152
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7], NewBowlingGame);
153
+ assert.AreEqual(17, game.Score);
154
+ end;
155
+
156
+ procedure BowlingTests.A_strike_earns_ten_points_in_frame_with_a_single_roll;
157
+ var game: IBowlingGame;
158
+ begin
159
+ game := RollMany([10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
160
+ assert.AreEqual(10, game.Score);
161
+ end;
162
+
163
+ procedure BowlingTests.Points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus;
164
+ var game: IBowlingGame;
165
+ begin
166
+ game := RollMany([10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
167
+ assert.AreEqual(26, game.Score);
168
+ end;
169
+
170
+ procedure BowlingTests.Consecutive_strikes_each_get_the_two_roll_bonus;
171
+ var game: IBowlingGame;
172
+ begin
173
+ game := RollMany([10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
174
+ assert.AreEqual(81, game.Score);
175
+ end;
176
+
177
+ procedure BowlingTests.A_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once;
178
+ var game: IBowlingGame;
179
+ begin
180
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1], NewBowlingGame);
181
+ assert.AreEqual(18, game.Score);
182
+ end;
183
+
184
+ procedure BowlingTests.Rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll;
185
+ var game: IBowlingGame;
186
+ begin
187
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3], NewBowlingGame);
188
+ assert.AreEqual(20, game.Score);
189
+ end;
190
+
191
+ procedure BowlingTests.Strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls;
192
+ var game: IBowlingGame;
193
+ begin
194
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10], NewBowlingGame);
195
+ assert.AreEqual(30, game.Score);
196
+ end;
197
+
198
+ procedure BowlingTests.A_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus;
199
+ var game: IBowlingGame;
200
+ begin
201
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10], NewBowlingGame);
202
+ assert.AreEqual(20, game.Score);
203
+ end;
204
+
205
+ procedure BowlingTests.All_strikes_is_a_perfect_game;
206
+ var game: IBowlingGame;
207
+ begin
208
+ game := RollMany([10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], NewBowlingGame);
209
+ assert.AreEqual(300, game.Score);
210
+ end;
211
+
212
+ procedure BowlingTests.Rolls_can_not_score_negative_points;
213
+ var game: IBowlingGame;
214
+ begin
215
+ game := RollMany([-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
216
+ Assert.AreEqual(-1, game.Score);
217
+ end;
218
+
219
+ procedure BowlingTests.A_roll_can_not_score_more_than_10_points;
220
+ var game: IBowlingGame;
221
+ begin
222
+ game := RollMany([11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
223
+ Assert.AreEqual(-1, game.Score);
224
+ end;
225
+
226
+ procedure BowlingTests.Two_rolls_in_a_frame_can_not_score_more_than_10_points;
227
+ var game: IBowlingGame;
228
+ begin
229
+ game := RollMany([5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
230
+ Assert.AreEqual(-1, game.Score);
231
+ end;
232
+
233
+ procedure BowlingTests.Two_bonus_rolls_after_a_strike_in_the_last_frame_can_not_score_more_than_10_points;
63
234
  var game: IBowlingGame;
64
235
  begin
65
- game := NewBowlingGame;
66
- RollStrike(game);
67
- game.Roll(3);
68
- game.Roll(4);
69
- RollMany(0, 16, game);
70
- assert.AreEqual(24, game.Score);
236
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6], NewBowlingGame);
237
+ Assert.AreEqual(-1, game.Score);
71
238
  end;
72
239
 
73
- procedure BowlingTests.Perfect_game;
240
+ procedure BowlingTests.An_unstarted_game_can_not_be_scored;
74
241
  var game: IBowlingGame;
75
242
  begin
76
- game := NewBowlingGame;
77
- RollMany(10, 12, game);
78
- assert.AreEqual(300, Game.Score);
243
+ game := RollMany([],NewBowlingGame);
244
+ Assert.AreEqual(-1, game.Score);
79
245
  end;
80
246
 
81
- class procedure BowlingTests.RollMany(pins: integer; count: integer; game: IBowlingGame);
82
- var i: integer;
247
+ procedure BowlingTests.An_incomplete_game_can_not_be_scored;
248
+ var game: IBowlingGame;
249
+ begin
250
+ game := RollMany([0, 0], NewBowlingGame);
251
+ Assert.AreEqual(-1, game.Score);
252
+ end;
253
+
254
+ procedure BowlingTests.A_game_with_more_than_ten_frames_can_not_be_scored;
255
+ var game: IBowlingGame;
256
+ begin
257
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], NewBowlingGame);
258
+ Assert.AreEqual(-1, game.Score);
259
+ end;
260
+
261
+ procedure BowlingTests.Bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
262
+ var game: IBowlingGame;
83
263
  begin
84
- for i := 0 to count - 1 do
85
- game.Roll(pins);
264
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10], NewBowlingGame);
265
+ Assert.AreEqual(-1, game.Score);
86
266
  end;
87
267
 
88
- class procedure BowlingTests.RollSpare(game: IBowlingGame);
268
+ procedure BowlingTests.Both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
269
+ var game: IBowlingGame;
270
+ begin
271
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10], NewBowlingGame);
272
+ Assert.AreEqual(-1, game.Score);
273
+ end;
274
+
275
+ procedure BowlingTests.Bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated;
276
+ var game: IBowlingGame;
89
277
  begin
90
- game.Roll(5);
91
- game.Roll(5);
278
+ game := RollMany([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3], NewBowlingGame);
279
+ Assert.AreEqual(-1, game.Score);
92
280
  end;
93
281
 
94
- class procedure BowlingTests.RollStrike(game: IBowlingGame);
282
+ class function BowlingTests.RollMany(pins: array of integer; game: IBowlingGame): IBowlingGame;
283
+ var count: integer;
95
284
  begin
96
- game.Roll(10);
285
+ for count in pins do
286
+ game.Roll(count);
287
+ result := game;
97
288
  end;
98
289
 
99
290
  initialization
@@ -10,25 +10,25 @@ import (
10
10
 
11
11
  type operatorFn func(stack *[]int) error
12
12
 
13
- type operatorId byte
13
+ type operatorID byte
14
14
 
15
15
  const (
16
- addOp operatorId = iota
17
- subOp
18
- mulOp
19
- divOp
20
- dropOp
21
- dupOp
22
- swapOp
23
- overOp
24
- constOp
25
- userDefOp
26
- endDefOp
16
+ opAdd operatorID = iota
17
+ opSub
18
+ opMul
19
+ opDiv
20
+ opDrop
21
+ opDup
22
+ opSwap
23
+ opOver
24
+ opConst
25
+ opUserDef
26
+ opEndDef
27
27
  )
28
28
 
29
29
  type operatorTyp struct {
30
30
  fn operatorFn
31
- id operatorId
31
+ id operatorID
32
32
  }
33
33
 
34
34
  func Forth(input []string) (result []int, err error) {
@@ -73,15 +73,15 @@ func parse(phrase string, userDefs map[string][]operatorTyp) (oplist []operatorT
73
73
  if udef, ok := userDefs[w]; ok {
74
74
  oplist = append(oplist, udef...)
75
75
  } else if op, ok := builtinOps[w]; ok {
76
- if op.id == userDefOp {
76
+ if op.id == opUserDef {
77
77
  // Handle user defined word definition.
78
78
  t++
79
79
  if t >= len(words)-2 {
80
- return nil, emptyUserDefErr
80
+ return nil, errEmptyUserDef
81
81
  }
82
82
  userword := strings.ToUpper(words[t])
83
83
  if _, numerr := strconv.Atoi(userword); numerr == nil {
84
- return nil, invalidUserDefErr
84
+ return nil, errInvalidUserDef
85
85
  }
86
86
  t++
87
87
  var userops []operatorTyp
@@ -90,17 +90,16 @@ func parse(phrase string, userDefs map[string][]operatorTyp) (oplist []operatorT
90
90
  if err != nil {
91
91
  return nil, err
92
92
  }
93
- if oneOp[0].id == endDefOp {
93
+ if oneOp[0].id == opEndDef {
94
94
  break
95
95
  }
96
96
  userops = append(userops, oneOp...)
97
97
  t++
98
98
  }
99
99
  if len(userops) == 0 {
100
- return nil, emptyUserDefErr
101
- } else {
102
- userDefs[userword] = userops
100
+ return nil, errEmptyUserDef
103
101
  }
102
+ userDefs[userword] = userops
104
103
  } else {
105
104
  // Normal builtin operator.
106
105
  oplist = append(oplist, op)
@@ -113,7 +112,7 @@ func parse(phrase string, userDefs map[string][]operatorTyp) (oplist []operatorT
113
112
  return nil, err
114
113
  }
115
114
  oplist = append(oplist,
116
- operatorTyp{id: constOp,
115
+ operatorTyp{id: opConst,
117
116
  fn: func(stack *[]int) error {
118
117
  push(stack, x)
119
118
  return nil
@@ -126,16 +125,16 @@ func parse(phrase string, userDefs map[string][]operatorTyp) (oplist []operatorT
126
125
 
127
126
  // builtinOps are the pre-defined operators to support.
128
127
  var builtinOps = map[string]operatorTyp{
129
- "+": {add, addOp},
130
- "-": {subtract, subOp},
131
- "*": {multiply, mulOp},
132
- "/": {divide, divOp},
133
- "DUP": {dup, dropOp},
134
- "DROP": {drop, dupOp},
135
- "SWAP": {swap, swapOp},
136
- "OVER": {over, overOp},
137
- ":": {nil, userDefOp},
138
- ";": {nil, endDefOp},
128
+ "+": {add, opAdd},
129
+ "-": {subtract, opSub},
130
+ "*": {multiply, opMul},
131
+ "/": {divide, opDiv},
132
+ "DUP": {dup, opDrop},
133
+ "DROP": {drop, opDup},
134
+ "SWAP": {swap, opSwap},
135
+ "OVER": {over, opOver},
136
+ ":": {nil, opUserDef},
137
+ ";": {nil, opEndDef},
139
138
  }
140
139
 
141
140
  func pop(stack *[]int) (v int, err error) {
@@ -145,7 +144,7 @@ func pop(stack *[]int) (v int, err error) {
145
144
  *stack = (*stack)[:slen-1]
146
145
  return v, nil
147
146
  }
148
- return 0, notEnoughOperands
147
+ return 0, errNotEnoughOperands
149
148
  }
150
149
 
151
150
  func pop2(stack *[]int) (v1, v2 int, err error) {
@@ -188,7 +187,7 @@ func divide(stack *[]int) error {
188
187
  return err
189
188
  }
190
189
  if v1 == 0 {
191
- return divideByZero
190
+ return errDivideByZero
192
191
  }
193
192
  push(stack, v2/v1)
194
193
  return nil
@@ -230,9 +229,9 @@ func swap(stack *[]int) error {
230
229
  return nil
231
230
  }
232
231
 
233
- var notEnoughOperands error = errors.New("not enough operands")
234
- var divideByZero error = errors.New("attempt to divide by zero")
235
- var emptyUserDefErr error = errors.New("empty user definition")
236
- var invalidUserDefErr error = errors.New("invalid user def word")
232
+ var errNotEnoughOperands = errors.New("not enough operands")
233
+ var errDivideByZero = errors.New("attempt to divide by zero")
234
+ var errEmptyUserDef = errors.New("empty user definition")
235
+ var errInvalidUserDef = errors.New("invalid user def word")
237
236
 
238
237
  const testVersion = 1
@@ -140,7 +140,7 @@ func TestGarden(t *testing.T) {
140
140
  t.Fatalf("Garden %d lookup %s returned ok = %t, want %t.",
141
141
  test.number, l.child, ok, l.ok)
142
142
  case ok && !reflect.DeepEqual(plants, l.plants):
143
- t.Fatalf("Garden %d lookup %s = %v, want %v.",
143
+ t.Fatalf("Garden %d lookup %s = %q, want %q.",
144
144
  test.number, l.child, plants, l.plants)
145
145
  }
146
146
  }
@@ -192,7 +192,7 @@ RVGCCGCV`
192
192
  t.Skip("Garden %d lookup %s returned ok = false, want true.",
193
193
  n, child)
194
194
  case !reflect.DeepEqual(plants, expPlants):
195
- t.Fatalf("Garden %d lookup %s = %v, want %v.",
195
+ t.Fatalf("Garden %d lookup %s = %q, want %q.",
196
196
  n, child, plants, expPlants)
197
197
  }
198
198
  }
@@ -90,6 +90,8 @@ public class AllergiesTest {
90
90
  Allergies allergies = new Allergies(5);
91
91
 
92
92
  assertEquals(true, allergies.isAllergicTo(Allergen.EGGS));
93
+ assertEquals(true, allergies.isAllergicTo(Allergen.SHELLFISH));
94
+ assertEquals(false, allergies.isAllergicTo(Allergen.STRAWBERRIES));
93
95
  }
94
96
 
95
97
  @Ignore
@@ -264,6 +264,16 @@
264
264
  "Filtering"
265
265
  ]
266
266
  },
267
+ {
268
+ "slug":"simple-linked-list",
269
+ "difficulty":1,
270
+ "topics":[
271
+ "Classes",
272
+ "Lists",
273
+ "Transforming",
274
+ "Generics"
275
+ ]
276
+ },
267
277
  {
268
278
  "slug":"atbash-cipher",
269
279
  "difficulty":1,
@@ -0,0 +1,3 @@
1
+ scalaVersion := "2.12.1"
2
+
3
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
@@ -0,0 +1,95 @@
1
+ class Node[+T]
2
+ case object Empty extends Node[Nothing]
3
+ case class NonEmpty[T](value: T, next: Node[T]) extends Node[T]
4
+
5
+ trait SimpleLinkedList[T] {
6
+ def isEmpty: Boolean
7
+ def value: T
8
+ def add(item: T): SimpleLinkedList[T]
9
+ def next: SimpleLinkedList[T]
10
+ def reverse: SimpleLinkedList[T]
11
+ def toSeq: Seq[T]
12
+ }
13
+
14
+ class SimpleLinkedListImpl[T](first: Node[T]) extends SimpleLinkedList[T] {
15
+
16
+ def isEmpty: Boolean = first == Empty
17
+
18
+ def value: T = first match {
19
+ case Empty => throw new NoSuchElementException
20
+ case node: NonEmpty[T] => node.value
21
+ }
22
+
23
+ def add(item: T): SimpleLinkedList[T] = {
24
+ var reversed = reverse
25
+ var current = NonEmpty[T](item, Empty)
26
+
27
+ while (!reversed.isEmpty) {
28
+ val value = reversed.value
29
+ val newNode = NonEmpty[T](value, current)
30
+
31
+ current = newNode
32
+ reversed = reversed.next
33
+ }
34
+
35
+ new SimpleLinkedListImpl[T](current)
36
+ }
37
+
38
+ def next: SimpleLinkedList[T] = first match {
39
+ case Empty => this
40
+ case node: NonEmpty[T] => new SimpleLinkedListImpl[T](first.asInstanceOf[NonEmpty[T]].next)
41
+ }
42
+
43
+ def reverse: SimpleLinkedList[T] = {
44
+ var newLast: Node[T] = Empty
45
+ var prev: Node[T] = Empty
46
+ var current = first
47
+ var next: Node[T] = Empty
48
+ while (current != Empty) {
49
+ val newNode = NonEmpty[T](current.asInstanceOf[NonEmpty[T]].value, prev)
50
+
51
+ if (newLast == Empty) {
52
+ newLast = newNode
53
+ }
54
+
55
+ next = current.asInstanceOf[NonEmpty[T]].next
56
+ prev = newNode
57
+ current = next
58
+ }
59
+
60
+ new SimpleLinkedListImpl[T](prev)
61
+ }
62
+
63
+ def length: Int = {
64
+ var len = 0
65
+
66
+ var current = first
67
+ while (current != Empty) {
68
+ len = len + 1
69
+ current = current.asInstanceOf[NonEmpty[T]].next
70
+ }
71
+
72
+ len
73
+ }
74
+
75
+ def toSeq: Seq[T] = {
76
+ var xs = List[T]()
77
+
78
+ var current = first
79
+ while (current != Empty) {
80
+ xs = current.asInstanceOf[NonEmpty[T]].value :: xs
81
+ current = current.asInstanceOf[NonEmpty[T]].next
82
+ }
83
+
84
+ xs.reverse
85
+ }
86
+ }
87
+
88
+ object SimpleLinkedList {
89
+ def apply[T](): SimpleLinkedList[T] = new SimpleLinkedListImpl[T](Empty)
90
+
91
+ def apply[T](ts: T*): SimpleLinkedList[T] = fromSeq(ts)
92
+
93
+ def fromSeq[T](seq: Seq[T]): SimpleLinkedList[T] =
94
+ seq.foldLeft(SimpleLinkedList[T]())((acc, t) => acc.add(t))
95
+ }
@@ -0,0 +1,8 @@
1
+ trait SimpleLinkedList[T] {
2
+ def isEmpty: Boolean
3
+ def value: T
4
+ def add(item: T): SimpleLinkedList[T]
5
+ def next: SimpleLinkedList[T]
6
+ def reverse: SimpleLinkedList[T]
7
+ def toSeq: Seq[T]
8
+ }
@@ -0,0 +1,108 @@
1
+ import org.scalacheck.{Arbitrary}
2
+ import org.scalatest.prop.GeneratorDrivenPropertyChecks
3
+ import org.scalatest.{FlatSpec, Matchers}
4
+
5
+
6
+ class SimpleLinkedListTest extends FlatSpec with Matchers with GeneratorDrivenPropertyChecks {
7
+
8
+ private implicit def arbitrarySimpleLinkedList[T](implicit arbitraryTs: Arbitrary[Array[T]]): Arbitrary[SimpleLinkedList[T]] =
9
+ Arbitrary {
10
+ arbitraryTs.arbitrary map (SimpleLinkedList(_:_*))
11
+ }
12
+
13
+ it should "handle single item list" in {
14
+ val list = SimpleLinkedList().add(1)
15
+ list.isEmpty should be (false)
16
+ list.value should be (1)
17
+ }
18
+
19
+ it should "handle single item has no next item" in {
20
+ pending
21
+ val list = SimpleLinkedList().add(1)
22
+ list.next.isEmpty should be (true)
23
+ }
24
+
25
+ it should "handle two item list" in {
26
+ pending
27
+ val list = SimpleLinkedList().add(1).add(2)
28
+ list.value should be (1)
29
+ list.next.value should be (2)
30
+ }
31
+
32
+ it should "handle two item list has no next value" in {
33
+ pending
34
+ val list = SimpleLinkedList().add(1).add(2)
35
+ list.next.next.isEmpty should be (true)
36
+ }
37
+
38
+ it should "allow creation from a Seq" in {
39
+ pending
40
+ val list = SimpleLinkedList.fromSeq(List(3, 2, 1))
41
+ list.value should be (3)
42
+ list.next.value should be (2)
43
+ list.next.next.value should be (1)
44
+ }
45
+
46
+ it should "allow conversion to a Seq" in {
47
+ pending
48
+ val list = SimpleLinkedList.fromSeq(List(3, 2, 1))
49
+ val seq = list.toSeq
50
+ seq should be (List(3, 2, 1))
51
+ }
52
+
53
+ it should "handle reverse" in {
54
+ pending
55
+ val list = SimpleLinkedList.fromSeq(List(1, 2, 3, 4, 5, 6))
56
+ val reversed = list.reverse
57
+ reversed.value should be (6)
58
+ reversed.next.value should be (5)
59
+ reversed.next.next.value should be (4)
60
+ reversed.next.next.next.value should be (3)
61
+ reversed.next.next.next.next.value should be (2)
62
+ reversed.next.next.next.next.next.value should be (1)
63
+ }
64
+
65
+ it should "handle arbitrary list fromSeq toSeq" in {
66
+ pending
67
+ forAll { seq: Seq[Int] =>
68
+ assert(SimpleLinkedList.fromSeq(seq).toSeq == seq)
69
+ }
70
+ }
71
+
72
+ it should "handle reverse arbitrary list " in {
73
+ pending
74
+ forAll { seq: Seq[Int] =>
75
+ assert(SimpleLinkedList.fromSeq(seq).reverse.toSeq == seq.reverse)
76
+ }
77
+ }
78
+
79
+ it should "reverse arbitrary list back to original" in {
80
+ pending
81
+ forAll { list: SimpleLinkedList[Int] =>
82
+ assert(list.reverse.reverse.toSeq == list.toSeq)
83
+ }
84
+ }
85
+
86
+ it should "return correct arbitrary value at index" in {
87
+ pending
88
+ def nthDatum(list: SimpleLinkedList[Int], i: Int): Int = {
89
+ (0 until i).foldLeft(list)((acc, j) => acc.next).value
90
+ }
91
+
92
+ forAll { xs: Seq[Int] =>
93
+ whenever(xs.nonEmpty) {
94
+ val list = SimpleLinkedList.fromSeq(xs)
95
+ xs.indices.foreach {
96
+ i => assert(nthDatum(list, i) == xs(i))
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ it should "handle arbitrary generics" in {
103
+ pending
104
+ forAll { xs: Seq[String] =>
105
+ assert(SimpleLinkedList.fromSeq(xs).toSeq == xs)
106
+ }
107
+ }
108
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trackler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8.10
4
+ version: 2.0.8.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katrina Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-03 00:00:00.000000000 Z
11
+ date: 2017-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -7391,6 +7391,10 @@ files:
7391
7391
  - tracks/scala/exercises/simple-cipher/example.scala
7392
7392
  - tracks/scala/exercises/simple-cipher/src/main/scala/.keep
7393
7393
  - tracks/scala/exercises/simple-cipher/src/test/scala/CipherTest.scala
7394
+ - tracks/scala/exercises/simple-linked-list/build.sbt
7395
+ - tracks/scala/exercises/simple-linked-list/example.scala
7396
+ - tracks/scala/exercises/simple-linked-list/src/main/scala/SimpleLinkedList.scala
7397
+ - tracks/scala/exercises/simple-linked-list/src/test/scala/SimpleLinkedListTest.scala
7394
7398
  - tracks/scala/exercises/space-age/build.sbt
7395
7399
  - tracks/scala/exercises/space-age/example.scala
7396
7400
  - tracks/scala/exercises/space-age/src/main/scala/.keep