trackler 2.0.8.10 → 2.0.8.11

Sign up to get free protection for your applications and to get access to all the features.
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