I had a lot of fun putting my bowling game together back when you first brought this up.
I have a Bowling (Game) class, a Frame class, aThrow class and a Score(ing) class. I made the Throws a class that I put in an OrderedCollection - but instVars would work as well... the rest of your game should be oblivious to your 'underpinnings' anyway.
The Bowling class controls the game and cycles through 10 frames, which I create then house in an OrderedCollection at the start of the game. Frame has a subclass called Frame10 that is instantiated for the 10th frame of the game.
Bowling processes each Frame, starting at 1, from the collection, and does a runFrame (or whatever action name you want). A Frame consists of throws, 1, 2, or 3 - depending on the frame and the result of the first throw.
A throw returns a random number of 'knocked down pins' between 0 (gutter ball) and the number of pins remaining in the frame (results of a previous throw). So my Frame always knows -pinsCleared and -pinsRemaining - but it asks the Throws what they cleared to calculate that info.
After each throw, the Score class runs through the frames to see if anything additional can be scored...
- i.e. the first throw on frame3 would be added to the 'spare' of frame2 plus the score of frame 1 - to get the frame 2 score. But frame3 cannot yet be scored.
Then when the frame does the 2nd throw, (as long as it's not a spare), the 3rd frame can also be scored. Scoring was certainly the most challenging/fun part for me as there are a number of variables to consider. Scoring would start at frame1 each time it is called and find the first frame without a score (the running score is stored on the frame), a frame can be asked what its score is, but it's kindof irrelevant as this is not shown on a scorecard, and it can't be done it a vacuum... i.e. if I have a strike or a spare in a frame, what is the frame score? You have to get the next two throws to figure that out... so I let the Score class do that and simply update the Frame score instVar once the calculation has been made.
As soon as Scoreing hits a frame it cannot score, it stops and the Frame goes on to the next throw, or if it has hit maxThrows for the frame (frame1-9, maxThrows=2, frame10 maxThrows=3)... some folks call the third ball a bonus ball, I decided not to.
So, when you get to frame10, we are allowed to have 3 throws if certain conditions are met -
- your first throw is a strike, or
- your second throw is a spare
... and of course scoring is a bit different for frame10, as well.
I created a simulator with a traceCr output to show my frames and throws.
Frame 1, 8 pins
Throw 1, 6 pins
Throw 2, 2 pins
Score: 8
Frame 2, 9 pins
Throw 1, 0 pins
Throw 2, 9 pins
Score: 17
Frame 3, 7 pins
Throw 1, 5 pins
Throw 2, 2 pins
Score: 24
Frame 4, 9 pins
Throw 1, 8 pins
Throw 2, 1 pins
Score: 33
Frame 5, 5 pins
Throw 1, 3 pins
Throw 2, 2 pins
Score: 38
Frame 6, 6 pins
Throw 1, 5 pins
Throw 2, 1 pins
Score: 44
Frame 7, 9 pins
Throw 1, 4 pins
Throw 2, 5 pins
Score: 53
Frame 8, 8 pins
Throw 1, 1 pins
Throw 2, 7 pins
Score: 61
Frame 9, 3 pins
Throw 1, 3 pins
Throw 2, 0 pins
Score: 64
Frame 10, 15 pins
Throw 1, 4 pins
Throw 2, 6 pins
Throw 3, 5 pins
Score: 79
Final score: 79
Strikes: 0
Spares: 1
Gutters: 2
Timer >> 24.933ms Bowling-runTestGame
I then tried my hand at a GUI - creating a BowlingPresenter, a ScorecardPresenter, a FramePresenter and a Frame10Presenter, resulting in...
I plan to add multi-player (or at least playing against the computer), but until I figure out how to make the throws be specific about which physical pins are remaining and the percentages of the next throw clearing them (much more complex that pure random) - there's not much else I can really do. So if anyone has direction for me on this, I'd love to try and tackle it sometime.
Let me know if you have any questions.
Thanks,
Russ