The rules of Ten Pin bowling are easy to follow, but can be tricky to implement in code. An example by Tomas Brennan can be
found here, which hosts a single-player GUI in C# for entering scores and calculating the
result. The approach I have used instead represents a scoreboard, including the appropriate layout and calculations printed in the command prompt. It also
stores internal data in a very different way, allowing for a different set of features.
As a technical test, I was tasked with creating a scoreboard for a game of Ten Pin bowling, validating all input and
incorporating all rules associated with the game. The examples provided with this article cover printing the scoreboard as text in the Windows command
prompt or in the Mac OS X terminal. This could of course be extended to displaying values in a GUI.
Using the code
The underlying system (i.e., not including the implementation of
InterfaceManager) was designed to
rely solely on STL classes, and therefore be completely cross-platform. While multiple forms of game have not been created, the game logic has been separated
from the main program (by using two classes:
BowlingGame) so that such changes would be trivial. For the sake of simplicity and time,
InterfaceManager was written twice in separate deployments instead of creating an abstract interface
to determine the output methodology (or worse, wrapping up the interface in large blocks of preprocessor directives).
Getting started: Initialization
Initialization is straightforward; set initial default values and request the number of players. The technical specification did
not provide a maximum number of players, so I set this to six. In order to get values from the user, everything is performed through the
referred to as Interface). This constitutes a simple
std::cin to an
which is then parsed to the appropriate type. To get the number of players between one and six from the user, the following code is used:
int playerCount = 0;
playerCount = Interface.getIntegerValue(" Please enter the number of players (1-6): ");
while (playerCount < 1 || playerCount > 6);
This simply draws the splash screen (involving a little ASCII art in these console versions), prints the message requesting an
integer input, and waits for the value to be entered. I do not trust
std::cin to directly put input values into anything other than a string,
so I instead use a
stringToInteger function from my
Once the program has a number between one and six, it proceeds to ask for the names of each of the new players. The validation for this is straightforward;
any input between three and sixteen characters long that isn't already the name of an entered player.
Additional input validation would be straightforward to implement (i.e., alphabets only, first letter uppercase, subsequent letters lowercase).
With all of the players set up, the game's initialization is complete - it begins on game one, frame one, and the program begins the game's update cycle.
Taking turns: Update loop
The following line determines which player's turn it is:
_turn = (_turn + 1) % _players.size();
And when it comes back to Player 1's turn, it begins the next round (or frame in game terms).
if (_turn == 0)
Rather than handling each update cycle for each ball being bowled, a given cycle is for a player's whole turn.
This means a player will continue bowling until their turn of this frame is over. A player progresses their turn by calling their
until it returns true, denoting the end of their turn.
Bowling a ball is a straightforward process, using the following code:
scoreThisBowl = Interface.getIntegerValue(" How many pins were hit on this bowl? ");
while (!isValidScore(scoreThisBowl, currentFrame));
Note: this has been abbreviated from the Windows version, as the console class is not valid in non-Windows systems.
isValidScore function simply ensures that a logical number has been entered. Most of the time, this is a value between 0 and 10. Otherwise, if it is
not the final frame and a non-Strike first ball has been bowled, it is a value between 0 and (10 - first score).
With a valid score entered, the player "updates" all of his previous scores with the new score. This could be optimised somewhat by not updating
more than the last two scores, but it is hardly a system performance bottleneck. The
update call simply adds the new score as a bonus to the old
score, if applicable. This is determined when the score is first recorded; if it is a Strike, it records the next two scores as bonuses. If it is a Spare, it
records the next single score as a bonus. When all bonuses have been applied to a score, it no longer adds bonuses to itself.
Displaying the scoreboard: The interface
Along with some utilities in the Windows version, the
InterfaceManager class is comprised of three main
splash screen simply shows some bowling ASCII art and the list of player names.
The score table is the most varied part of this program, requiring the most alteration between the Windows
and Mac OS X versions. This is because the Mac terminal does not support utility features relating to different font colours or manually positioning the
caret around the window. As a result, it needs to generate the score table line-by-line in the correct order, as opposed to printing the score table
with no formatting and then filling in the individual scores as appropriate. In Windows, this included some extra formatting to change the colour of the text
depending on whose turn it is, highlighting the current player's name and scores in yellow. Finally, the scores themselves are formatted according to the
rules; a Strike is shown as an "X", a Spare is shown as a "/", and a score of zero is shown as a "-".
The game over screen simply shows the score table and an ASCII trophy, declaring the winner and the score they achieved. Ties for the top score are shown as
necessary, and the total score of the whole team added together is shown at the bottom.
Ending the game: Replay and shutdown
When a game has been played through ten frames and the winner(s) declared, the program prompts the user whether they want to
play another game or not. If so, the game resets all player data and runs its initialization again. Otherwise, the game shuts down and closes the
program. There is no dynamically allocated memory in this program, so everything is automatically cleared up on shutdown.
Points of interest
I'd learned how to write code that is cross-platform and does not rely on obscure, outdated, or experimental
libraries that are not likely to exist on every machine. However, before this project, I had not attempted to print out a program in the Mac OS X terminal;
my assumptions had been that, because they both print text using
std::cout, I could very easily redeploy my program.
I had not counted on the different features of the terminal, and ended up rewriting fairly large sections of the interface. This mostly involved taking
out the changing font colours and repositioning the caret; everything was instead printed line-by-line, resulting in similar output but requiring a bit
more care and calculation.
Deployed and tested version 1.0 on Windows 7 x64 and Mac OS X Snow Leopard.