This repo should auxiliate on the counting of score in bowling. It uses a .NET Core ClassLib for the logic and xUnit for Unit Testing.
The bowling score system works with the following rules:
- the more pins knocked down with the least number of attempts (throws), the bigger the score
- each game has always 10 frames
- when the player knocks down 10 pins in a single throw, it's a strike
- when the player knocks down 10 total pins in different throws but in the same frame, it's a spare
- at each of the first 9 frames the player has 10 pins to knock down and:
- only 1 throw if the first ball hits a strike, or
- 2 throws if it doesn't
- at the frame 10 the player has 10 pins to knock down (that are restored after each strike/spare) and:
- only 2 throws if none of the balls hit a strike or a spare, or
- 3 throws if at least one of them do
- each pin knocked down is worth a point, but:
- every strike multiplies the score of the next 2 throws on the next frame, and
- every spare multiplies the score of the next throw on the next frame
Expressions used in this section:
- normal throw: a ball thrown that hasn't scored a strike nor a spare.
- special throw: a ball that has scored either a strike or a spare.
A normal match with no special throws should last 20 throws.
An 'extended match' would be one where a special throw of any kind is reached at the 10th frame, resulting in an extra throw.
The least amount of score is 0 (all misses) and the highest is 300 (perfect match with 12 strikes).
The least amount of throws is 11 (9 strikes followed by 2 normal throws at the 10th) and the highest is 21 (18 normal throws followed by a special throw at the 10th frame).
Two strikes in sequence should multiply the score of the next throw by 3.
Since special throws only affect the throw(s) on the next frame, any special throws on the 10th frame will not affect following throws.
That means that the only throws capable of multiplying the following throw(s) are the ones from frames 1 to 9.
Even though the throws from frame 10 cannot multiply following throws, their value can be normally multiplied by previous throws.
Based on all the rules and situations on special throws explained before, there are two (or maybe more) ways of counting the score on a bowling game, they are:
- the official way: in this way the extra score generated by special throws is added to the special throw itself.
- this method will require the previous values to be updated when a special throw multiplies the following throws.
- this method is the right one for showing score (i.e. on a chart or screen) and can also count the total score.
- the way used in this program: in this one, the extra score is added to the following throws and not to the special throw itself.
- this method does not require backtracking to update previous values and therefore is easier to implement (in my personal opinion).
- this method is not recommended for showing score, but can perfectly count the total score.
At the example below, we can see the pin points (amount of pins knocked, not yet multiplied), official way and 'easy' way at each frame of a perfect match:
| Counting | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 |
|---|---|---|---|---|---|---|---|---|---|---|
| Pin points | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 + 10 + 10 |
| Official way | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
| 'Easy' way | 10 | 20 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 + 20 + 10 |
Along with using the official way of counting, when the score should be displayed (at a screen, card or chart) the amount of score visually displayed at each frame represents the total score until then (all previous frames + current frame total). So the end of a perfect match would display like this:
| Player | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 |
|---|---|---|---|---|---|---|---|---|---|---|
| Player 1 👑 | 30 | 60 | 90 | 120 | 150 | 180 | 210 | 240 | 270 | 300 |
- Should score 0 for gutter game:
20 * 0 - Should score 20 for all ones game:
20 * 1 - Should score 16 for a spare followed by a 3 ball:
[ 4 + 6 ] + 3 - Should score 24 for a strike followed by a 3-point and a 4-point ball:
🔟 + [ 3 + 4 ] - Should score 23 for two sequential spares:
[ 4 + 6 ] + [ 3 + 7 ] - Should score 300 for a perfect game:
12 * 🔟 - Should score 30 for a strike followed by a spare:
🔟 + [ 5 + 5 ] - Should score 270 for 9 strikes followed by 5-point balls thrown 3 times at the 10th frame:
[ 9️ * 🔟 ] + [ 5 + 5 + 5 ]
Instructions to use:
- download or clone the repo
- run a Shell prompt inside the project's main folder (bolichePontos)
- enter the following command and press Enter:
dotnet test- voilà!
The program should be able to:
- Calculate the amount of score for games with no strikes or spares.
- Calculate the effect of strikes and spares on the score.
- Execute Unit Testing through xUnit and test the test cases described on this document.
- Elaborate a full-covered Coverage Report.
The main idiom used is [🇧🇷] Brazilian Portuguese, my mother tongue.
-
Create a terminal instance in your tests project folder
-
Add the coverlet package to your project (this command has already been run in this project)
dotnet add package coverlet.msbuild
-
Install the dotnet reportgenerator to generate HTML previews of the coverage report
dotnet tool install -g dotnet-reportgenerator-globaltool
-
Run the test command with this parameter to generate the coverage report
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./lcov.info ./bolicheTests -
Run the reportgenerator command to generate the HTML coverage report
reportgenerator -reports:./bolicheTests/lcov.info -targetdir:coveragereport -reporttypes:Html
-
It is also possible to run dotnet watch to rerun tests and generate coverage whenever a new change is detected to one of the project files
dotnet watch --project bolicheTests test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./lcov.info
This project uses the following Commit Guidelines:
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- test: Adding missing tests or correcting existing tests
Contact and support me through the following social medias:
This project is licensed under the MIT License - see the LICENSE file for details.
🧰 Being developed by Wesley Yago!