Skip to content

Instantly share code, notes, and snippets.

@glossawy
Created March 24, 2022 16:53
Show Gist options
  • Save glossawy/912842802edccf1b72af9e70291194b5 to your computer and use it in GitHub Desktop.
Save glossawy/912842802edccf1b72af9e70291194b5 to your computer and use it in GitHub Desktop.

Bowling Score Calculator

Goal

Write a basic bowling game scoring calculator, which accepts individual rolls and provides the correct score for them.

How bowling scoring works

A bowling game is broken down into multiple attempts to knock down 10 pins with your ball. Each turn you get two attemps to knock down all 10 pins. Each turn is called a frame during scoring.

Open frames

If you do not knock down all 10 pins in a frame, it is considered open.

The score of the frame is simply the number of pins knocked down total.

Spares

If you knock down all 10 pins using both rolls of a frame, you get a spare.

A spare earns 10 points, plus the number of pins knocked down in your next roll.

Strikes

If you knock down all 10 pins in a single roll, you get a strike.

Strikes earn 10 points, plus the sum of your next two rolls.

The 10th frame

Scoring the 10th frame works slightly differently

  • If you roll a strike on the first attempt, the pins are reset you get two more rolls
  • If you roll a spare in the first two appempts, the pins are reset and you get 1 additional roll
  • If you roll an open frame, the your turn is over

There are no modifiers applied to the 10th frame, the score is the number of pins knocked down.

How to work through this exercise

A number of tests have been written for you, with all but the first commented out.

Work through each test until you get it passing, and then uncomment the next. Repeat this, ensuring that previously passing tests don't regress, until you have a fully green suite.

It should be noted that these tests do not account for every possible scenario in bowling, but you should limit the scope of your efforts here to the conditions they do set up for you!

Test Cases

  • when a spare is scored
    • in: 3, 7, 5, 0
    • out: 20
  • when a strike is scored
    • in: 10, 5, 4
    • out: 28
  • when adjacent pair equals 10 but in different frames
    • in: 3, 3, 7, 2
    • out: 15
  • when a strike precedes a spare
    • in: 10, 3, 7, 5, 0
    • out: 40
  • perfect game
    • in: 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
    • out: 300
import java.util.List;
public class Game {
public int score(List<Integer> scores) {
// TODO: Implement me!
return -1;
}
}
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
// TODO: import Game.java
// import Game;
public class GameTest {
// TODO: initialize Game
// Game game = new Game();
@Test
public void testScore() {
List<Integer> scores = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
// assertEquals(10, game.score(scores));
}
@Test
public void testScoreSpare() {
List<Integer> scores = new ArrayList<>(Arrays.asList(3, 7, 5, 0));
// assertEquals(20, game.score(scores));
}
@Test
public void testScoreStrike() {
List<Integer> scores = new ArrayList<>(Arrays.asList(10, 5, 4));
// assertEquals(28, game.score(scores));
}
@Test
public void testScoreSiblingScoreTen() {
List<Integer> scores = new ArrayList<>(Arrays.asList(3, 3, 7, 2));
// assertEquals(15, game.score(scores));
}
@Test
public void testScoreStrikeBeforeSpare() {
List<Integer> scores = new ArrayList<>(Arrays.asList(10, 3, 7, 5, 0));
// assertEquals(40, game.score(scores));
}
@Test
public void testScorePerfectGame() {
List<Integer> scores = new ArrayList<>(Arrays.asList(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10));
// assertEquals(300, game.score(scores));
}
}
/*
copy code into a file named: game.test.js
run this command in the same folder as the file you created
$ npm init -y
install jest in same folder
$ npm install jest
running this should run your file:
$ npx jest game.test.js
*/
class Game {
score(scores) {
// put your code here
}
}
describe('Game', () => {
const subject = new Game();
test('when no special scores occur', () => {
let scores = [1, 2, 3, 4];
expect(subject.score(scores)).toEqual(10);
});
// test('when a spare is scored', () => {
// let scores = [3, 7, 5, 0];
// expect(subject.score(scores)).toEqual(20);
// });
// test('when a strike is scored', () => {
// let scores = [10, 5, 4];
// expect(subject.score(scores)).toEqual(28);
// });
// test('when sibling scores equal 10 but are not in the same frame', () => {
// let scores = [3, 3, 7, 2];
// expect(subject.score(scores)).toEqual(15);
// });
// test('and a strike precedes a spare', () => {
// let scores = [10, 3, 7, 5, 0];
// expect(subject.score(scores)).toEqual(40);
// });
// test('when a perfect game is bowled', () => {
// let scores = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10];
// expect(subject.score(scores)).toEqual(300);
// });
});
require 'rspec/autorun'
class Game
def score(scores)
end
end
RSpec.describe Game do
subject(:game) { Game.new }
describe '#score' do
subject { game.score(scores) }
context 'when no special scores occur' do
let(:scores) { [ 1, 2, 3, 4 ] }
it { is_expected.to eq 10 }
end
# context 'when a spare is scored' do
# let(:scores) { [ 3, 7, 5, 0 ] }
# it { is_expected.to eq 20 }
# end
# context 'when a strike is scored' do
# let(:scores) { [ 10, 5, 4 ] }
# it { is_expected.to eq 28 }
# end
# context 'when sibling scores equal 10 but are not in the same frame' do
# let(:scores) { [ 3, 3, 7, 2 ] }
# it { is_expected.to eq 15 }
# context 'and a strike precedes a spare' do
# let(:scores) { [ 10, 3, 7, 5, 0 ] }
# it { is_expected.to eq 40 }
# end
# end
# context 'when a perfect game is bowled' do
# let(:scores) { [ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ] }
# it { is_expected.to eq 300 }
# end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment