SlideShare a Scribd company logo
Bowling Game KataAdapted for C# and nUnitBy Dan Stewart (with modifications by Mike Clement)dan@stewshack.commike@softwareontheside.com
Scoring Bowling.The game consists of 10 frames as shown above.  In each frame the player has two opportunities to knock down 10 pins.  The score for the frame is the total number of pins knocked down, plus bonuses for strikes and spares.A spare is when the player knocks down all 10 pins in two tries.  The bonus for that frame is the number of pins knocked down by the next roll.  So in frame 3 above, the score is 10 (the total number knocked down) plus a bonus of 5 (the number of pins knocked down on the next roll.)A strike is when the player knocks down all 10 pins on his first try.  The bonus for that frame is the value of the next two balls rolled.In the tenth frame a player who rolls a spare or strike is allowed to roll the extra balls to complete the frame.  However no more than three balls can be rolled in tenth frame.
A quick design sessionClearly we need the Game class.
A quick design sessionA game has 10 frames.
A quick design sessionA frame has 1 or two rolls.
A quick design sessionThe tenth frame has two or three rolls.It is different from all the other frames.
A quick design sessionThe score function mustinclude all the frames, and calculate all their scores.
A quick design sessionThe score for a spare or a strike depends on the frame’s successor
Begin.Create a class library named BowlingGameKata
Begin.Add a test fixture named BowlingGameTests to the projectusingNUnit.Framework;namespaceBowlingGameKata{[TestFixture]publicclassBowlingGameTests{        [Test]publicvoidGutterGameTest()        {        }    }}
The first test.[Test]publicvoidGutterGameTest() {     Game g = new Game();}
The first test.namespaceBowlingGameKata{publicclassGame    {    }}[Test]publicvoidGutterGameTest(){     Game g = new Game();}
The first test.[Test]publicvoidGutterGameTest(){     Game g = new Game();}publicclassGame{}
The first test.[Test]publicvoidGutterGameTest(){    Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0); }}publicclassGame{}
The first test.public class Game{   publicvoid Roll(int p){   thrownewSystem.NotImplementedException();}}[Test]publicvoidGutterGameTest(){    Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0); }}
The first test.[Test]publicvoidGutterGameTest(){   Gameg = newGame();for(int i = 0; i < 20; i++){g.Roll(0);}Assert.That(g.Score(), Is.EqualTo(0));}public class Game{   publicvoid Roll(int p){   thrownewSystem.NotImplementedException();   }}
The first test.[Test]publicvoidGutterGameTest(){   Gameg = newGame();for(int i = 0; i < 20; i++){g.Roll(0);}Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{   publicvoid Roll(int p)   {thrownew System.NotImplementedException();   }publicobject Score(){thrownew System.NotImplementedException();   }}Failed GutterGameTestthrew exception
The first test.[Test]publicvoidGutterGameTest(){    Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0);   }Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
The Second test.[Test]publicvoidAllOnesTest(){    Gameg = newGame();    for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
The Second test.- Game creation is duplicated- roll loop is duplicated[Test]publicvoidAllOnesTest(){    Gameg = newGame();    for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
The Second test.- Game creation is duplicated- roll loop is duplicated[Test]publicvoidAllOnesTest(){    Gameg = newGame();    for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins){}publicintScore(){return score;   }}Assert.AreEqual failed. Expected:<20>. Actual:<0>.
The Second test.- roll loop is duplicatedprivateGame g;[SetUp]publicvoidSetup() {    g = newGame();}[Test]publicvoidGutterGameTest(){for(int i = 0; i < 20; i++) {g.Roll(0); }Assert.That(g.Score(), Is.EqualTo(0));}[Test]publicvoidAllOnesTest(){for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}
The Second test.- roll loop is duplicated[Test]publicvoidGutterGameTest(){int rolls = 20;intpins = 0;for(int i = 0; i < rolls; i++){g.Roll(pins);}Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}
The Second test.- roll loop is duplicated[Test]publicvoidGutterGameTest(){int rolls = 20;intpins = 0;RollMany(rolls, pins);for(int i = 0; i < rolls; i++)  {g.Roll(pins); }Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}
The Second test.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}[Test]publicvoidGutterGameTest(){RollMany(20, 0);Assert.That(g.Score(), Is.EqualTo(0));}privatevoidRollMany(introlls, int pins){    for(int i = 0; i < rolls; i++) {g.Roll(pins); }}
The Second test.[Test]publicvoidGutterGameTest(){RollMany(20, 0);Assert.That(g.Score(), Is.EqualTo(0));}[Test]publicvoidAllOnesTest(){RollMany(20, 1);Assert.That(g.Score(), Is.EqualTo(20));}privatevoidRollMany(int rolls, int pins){    for(int i = 0; i < rolls; i++) {g.Roll(pins); }}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}
The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}tempted to use flag to remember previous roll.  So design must be wrong.Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.Roll() calculates score, but name does not imply that.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.AreEqual(16, g.Score);}Score() does not calculate score, but name implies that it does.Design is wrong.  Responsibilities are misplaced.Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score;    }}
The Third test.- ugly comment in test.publicclassGame{privateint score;privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;score += pins;}publicint Score(){return score;    }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}
The Third test.- ugly comment in test.publicclassGame{        privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score;    }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}
The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{        privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score;    }}Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++)    {        // spare        if(rolls[i] + rolls[i+1] == 10){score += ...}score += rolls[i];}return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}This isn’t going to work because i might not refer to the first ball of the frame.Design is still wrong.Need to walk through array two balls (one frame) at a time.Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.publicclassGame{        privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score;    }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));Assert.Inconclusive();}
The Third test.- ugly comment in test.publicint Score(){int score = 0;inti = 0;for (int frame = 0; frame < 10; frame++){        score += rolls[i] + rolls[i + 1];        i+= 2;}returnscore;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));Assert.Inconclusive();}
The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicint Score(){int score = 0;int i = 0;for (int frame = 0; frame < 10; frame++)    {        score += rolls[i] + rolls[i + 1];        i += 2;    }return score;}Failed Assert.AreEqual Expected:<16>. Actual:<13>
The Third test.- ugly comment in test.publicint Score(){int score = 0;inti = 0;for (int frame = 0; frame < 10; frame++){// spareif (rolls[i] + rolls[i + 1] == 10){score += 10 + rolls[i + 2];i += 2;}else{            score += rolls[i] + rolls[i + 1];      i += 2;       }    }return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
The Third test.ugly comment in test.
ugly comment in conditional.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){// spareif (rolls[roll] + rolls[roll + 1] == 10){score += 10 + rolls[roll + 2];roll += 2;}else{            score += rolls[roll] + rolls[roll + 1];                  roll += 2;        }   }return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
The Third test.- ugly comment in test.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){        if(IsSpare(roll))        {           score += 10 + rolls[roll + 2];            roll += 2;        }else        {            score += rolls[roll] + rolls[roll + 1];                  roll += 2;}   }returnscore;}privateboolIsSpare(int roll){    returnrolls[roll] +    rolls[roll + 1] == 10;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
The Third test.[Test]publicvoidOneSpareTest(){RollSpare();g.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}privatevoidRollSpare(){g.Roll(5);g.Roll(5);}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){        if(IsSpare(roll))        {            score += 10 + rolls[roll + 2];            roll += 2;        }else        {            score += rolls[roll] + rolls[roll + 1];                  roll += 2;        }}returnscore;}privateboolIsSpare(int roll){    returnrolls[roll] +    rolls[roll + 1] == 10;}
The Fourth test.- ugly comment in OneStrikeTest.[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){        if(IsSpare(roll)){    score += 10 + rolls[roll + 2];}else{            score += rolls[roll] + rolls[roll + 1];}roll += 2;}returnscore;}privatebool IsSpare(int roll){    returnrolls[roll] +    rolls[roll + 1] == 10;}Failed Assert.AreEqual Expected:<24>. Actual:<17>
The Fourth test.ugly comment in OneStrikeTest.
ugly comment in conditional.
ugly expressions.publicint Score(){    intscore = 0;introll = 0;for(int frame = 0; frame < 10; frame++){if(rolls[roll] == 10) // strike{    score += 10 + rolls[roll + 1]    + rolls[roll + 2];roll++;}elseif (IsSpare(roll)){    score += 10 + rolls[roll + 2];roll += 2;}else{    score += rolls[roll] + rolls[roll + 1];roll += 2;}    }    returnscore;}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}
The Fourth test.ugly comment in OneStrikeTest.
ugly comment in conditional.publicint Score(){    intscore = 0;introll = 0;for(int frame = 0; frame < 10; frame++){if(rolls[roll] == 10) // strike{    score += 10 + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){    score += 10 + SpareBonus(roll);roll += 2;}else{           score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}privateint SumOfBallsInFrame(int roll){    returnrolls[roll] + rolls[roll + 1];}privateint SpareBonus(int roll){    returnrolls[roll + 2];}privateint StrikeBonus(int roll){    returnrolls[roll + 1] + rolls[roll + 2];}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}
The Fourth test.- ugly comment in OneStrikeTest.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){if(IsStrike(roll)){    score += 10    + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){score += 10+ SpareBonus(roll);roll += 2;}else{            score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}privatebool IsStrike(int roll){    returnrolls[roll] == 10;}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}

More Related Content

PPT
Bowling Game Kata
PPTX
Bowling Game Kata C#
PPTX
Java: Regular Expression
PDF
Curso de Java: Threads
PPTX
Java 8 Lambda and Streams
PPTX
Regular Expressions in Java
PPTX
Java Foundations: Basic Syntax, Conditions, Loops
PDF
Curso de Java: Introdução a lambda e Streams
Bowling Game Kata
Bowling Game Kata C#
Java: Regular Expression
Curso de Java: Threads
Java 8 Lambda and Streams
Regular Expressions in Java
Java Foundations: Basic Syntax, Conditions, Loops
Curso de Java: Introdução a lambda e Streams

What's hot (20)

PPTX
Loops in C# for loops while and do while loop.
PDF
Workshop unit test
PPTX
Introduction to Regular Expressions
PPTX
Java Lambda Expressions.pptx
PPTX
Java Unit Testing
PDF
Page Object Model and Implementation in Selenium
PPTX
Whitebox testing of Spring Boot applications
PPTX
Paging Like A Pro
PPT
05 junit
PPTX
Java Generics
PPT
Java Collections Framework
PPT
JUnit 4
PDF
GMock framework
PDF
PPTX
20.4 Java interfaces and abstraction
PDF
Mocking in Java with Mockito
PPT
7.data types in c#
PDF
Core Java Tutorial
PPTX
for loop in java
PDF
Algo poo ts
Loops in C# for loops while and do while loop.
Workshop unit test
Introduction to Regular Expressions
Java Lambda Expressions.pptx
Java Unit Testing
Page Object Model and Implementation in Selenium
Whitebox testing of Spring Boot applications
Paging Like A Pro
05 junit
Java Generics
Java Collections Framework
JUnit 4
GMock framework
20.4 Java interfaces and abstraction
Mocking in Java with Mockito
7.data types in c#
Core Java Tutorial
for loop in java
Algo poo ts
Ad

Similar to Bowling Game Kata in C# Adapted (15)

PPT
Bowling Game Kata by Robert C. Martin
PPT
Bowling game kata
PPT
Bowling game kata
PPT
Bowling game kata
PDF
Test-Driven Development Fundamentals on Force.com
PPT
Csphtp1 06
PPT
Introduction to Spec#
PPT
Csphtp1 07
PDF
C++You will design a program to play a simplified version of war, .pdf
PDF
Code retreat june24th
PPT
Csharp In Detail Part2
PPTX
Thinking in F#
DOCX
Java Helpa4.pdfASSIGNMENT 4 A game and an email system.docx
PPT
Classes1
PDF
Bowling Game Kata by Robert C. Martin
Bowling game kata
Bowling game kata
Bowling game kata
Test-Driven Development Fundamentals on Force.com
Csphtp1 06
Introduction to Spec#
Csphtp1 07
C++You will design a program to play a simplified version of war, .pdf
Code retreat june24th
Csharp In Detail Part2
Thinking in F#
Java Helpa4.pdfASSIGNMENT 4 A game and an email system.docx
Classes1
Ad

More from Mike Clement (19)

PPTX
Collaboration Principles from Mob Programming
PPTX
Focus on Flow: Lean Principles in Action
PPTX
Taming scary production code that nobody wants to touch
PPTX
Develop your sense of code smell
PPTX
Maps over Backlogs: User Story Mapping to Share the Big Picture
PPTX
Escaping the Pitfalls of Software Product Development
PPTX
Put the Tests Before the Code
PDF
Mob Programming for Continuous Learning
PPTX
Play to Learn: Agile Games with Cards and Dice
PPTX
The Quest for Continuous Delivery at Pluralsight
PPTX
Software Craftsmanship and Agile Code Games
PPTX
Transformation Priority Premise: TDD Test Order Matters
PPTX
Power of Patterns: Refactoring to (or away from) Patterns
PPTX
Code Katas Spring 2012
PPTX
FizzBuzz Guided Kata
PPTX
Linq (from the inside)
PPTX
Code Katas: Practicing Your Craft
PPTX
Software Craftsmanship
PPTX
Using Rhino Mocks for Effective Unit Testing
Collaboration Principles from Mob Programming
Focus on Flow: Lean Principles in Action
Taming scary production code that nobody wants to touch
Develop your sense of code smell
Maps over Backlogs: User Story Mapping to Share the Big Picture
Escaping the Pitfalls of Software Product Development
Put the Tests Before the Code
Mob Programming for Continuous Learning
Play to Learn: Agile Games with Cards and Dice
The Quest for Continuous Delivery at Pluralsight
Software Craftsmanship and Agile Code Games
Transformation Priority Premise: TDD Test Order Matters
Power of Patterns: Refactoring to (or away from) Patterns
Code Katas Spring 2012
FizzBuzz Guided Kata
Linq (from the inside)
Code Katas: Practicing Your Craft
Software Craftsmanship
Using Rhino Mocks for Effective Unit Testing

Recently uploaded (20)

PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
DP Operators-handbook-extract for the Mautical Institute
PDF
A comparative study of natural language inference in Swahili using monolingua...
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
August Patch Tuesday
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Tartificialntelligence_presentation.pptx
PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Enhancing emotion recognition model for a student engagement use case through...
PDF
project resource management chapter-09.pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Encapsulation theory and applications.pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
MIND Revenue Release Quarter 2 2025 Press Release
DP Operators-handbook-extract for the Mautical Institute
A comparative study of natural language inference in Swahili using monolingua...
Group 1 Presentation -Planning and Decision Making .pptx
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
August Patch Tuesday
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Tartificialntelligence_presentation.pptx
A comparative analysis of optical character recognition models for extracting...
cloud_computing_Infrastucture_as_cloud_p
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
Building Integrated photovoltaic BIPV_UPV.pdf
Enhancing emotion recognition model for a student engagement use case through...
project resource management chapter-09.pdf
Encapsulation_ Review paper, used for researhc scholars
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Digital-Transformation-Roadmap-for-Companies.pptx
Encapsulation theory and applications.pdf

Bowling Game Kata in C# Adapted

  • 1. Bowling Game KataAdapted for C# and nUnitBy Dan Stewart (with modifications by Mike Clement)dan@stewshack.commike@softwareontheside.com
  • 2. Scoring Bowling.The game consists of 10 frames as shown above. In each frame the player has two opportunities to knock down 10 pins. The score for the frame is the total number of pins knocked down, plus bonuses for strikes and spares.A spare is when the player knocks down all 10 pins in two tries. The bonus for that frame is the number of pins knocked down by the next roll. So in frame 3 above, the score is 10 (the total number knocked down) plus a bonus of 5 (the number of pins knocked down on the next roll.)A strike is when the player knocks down all 10 pins on his first try. The bonus for that frame is the value of the next two balls rolled.In the tenth frame a player who rolls a spare or strike is allowed to roll the extra balls to complete the frame. However no more than three balls can be rolled in tenth frame.
  • 3. A quick design sessionClearly we need the Game class.
  • 4. A quick design sessionA game has 10 frames.
  • 5. A quick design sessionA frame has 1 or two rolls.
  • 6. A quick design sessionThe tenth frame has two or three rolls.It is different from all the other frames.
  • 7. A quick design sessionThe score function mustinclude all the frames, and calculate all their scores.
  • 8. A quick design sessionThe score for a spare or a strike depends on the frame’s successor
  • 9. Begin.Create a class library named BowlingGameKata
  • 10. Begin.Add a test fixture named BowlingGameTests to the projectusingNUnit.Framework;namespaceBowlingGameKata{[TestFixture]publicclassBowlingGameTests{ [Test]publicvoidGutterGameTest() { } }}
  • 12. The first test.namespaceBowlingGameKata{publicclassGame { }}[Test]publicvoidGutterGameTest(){ Game g = new Game();}
  • 13. The first test.[Test]publicvoidGutterGameTest(){ Game g = new Game();}publicclassGame{}
  • 14. The first test.[Test]publicvoidGutterGameTest(){ Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0); }}publicclassGame{}
  • 15. The first test.public class Game{ publicvoid Roll(int p){ thrownewSystem.NotImplementedException();}}[Test]publicvoidGutterGameTest(){ Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0); }}
  • 16. The first test.[Test]publicvoidGutterGameTest(){ Gameg = newGame();for(int i = 0; i < 20; i++){g.Roll(0);}Assert.That(g.Score(), Is.EqualTo(0));}public class Game{ publicvoid Roll(int p){ thrownewSystem.NotImplementedException(); }}
  • 17. The first test.[Test]publicvoidGutterGameTest(){ Gameg = newGame();for(int i = 0; i < 20; i++){g.Roll(0);}Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{ publicvoid Roll(int p) {thrownew System.NotImplementedException(); }publicobject Score(){thrownew System.NotImplementedException(); }}Failed GutterGameTestthrew exception
  • 18. The first test.[Test]publicvoidGutterGameTest(){ Gameg = newGame();for(int i = 0; i < 20; i++) {g.Roll(0); }Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
  • 19. The Second test.[Test]publicvoidAllOnesTest(){ Gameg = newGame(); for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
  • 20. The Second test.- Game creation is duplicated- roll loop is duplicated[Test]publicvoidAllOnesTest(){ Gameg = newGame(); for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins) { }publicintScore() {returnscore; }}
  • 21. The Second test.- Game creation is duplicated- roll loop is duplicated[Test]publicvoidAllOnesTest(){ Gameg = newGame(); for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins){}publicintScore(){return score; }}Assert.AreEqual failed. Expected:<20>. Actual:<0>.
  • 22. The Second test.- roll loop is duplicatedprivateGame g;[SetUp]publicvoidSetup() { g = newGame();}[Test]publicvoidGutterGameTest(){for(int i = 0; i < 20; i++) {g.Roll(0); }Assert.That(g.Score(), Is.EqualTo(0));}[Test]publicvoidAllOnesTest(){for(int i = 0; i < 20; i++) {g.Roll(1); }Assert.That(g.Score(), Is.EqualTo(20));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}
  • 23. The Second test.- roll loop is duplicated[Test]publicvoidGutterGameTest(){int rolls = 20;intpins = 0;for(int i = 0; i < rolls; i++){g.Roll(pins);}Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}
  • 24. The Second test.- roll loop is duplicated[Test]publicvoidGutterGameTest(){int rolls = 20;intpins = 0;RollMany(rolls, pins);for(int i = 0; i < rolls; i++) {g.Roll(pins); }Assert.That(g.Score(), Is.EqualTo(0));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}
  • 25. The Second test.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}[Test]publicvoidGutterGameTest(){RollMany(20, 0);Assert.That(g.Score(), Is.EqualTo(0));}privatevoidRollMany(introlls, int pins){ for(int i = 0; i < rolls; i++) {g.Roll(pins); }}
  • 26. The Second test.[Test]publicvoidGutterGameTest(){RollMany(20, 0);Assert.That(g.Score(), Is.EqualTo(0));}[Test]publicvoidAllOnesTest(){RollMany(20, 1);Assert.That(g.Score(), Is.EqualTo(20));}privatevoidRollMany(int rolls, int pins){ for(int i = 0; i < rolls; i++) {g.Roll(pins); }}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}
  • 27. The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 28. The Third test.- ugly comment in test.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}tempted to use flag to remember previous roll. So design must be wrong.Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 29. The Third test.- ugly comment in test.Roll() calculates score, but name does not imply that.publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.AreEqual(16, g.Score);}Score() does not calculate score, but name implies that it does.Design is wrong. Responsibilities are misplaced.Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 30. The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{privateint score;publicvoid Roll(int pins){score += pins;}publicint Score(){return score; }}
  • 31. The Third test.- ugly comment in test.publicclassGame{privateint score;privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;score += pins;}publicint Score(){return score; }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}
  • 32. The Third test.- ugly comment in test.publicclassGame{ privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score; }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));}
  • 33. The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicclassGame{ privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score; }}Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 34. The Third test.- ugly comment in test.publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++) { // spare if(rolls[i] + rolls[i+1] == 10){score += ...}score += rolls[i];}return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}This isn’t going to work because i might not refer to the first ball of the frame.Design is still wrong.Need to walk through array two balls (one frame) at a time.Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 35. The Third test.- ugly comment in test.publicclassGame{ privateint[] rolls = newint[21];privateint currentRoll;publicvoid Roll(int pins){rolls[currentRoll++] = pins;}publicint Score(){int score = 0;for (int i = 0; i < rolls.Length; i++){score += rolls[i];}return score; }}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));Assert.Inconclusive();}
  • 36. The Third test.- ugly comment in test.publicint Score(){int score = 0;inti = 0;for (int frame = 0; frame < 10; frame++){ score += rolls[i] + rolls[i + 1]; i+= 2;}returnscore;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);//Assert.That(g.Score(), Is.EqualTo(16));Assert.Inconclusive();}
  • 37. The Third test.- ugly comment in test.[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}publicint Score(){int score = 0;int i = 0;for (int frame = 0; frame < 10; frame++) { score += rolls[i] + rolls[i + 1]; i += 2; }return score;}Failed Assert.AreEqual Expected:<16>. Actual:<13>
  • 38. The Third test.- ugly comment in test.publicint Score(){int score = 0;inti = 0;for (int frame = 0; frame < 10; frame++){// spareif (rolls[i] + rolls[i + 1] == 10){score += 10 + rolls[i + 2];i += 2;}else{ score += rolls[i] + rolls[i + 1]; i += 2; } }return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
  • 39. The Third test.ugly comment in test.
  • 40. ugly comment in conditional.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){// spareif (rolls[roll] + rolls[roll + 1] == 10){score += 10 + rolls[roll + 2];roll += 2;}else{ score += rolls[roll] + rolls[roll + 1]; roll += 2; } }return score;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
  • 41. The Third test.- ugly comment in test.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){ if(IsSpare(roll)) { score += 10 + rolls[roll + 2]; roll += 2; }else { score += rolls[roll] + rolls[roll + 1]; roll += 2;} }returnscore;}privateboolIsSpare(int roll){ returnrolls[roll] + rolls[roll + 1] == 10;}[Test]publicvoidOneSpareTest(){g.Roll(5);g.Roll(5); // spareg.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}
  • 42. The Third test.[Test]publicvoidOneSpareTest(){RollSpare();g.Roll(3);RollMany(17, 0);Assert.That(g.Score(), Is.EqualTo(16));}privatevoidRollSpare(){g.Roll(5);g.Roll(5);}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){ if(IsSpare(roll)) { score += 10 + rolls[roll + 2]; roll += 2; }else { score += rolls[roll] + rolls[roll + 1]; roll += 2; }}returnscore;}privateboolIsSpare(int roll){ returnrolls[roll] + rolls[roll + 1] == 10;}
  • 43. The Fourth test.- ugly comment in OneStrikeTest.[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){ if(IsSpare(roll)){ score += 10 + rolls[roll + 2];}else{ score += rolls[roll] + rolls[roll + 1];}roll += 2;}returnscore;}privatebool IsSpare(int roll){ returnrolls[roll] + rolls[roll + 1] == 10;}Failed Assert.AreEqual Expected:<24>. Actual:<17>
  • 44. The Fourth test.ugly comment in OneStrikeTest.
  • 45. ugly comment in conditional.
  • 46. ugly expressions.publicint Score(){ intscore = 0;introll = 0;for(int frame = 0; frame < 10; frame++){if(rolls[roll] == 10) // strike{ score += 10 + rolls[roll + 1] + rolls[roll + 2];roll++;}elseif (IsSpare(roll)){ score += 10 + rolls[roll + 2];roll += 2;}else{ score += rolls[roll] + rolls[roll + 1];roll += 2;} } returnscore;}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}
  • 47. The Fourth test.ugly comment in OneStrikeTest.
  • 48. ugly comment in conditional.publicint Score(){ intscore = 0;introll = 0;for(int frame = 0; frame < 10; frame++){if(rolls[roll] == 10) // strike{ score += 10 + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){ score += 10 + SpareBonus(roll);roll += 2;}else{ score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}privateint SumOfBallsInFrame(int roll){ returnrolls[roll] + rolls[roll + 1];}privateint SpareBonus(int roll){ returnrolls[roll + 2];}privateint StrikeBonus(int roll){ returnrolls[roll + 1] + rolls[roll + 2];}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}
  • 49. The Fourth test.- ugly comment in OneStrikeTest.publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){if(IsStrike(roll)){ score += 10 + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){score += 10+ SpareBonus(roll);roll += 2;}else{ score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}privatebool IsStrike(int roll){ returnrolls[roll] == 10;}[Test]publicvoidOneStrikeTest(){g.Roll(10); // strikeg.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}
  • 50. The Fourth test.[Test]publicvoidOneStrikeTest(){RollStrike();g.Roll(3);g.Roll(4);RollMany(16, 0);Assert.That(g.Score(), Is.EqualTo(24));}privatevoidRollStrike(){g.Roll(10);}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){if(IsStrike(roll)){ score += 10 + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){score += 10+ SpareBonus(roll);roll += 2;}else{ score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}
  • 51. The Fifth test.[Test]publicvoidPerfectGameTest(){RollMany(12, 10);Assert.That(g.Score(), Is.EqualTo(300));}publicint Score(){int score = 0;int roll = 0;for (int frame = 0; frame < 10; frame++){if(IsStrike(roll)){ score += 10 + StrikeBonus(roll);roll++;}elseif (IsSpare(roll)){score += 10+ SpareBonus(roll);roll += 2;}else{ score += SumOfBallsInFrame(roll);roll += 2;}}returnscore;}

Editor's Notes

  • #50: I would like to thank Uncle Bob Martin and Object Mentor for the bowling game kata.