Don't forget to also checkout my second blog containing articles to all other related ICT topics!!

Monday, May 28, 2012

Final exam CS212: bowling puzzler

This is the first question from the Udacity CS212 final exam. I will update this article with my solution in 1 week. Please do not comment anything during the final exam week !!
```"""
UNIT 1: Bowling:

You will write the function bowling(balls), which returns an integer indicating
the score of a ten-pin bowling game.  balls is a list of integers indicating
how many pins are knocked down with each ball.  For example, a perfect game of
bowling would be described with:

>>> bowling([10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
300

The rules of bowling are as follows:

(1) A game consists of 10 frames. In each frame you roll one or two balls,
except for the tenth frame, where you roll one, two, or three.  Your total
score is the sum of your scores for the ten frames.
(2) If you knock down fewer than ten pins with your two balls in the frame,
you score the total knocked down.  For example, bowling([8, 1, 7, ...]) means
that you knocked down a total of 9 pins in the first frame.  You score 9 point
for the frame, and you used up two balls in the frame. The second frame will
(3) If you knock down all ten pins on your second ball it is called a 'spare'
and you score 10 points plus a bonus: whatever you roll with your next ball.
The next ball will also count in the next frame, so the next ball counts twice
(except in the tenth frame, in which case the bonus ball counts only once).
For example, bowling([8, 2, 7, ...]) means you get a spare in the first frame.
You score 10 + 7 for the frame; the second frame starts with the 7.
(4) If you knock down all ten pins on your first ball it is called a 'strike'
and you score 10 points plus a bonus of your score on the next two balls.
(The next two balls also count in the next frame, except in the tenth frame.)
For example, bowling([10, 7, 3, ...]) means that you get a strike, you score
10 + 7 + 3 = 20 in the first frame; the second frame starts with the 7.

"""

def bowling(balls):
"Compute the total score for a player's game of bowling."

def test_bowling():
assert   0 == bowling( * 20)
assert  20 == bowling( * 20)
assert  80 == bowling( * 20)
assert 190 == bowling([9,1] * 10 + )
assert 300 == bowling( * 12)
assert 200 == bowling([10, 5,5] * 5 + )
assert  11 == bowling([0,0] * 9 + [10,1,0])
assert  12 == bowling([0,0] * 8 + [10, 1,0])

test_bowling()
```
My solution:
```"""
UNIT 1: Bowling:

You will write the function bowling(balls), which returns an integer indicating
the score of a ten-pin bowling game.  balls is a list of integers indicating
how many pins are knocked down with each ball.  For example, a perfect game of
bowling would be described with:

>>> bowling([10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
300

The rules of bowling are as follows:

(1) A game consists of 10 frames. In each frame you roll one or two balls,
except for the tenth frame, where you roll one, two, or three.  Your total
score is the sum of your scores for the ten frames.
(2) If you knock down fewer than ten pins with your two balls in the frame,
you score the total knocked down.  For example, bowling([8, 1, 7, ...]) means
that you knocked down a total of 9 pins in the first frame.  You score 9 point
for the frame, and you used up two balls in the frame. The second frame will
(3) If you knock down all ten pins on your second ball it is called a 'spare'
and you score 10 points plus a bonus: whatever you roll with your next ball.
The next ball will also count in the next frame, so the next ball counts twice
(except in the tenth frame, in which case the bonus ball counts only once).
For example, bowling([8, 2, 7, ...]) means you get a spare in the first frame.
You score 10 + 7 for the frame; the second frame starts with the 7.
(4) If you knock down all ten pins on your first ball it is called a 'strike'
and you score 10 points plus a bonus of your score on the next two balls.
(The next two balls also count in the next frame, except in the tenth frame.)
For example, bowling([10, 7, 3, ...]) means that you get a strike, you score
10 + 7 + 3 = 20 in the first frame; the second frame starts with the 7.

"""

def bowling(balls):
"Compute the total score for a player's game of bowling."
balls.reverse()
score = countScore(balls, 0, 0)
return score

def countScore(balls, frame, score):
frame += 1
if not balls:
return score
ball1 = balls.pop()
if ball1 == 10:
#we got a strike so we need to add two next balls
newscore = score + ball1 + (balls.pop() if frame == 10 else balls[-1]) + (balls.pop() if frame == 10 else balls[len(balls) - 2])
return countScore(balls, frame, newscore)
if ball1 + balls[-1] == 10:
#we got a spare so we pop the second one as well
ball2 = balls.pop()
newscore = score + ball1 + ball2 + (balls.pop() if frame == 10 else balls[-1])
return countScore(balls, frame, newscore)
#else we just add up the scores of the first two balls for this frame
ball2 = balls.pop()
newscore = score + ball1 + ball2
return countScore(balls, frame, newscore)

def test_bowling():
assert   0 == bowling( * 20)
assert  20 == bowling( * 20)
assert  80 == bowling( * 20)
assert 190 == bowling([9,1] * 10 + )
assert 300 == bowling( * 12)
assert 200 == bowling([10, 5,5] * 5 + )
#here we throw in frame 10 a strike and we add 1 and 0 to the final score
assert  11 == bowling([0,0] * 9 + [10,1,0])
#here we throw a strike in frame 9 (10 + 1) and in frame 10 we throw 1 and 0 so this adds up to 11 + 1
assert  12 == bowling([0,0] * 8 + [10, 1,0])

test_bowling()
```