Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Ten Pin Bowling Scoreboard

0.00/5 (No votes)
9 Mar 2012 1  
Command line application for recording and displaying scores for Ten Pin bowling

Introduction

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.

Background

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: Program and BowlingGame) so that such changes would be trivial. For the sake of simplicity and time, the 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 InterfaceManager (externally referred to as Interface). This constitutes a simple std::cin to an std::string value, 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;
do
{
    Interface.drawSplashScreen(*this);
    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 GameUtil class.

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.

325728/PlayerNames.jpg

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)
    _frame++;

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 bowlBall function until it returns true, denoting the end of their turn.

Bowling a ball is a straightforward process, using the following code:

do
{
    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.

The 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 functions: drawSplashScreen, drawScoreTable, and drawGameOverScreen. The 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.

325728/Winner.jpg

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.

History

  • 6th February, 2012: Initial post

Deployed and tested version 1.0 on Windows 7 x64 and Mac OS X Snow Leopard

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here