diff --git a/lib/bowling_game.dart b/lib/bowling_game.dart index f1494d2..0d7a54a 100644 --- a/lib/bowling_game.dart +++ b/lib/bowling_game.dart @@ -1,35 +1,58 @@ class BowlingGame { + static const _totalFrames = 10; + static const _allPins = 10; + static const _rollsInNormalFrame = 2; + static const _rollsInStrike = 1; + final List _rolls = []; - void roll(int pins) { - _rolls.add(pins); - } + void roll(int pins) => _rolls.add(pins); int score() { - int totalScore = 0; + int total = 0; int rollIndex = 0; - for (int frame = 0; frame < 10; frame++) { + for (int frame = 0; frame < _totalFrames; frame++) { if (_isStrike(rollIndex)) { - totalScore += 10 + _rolls[rollIndex + 1] + _rolls[rollIndex + 2]; - rollIndex += 1; + total += _strikeScore(rollIndex); + rollIndex += _rollsInStrike; } else if (_isSpare(rollIndex)) { - totalScore += 10 + _rolls[rollIndex + 2]; - rollIndex += 2; + total += _spareScore(rollIndex); + rollIndex += _rollsInNormalFrame; } else { - totalScore += _rolls[rollIndex] + _rolls[rollIndex + 1]; - rollIndex += 2; + total += _normalScore(rollIndex); + rollIndex += _rollsInNormalFrame; } } - return totalScore; + return total; + } + + int _strikeScore(int rollIndex) { + return _allPins + _nextTwoRollsBonus(rollIndex); + } + + int _spareScore(int rollIndex) { + return _allPins + _nextRollBonus(rollIndex); + } + + int _normalScore(int rollIndex) { + return _rolls[rollIndex] + _rolls[rollIndex + 1]; + } + + int _nextTwoRollsBonus(int rollIndex) { + return _rolls[rollIndex + 1] + _rolls[rollIndex + 2]; + } + + int _nextRollBonus(int rollIndex) { + return _rolls[rollIndex + 2]; } bool _isSpare(int rollIndex) { - return _rolls[rollIndex] + _rolls[rollIndex + 1] == 10; + return _rolls[rollIndex] + _rolls[rollIndex + 1] == _allPins; } bool _isStrike(int rollIndex) { - return _rolls[rollIndex] == 10; + return _rolls[rollIndex] == _allPins; } } diff --git a/test/bowling_game_test.dart b/test/bowling_game_test.dart index 14fafe0..cc2f463 100644 --- a/test/bowling_game_test.dart +++ b/test/bowling_game_test.dart @@ -2,7 +2,7 @@ import 'package:tdd_katas/bowling_game.dart'; import 'package:test/test.dart'; void main() { - group('Bowling Game', () { + group('Bowling Game Scoring', () { late BowlingGame game; setUp(() { @@ -15,32 +15,64 @@ void main() { } } - test('gutter game - all zeros', () { - rollMany(20, 0); - expect(game.score(), 0); + group('Basic Scoring', () { + test('gutter game - no pins knocked', () { + rollMany(20, 0); + expect(game.score(), 0); + }); + + test('all ones - simple addition', () { + rollMany(20, 1); + expect(game.score(), 20); + }); }); - test('all ones - score is 20', () { - rollMany(20, 1); - expect(game.score(), 20); + group('Spare Bonus (next 1 roll)', () { + test('one spare in first frame', () { + game.roll(5); + game.roll(5); // spare + game.roll(3); // bonus for spare + rollMany(17, 0); + + expect(game.score(), 16); // 10 + 3 (bonus) + 3 + }); + + test('all spares with 5 pins each', () { + rollMany(21, 5); // 10 frames of 5,5 + 1 bonus roll + expect(game.score(), 150); + }); }); - test('one spare', () { - game.roll(5); - game.roll(5); // spare - game.roll(3); // bonus for spare - rollMany(17, 0); // rest are gutter balls + group('Strike Bonus (next 2 rolls)', () { + test('one strike in first frame', () { + game.roll(10); // Strike! + game.roll(3); + game.roll(4); // Next 2 rolls are bonus + rollMany(16, 0); - expect(game.score(), 16); // 10 (spare) + 3 (bonus) + 3 (normal roll) + expect(game.score(), 24); // 10 + 3 + 4 (bonus) + 7 + }); + + test('perfect game - twelve consecutive strikes', () { + rollMany(12, 10); + expect(game.score(), 300); + }); }); - test('one strike', () { - game.roll(10); // Strike! - game.roll(3); - game.roll(4); // Next 2 rolls are bonus - rollMany(16, 0); + group('Complex Scenarios', () { + test('combination of strikes, spares, and normal frames', () { + game.roll(10); // Frame 1: Strike + game.roll(5); + game.roll(5); // Frame 2: Spare + game.roll(7); + game.roll(2); // Frame 3: Normal + rollMany(15, 0); - expect(game.score(), 24); // 10 + 3 + 4 (strike) + 3 + 4 (frame 2) = 24 + // Frame 1: 10 + 5 + 5 = 20 + // Frame 2: 10 + 7 = 17 + // Frame 3: 7 + 2 = 9 + expect(game.score(), 46); + }); }); }); }