From 3f7b81743c15b36ca0635d148ff3ea2ede8f55c8 Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Fri, 2 Jan 2026 01:36:38 -0800 Subject: [PATCH 01/17] bowling - inline test functions setUp and rollMany --- .config.json.swo | Bin 0 -> 20480 bytes config.json | 8 + exercises/practice/bowling/.meta/config.json | 3 +- exercises/practice/bowling/BowlingTest.php | 1326 +++++++++++++++--- 4 files changed, 1146 insertions(+), 191 deletions(-) create mode 100644 .config.json.swo diff --git a/.config.json.swo b/.config.json.swo new file mode 100644 index 0000000000000000000000000000000000000000..181d58c71bd35ae3cdb9e92ca5cdd2fe5fe8407b GIT binary patch literal 20480 zcmeI4d#oKr9mfw3vGP>p4-^vCMIaca?E8U8AV^cN(2H$(1j)_p&g{9{?%6%v-P86K z%2PB%Kn28DpHc7+QHU`CixMLxLaK>G_=E6BRE&W{LgEWb5d6+LyXWqnyWUe;ESl^l zpPqB~H?wE9@luORPP;!^69USlPbbfg4rQ!OYE$b{hq|=GQXkMJ2c8GG> zY()Ec(qF3VHKO3@d<#$gFzcP}CvgyVm#@!~c&S>gtyQ2^V4oEjK?QUxmHA{=F0SHwyc0Mg23229@;>F3y+sT@&`#C$4|l zL8A&~{oRHAOT~3wny|lC*l#TC^TiLA^H@;`|rL154+*s#> zu)iXX(mwjD{kK)1RiIU%RiIU%RiIU%RiIU%RiIU%RiIVizoP(UozCI7^qhE~M*P2g zKY#P6PUj`?H24+xDfk+=4s^lAU=_%Z>~t7d4K#2(c>Rb@=O5sY;Bl}MJOJ(nH-j5M z4%UH-z$d_o;COH-cm)l53H%8>2_69tfp3EpoB=)x4g;d`FC5nC>;k_8JHU3(2M&DWk;-Q_+Z^5JBUhrM89b5xE@G)=GOT8EQiobxVEC(hC|rSprJ-ro!%(@a8bk{elNgR^5zjDfVk^{eEyp*R=QW9TZkW$YtAhaJq-riD^I;}Q-MsgL zm2Np!Y>#!>MAMLZ5hoFkyZIcUX?M`$F(nHV+ zG{+2>MvTCOH+hyxT-&vY>uQWKlRH$cO?{;>mxeJ*He;|$Yv!|@_nNeUc~pjE^)h=e z&v3lqa&b<#EI7m-OXMX<#A#gdr73=+I=*3Z+arOe8^mCWLOjdW@${gktJ>VeOjW)0 zQl4|-m`3yQDVcOW5)z}ln7OMHPw@<)qmmg3n+m>bN?{Z(elU!k3L`Lx5G(~Tl`ph$UKrGX7iNPVYr`rbp^gJ_AEO=_;IGqW%Zl%&pSnZ2)i1vkz z^cQUJny8Cs#ia))vphv{u};w~56c#&`NXAmK$vL;y6>^TV70lt^uCp0cP{hi;Ox?x z&79|RoTivS8@w-TFuxsn7LUBj+NJUp&hQ_G?$QdF%(eoRY9w$Jj~LX^h@;wg;+dMJ zE3R!Y+W4@;3L&Io_^ldbewYmKg=VxH*H(F@gWySCGmQi&J+)ZD$wiLwa2X^@6sw3U zi$NhT$1;kFOypi4E4AhQx&CN^5*3H17B2(gSXA}2A{m3)@7 z5DV1e=VUZ26U*Tu4nP2WdaaxRm*6*cX$QRJKcE zJPW%qXHq{6dzkd1c_~OzX*2g=+Qg%zFBTumrSo%f$t31d5=aqGJ4kN5xEiaU9^c<+A{ zpZ9}1z|BC!|F?k8fV06e@Csu7zXLnKJ>Uyq6NrEht^j9)lfcV}?>_||1m6PJfc4;V zuo|oYX91B9unatb`2K@nJGdV7z~x{ySOLxgM}t2jzJDM13fKZ>!KZ)@jsb^)1Hf*? z_n!q1gPTAERs##jU>W!u;`$=~{{(mp`~rL*+zQr#GrnVN7~>P(LJWS3ihix)vG)0<(~W+Kcybxn$j9SNo%|I z?4a} z1o6T}#Tst1<_8UtN=s#0~rQkaVeoX65R zc~1QeRePz(Mqwv#?W%p66qD&1`(b_<1}MgfEiU7XTS#ZIJi|f0k%39V2^dlQK=Wa= zHKj4JWd&R#7kY?PohCVgQ2}H{R0~Yg15?9XZC;>JHyH+aYXfY5x(j0J+zuSVsR?({ z43l__>qLVvf#UhxV~uGC=cGLZQ4>UPmdO60WuZk;>1jd@$DNoxW1(l#V{BPJjK_kUv;5!#37rFHTo9v*eZs1 zRw@=El$68>upz)$kzlIJsg=U}_TaWGTj7Y96W`G>CaKGagFy=C3v|^qP0szsF)8$t z&P@h!WB!j2jrcX|H08W7-yCLqc9d`jRVwKy@T$EWoA01dSl(!=X%H3Jk`M~tTm#t{ zs_NRdp$5p#Yjmtjip(u()i85Qx_Ch299d=6{w}BW$t(4cg}sd?^+)6Rgame = new Game(); - } - /** * uuid 656ae006-25c2-438c-a549-f338e7ec7441 */ #[TestDox('should be able to score a game with all zeros')] public function testShouldBeAbleToScoreAGameWithAllZeros(): void { - $this->rollMany(20, 0); - - $this->assertEquals(0, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(0, $game->score()); } /** @@ -41,28 +73,49 @@ public function testShouldBeAbleToScoreAGameWithAllZeros(): void #[TestDox('should be able to score a game with no strikes or spares')] public function testShouldBeAbleToScoreAGameWithNoStrikesOrSpares(): void { - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - $this->game->roll(3); - $this->game->roll(6); - - $this->assertEquals(90, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(3); + $game->roll(6); + + // Frame 2 + $game->roll(3); + $game->roll(6); + + // Frame 3 + $game->roll(3); + $game->roll(6); + + // Frame 4 + $game->roll(3); + $game->roll(6); + + // Frame 5 + $game->roll(3); + $game->roll(6); + + // Frame 6 + $game->roll(3); + $game->roll(6); + + // Frame 7 + $game->roll(3); + $game->roll(6); + + // Frame 8 + $game->roll(3); + $game->roll(6); + + // Frame 9 + $game->roll(3); + $game->roll(6); + + // Frame 10 + $game->roll(3); + $game->roll(6); + + $this->assertEquals(90, $game->score()); } /** @@ -71,11 +124,49 @@ public function testShouldBeAbleToScoreAGameWithNoStrikesOrSpares(): void #[TestDox('a spare followed by zeros is worth ten points')] public function testASpareFollowedByZerosIsWorthTenPoints(): void { - $this->game->roll(6); - $this->game->roll(4); - $this->rollMany(18, 0); - - $this->assertEquals(10, $this->game->score()); + $game = new Game(); + + // Frame 1 - Spare (6 + 4 = 10) + $game->roll(6); + $game->roll(4); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(10, $game->score()); } /** @@ -84,12 +175,49 @@ public function testASpareFollowedByZerosIsWorthTenPoints(): void #[TestDox('points scored in the roll after a spare are counted twice')] public function testPointsScoredInTheRollAfterASpareAreCountedTwice(): void { - $this->game->roll(6); - $this->game->roll(4); - $this->game->roll(3); - $this->rollMany(17, 0); - - $this->assertEquals(16, $this->game->score()); + $game = new Game(); + + // Frame 1 - Spare (6 + 4 = 10) + $game->roll(6); + $game->roll(4); + + // Frame 2 + $game->roll(3); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(16, $game->score()); } /** @@ -98,14 +226,49 @@ public function testPointsScoredInTheRollAfterASpareAreCountedTwice(): void #[TestDox('consecutive spares each get a one roll bonus')] public function testConsecutiveSparesEachGetAOneRollBonus(): void { - $this->game->roll(5); - $this->game->roll(5); - $this->game->roll(3); - $this->game->roll(7); - $this->game->roll(4); - $this->rollMany(15, 0); - - $this->assertEquals(31, $this->game->score()); + $game = new Game(); + + // Frame 1 - Spare (5 + 5 = 10) + $game->roll(5); + $game->roll(5); + + // Frame 2 - Spare (3 + 7 = 10) + $game->roll(3); + $game->roll(7); + + // Frame 3 + $game->roll(4); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(31, $game->score()); } /** @@ -114,12 +277,50 @@ public function testConsecutiveSparesEachGetAOneRollBonus(): void #[TestDox('a spare in the last frame gets a one roll bonus that is counted once')] public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce(): void { - $this->rollMany(18, 0); - $this->game->roll(7); - $this->game->roll(3); - $this->game->roll(7); - - $this->assertEquals(17, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Spare (7 + 3 = 10) with bonus roll + $game->roll(7); + $game->roll(3); + $game->roll(7); // Bonus roll + + $this->assertEquals(17, $game->score()); } /** @@ -128,10 +329,48 @@ public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce(): vo #[TestDox('a strike earns ten points in a frame with a single roll')] public function testAStrikeEarnsTenPointsInFrameWithASingleRoll(): void { - $this->game->roll(10); - $this->rollMany(18, 0); + $game = new Game(); + + // Frame 1 - Strike + $game->roll(10); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); - $this->assertEquals(10, $this->game->score()); + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(10, $game->score()); } /** @@ -140,12 +379,48 @@ public function testAStrikeEarnsTenPointsInFrameWithASingleRoll(): void #[TestDox('points scored in the two rolls after a strike are counted twice as a bonus')] public function testPointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus(): void { - $this->game->roll(10); - $this->game->roll(5); - $this->game->roll(3); - $this->rollMany(16, 0); - - $this->assertEquals(26, $this->game->score()); + $game = new Game(); + + // Frame 1 - Strike + $game->roll(10); + + // Frame 2 + $game->roll(5); + $game->roll(3); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(26, $game->score()); } /** @@ -154,14 +429,46 @@ public function testPointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus #[TestDox('consecutive strikes each get the two roll bonus')] public function testConsecutiveStrikesEachGetTheTwoRollBonus(): void { - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(5); - $this->game->roll(3); - $this->rollMany(12, 0); - - $this->assertEquals(81, $this->game->score()); + $game = new Game(); + + // Frame 1 - Strike + $game->roll(10); + + // Frame 2 - Strike + $game->roll(10); + + // Frame 3 - Strike + $game->roll(10); + + // Frame 4 + $game->roll(5); + $game->roll(3); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $this->assertEquals(81, $game->score()); } /** @@ -170,12 +477,50 @@ public function testConsecutiveStrikesEachGetTheTwoRollBonus(): void #[TestDox('a strike in the last frame gets a two roll bonus that is counted once')] public function testAStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce(): void { - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(7); - $this->game->roll(1); - - $this->assertEquals(18, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(7); + $game->roll(1); + + $this->assertEquals(18, $game->score()); } /** @@ -184,12 +529,50 @@ public function testAStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce(): v #[TestDox('rolling a spare with the two roll bonus does not get a bonus roll')] public function testAStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGetABonus(): void { - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(7); - $this->game->roll(3); - - $this->assertEquals(20, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(7); + $game->roll(3); + + $this->assertEquals(20, $game->score()); } /** @@ -198,12 +581,50 @@ public function testAStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGe #[TestDox('strikes with the two roll bonus do not get bonus rolls')] public function testRollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll(): void { - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(10); - - $this->assertEquals(30, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(10); + $game->roll(10); + + $this->assertEquals(30, $game->score()); } /** @@ -212,13 +633,49 @@ public function testRollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll(): void #[TestDox('last two strikes followed by only last bonus with non strike points')] public function testLastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints(): void { - $this->rollMany(16, 0); - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(0); - $this->game->roll(1); - - $this->assertEquals(31, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 - Strike + $game->roll(10); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(0); + $game->roll(1); + + $this->assertEquals(31, $game->score()); } /** @@ -227,12 +684,50 @@ public function testLastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints(): #[TestDox('a strike with the one roll bonus after a spare in the last frame does not get a bonus')] public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls(): void { - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(7); - $this->game->roll(3); - - $this->assertEquals(20, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Spare (10) with bonus roll + $game->roll(10); + $game->roll(7); + $game->roll(3); + + $this->assertEquals(20, $game->score()); } /** @@ -241,9 +736,41 @@ public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls(): void #[TestDox('all strikes is a perfect gam')] public function testAllStrikesIsAPerfectGame(): void { - $this->rollMany(12, 10); + $game = new Game(); - $this->assertEquals(300, $this->game->score()); + // Frame 1 - Strike + $game->roll(10); + + // Frame 2 - Strike + $game->roll(10); + + // Frame 3 - Strike + $game->roll(10); + + // Frame 4 - Strike + $game->roll(10); + + // Frame 5 - Strike + $game->roll(10); + + // Frame 6 - Strike + $game->roll(10); + + // Frame 7 - Strike + $game->roll(10); + + // Frame 8 - Strike + $game->roll(10); + + // Frame 9 - Strike + $game->roll(10); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(10); + $game->roll(10); + + $this->assertEquals(300, $game->score()); } /** @@ -252,9 +779,11 @@ public function testAllStrikesIsAPerfectGame(): void #[TestDox('rolls cannot score negative points')] public function testRollsCanNotScoreNegativePoints(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->game->roll(-1); + $game->roll(-1); } /** @@ -263,11 +792,11 @@ public function testRollsCanNotScoreNegativePoints(): void #[TestDox('a roll cannot score more than 10 points')] public function testARollCanNotScoreMoreThan10Points(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->game->roll(11); - $this->rollMany(19, 0); - $this->game->score(); + $game->roll(11); } /** @@ -276,12 +805,13 @@ public function testARollCanNotScoreMoreThan10Points(): void #[TestDox('two rolls in a frame cannot score more than 10 points')] public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->game->roll(5); - $this->game->roll(6); - $this->rollMany(18, 0); - $this->game->score(); + // Frame 1 + $game->roll(5); + $game->roll(6); } /** @@ -290,13 +820,51 @@ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void #[TestDox('bonus roll after a strike in the last frame cannot score more than 10 points')] public function testBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points(): void { - $this->expectException(Exception::class); + $game = new Game(); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(11); + $this->expectException(Exception::class); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(11); + + $game->score(); } @@ -306,14 +874,52 @@ public function testBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Poi #[TestDox('two bonus rolls after a strike in the last frame cannot score more than 10 points')] public function testTwoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points(): void { - $this->expectException(Exception::class); + $game = new Game(); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(5); - $this->game->roll(6); + $this->expectException(Exception::class); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(5); + $game->roll(6); + + $game->score(); } /** @@ -322,12 +928,50 @@ public function testTwoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10 #[TestDox('two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike')] public function testTwoBonusRollsAfterAStrikeInTheLastFramCanScoreMoreThan10PointsIfOneIsAStrike(): void { - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(6); - - $this->assertEquals(26, $this->game->score()); + $game = new Game(); + + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(10); + $game->roll(6); + + $this->assertEquals(26, $game->score()); } /** @@ -336,13 +980,52 @@ public function testTwoBonusRollsAfterAStrikeInTheLastFramCanScoreMoreThan10Poin #[TestDox('the second bonus rolls after a strike in the last frame cannot be a strike if the first one is not a strike')] public function testTheSecondBonusRollsAfterAStrikeInTheLastFrameCannotBeAStrikeIfTheFirstOneIsNotAStrike(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(6); - $this->game->roll(10); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(6); + $game->roll(10); + + $game->score(); } /** @@ -351,13 +1034,50 @@ public function testTheSecondBonusRollsAfterAStrikeInTheLastFrameCannotBeAStrike #[TestDox('second bonus roll after a strike in the last frame cannot score more than 10 points')] public function testSecondBonusRollAfterAStrikeInTheLastFrameCannotScoreMoreThan10Points(): void { + $game = new Game(); $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(10); - $this->game->roll(11); - - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(10); + $game->roll(11); + + $game->score(); } /** @@ -366,9 +1086,11 @@ public function testSecondBonusRollAfterAStrikeInTheLastFrameCannotScoreMoreThan #[TestDox('an unstarted game cannot be scored')] public function testAnUnstartedGameCanNotBeScored(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->game->score(); + $game->score(); } /** @@ -377,11 +1099,14 @@ public function testAnUnstartedGameCanNotBeScored(): void #[TestDox('an incomplete game cannot be scored')] public function testAnIncompleteGameCanNotBeScored(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->game->roll(0); - $this->game->roll(0); - $this->game->score(); + $game->roll(0); + $game->roll(0); + + $game->score(); } /** @@ -390,11 +1115,53 @@ public function testAnIncompleteGameCanNotBeScored(): void #[TestDox('cannot roll if game already has ten frames')] public function testCannotRollIfGameAlreadyHasTenFrames(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(20, 0); - $this->game->roll(0); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); + + $game->roll(0); + + $game->score(); } /** @@ -403,11 +1170,50 @@ public function testCannotRollIfGameAlreadyHasTenFrames(): void #[TestDox('bonus rolls for a strike in the last frame must be rolled before score can be calculated')] public function testBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + + $game->score(); } /** @@ -416,12 +1222,51 @@ public function testBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCan #[TestDox('both bonus rolls for a strike in the last frame must be rolled before score can be calculated')] public function testBothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(10); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(10); + + $game->score(); } /** @@ -430,12 +1275,51 @@ public function testBothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScor #[TestDox('bonus roll for a spare in the last frame must be rolled before score can be calculated')] public function testBonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(7); - $this->game->roll(3); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Spare with bonus roll + $game->roll(7); + $game->roll(3); + + $game->score(); } /** @@ -444,14 +1328,53 @@ public function testBonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBe #[TestDox('cannot roll after bonus roll for spare')] public function testCannotRollAfterBonusRollForSpare(): void { + $game = new Game(); + $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(7); - $this->game->roll(3); - $this->game->roll(2); - $this->game->roll(2); - $this->game->score(); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Spare with bonus roll + $game->roll(7); + $game->roll(3); + $game->roll(2); + $game->roll(2); + + $game->score(); } /** @@ -460,30 +1383,53 @@ public function testCannotRollAfterBonusRollForSpare(): void #[TestDox('cannot roll after bonus rolls for strike')] public function testCannotRollAfterBonusRollsForStrike(): void { - $this->expectException(Exception::class); - $this->rollMany(18, 0); - $this->game->roll(10); - $this->game->roll(3); - $this->game->roll(2); - $this->game->roll(2); - - $this->game->score(); - } + $game = new Game(); - private function rollStrike(): void - { - $this->game->roll(10); - } + $this->expectException(Exception::class); - private function rollSpare(): void - { - $this->rollMany(2, 5); + // Frame 1 + $game->roll(0); + $game->roll(0); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 - Strike with two bonus rolls + $game->roll(10); + $game->roll(3); + $game->roll(2); + $game->roll(2); + + $game->score(); } - private function rollMany($n, $pins): void - { - for ($i = 0; $i < $n; $i++) { - $this->game->roll($pins); - } - } } From b9217feb4b91246d2c8080d4b7fde267d27fb580 Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Fri, 2 Jan 2026 01:39:25 -0800 Subject: [PATCH 02/17] delete --- .config.json.swo | Bin 20480 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .config.json.swo diff --git a/.config.json.swo b/.config.json.swo deleted file mode 100644 index 181d58c71bd35ae3cdb9e92ca5cdd2fe5fe8407b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI4d#oKr9mfw3vGP>p4-^vCMIaca?E8U8AV^cN(2H$(1j)_p&g{9{?%6%v-P86K z%2PB%Kn28DpHc7+QHU`CixMLxLaK>G_=E6BRE&W{LgEWb5d6+LyXWqnyWUe;ESl^l zpPqB~H?wE9@luORPP;!^69USlPbbfg4rQ!OYE$b{hq|=GQXkMJ2c8GG> zY()Ec(qF3VHKO3@d<#$gFzcP}CvgyVm#@!~c&S>gtyQ2^V4oEjK?QUxmHA{=F0SHwyc0Mg23229@;>F3y+sT@&`#C$4|l zL8A&~{oRHAOT~3wny|lC*l#TC^TiLA^H@;`|rL154+*s#> zu)iXX(mwjD{kK)1RiIU%RiIU%RiIU%RiIU%RiIU%RiIVizoP(UozCI7^qhE~M*P2g zKY#P6PUj`?H24+xDfk+=4s^lAU=_%Z>~t7d4K#2(c>Rb@=O5sY;Bl}MJOJ(nH-j5M z4%UH-z$d_o;COH-cm)l53H%8>2_69tfp3EpoB=)x4g;d`FC5nC>;k_8JHU3(2M&DWk;-Q_+Z^5JBUhrM89b5xE@G)=GOT8EQiobxVEC(hC|rSprJ-ro!%(@a8bk{elNgR^5zjDfVk^{eEyp*R=QW9TZkW$YtAhaJq-riD^I;}Q-MsgL zm2Np!Y>#!>MAMLZ5hoFkyZIcUX?M`$F(nHV+ zG{+2>MvTCOH+hyxT-&vY>uQWKlRH$cO?{;>mxeJ*He;|$Yv!|@_nNeUc~pjE^)h=e z&v3lqa&b<#EI7m-OXMX<#A#gdr73=+I=*3Z+arOe8^mCWLOjdW@${gktJ>VeOjW)0 zQl4|-m`3yQDVcOW5)z}ln7OMHPw@<)qmmg3n+m>bN?{Z(elU!k3L`Lx5G(~Tl`ph$UKrGX7iNPVYr`rbp^gJ_AEO=_;IGqW%Zl%&pSnZ2)i1vkz z^cQUJny8Cs#ia))vphv{u};w~56c#&`NXAmK$vL;y6>^TV70lt^uCp0cP{hi;Ox?x z&79|RoTivS8@w-TFuxsn7LUBj+NJUp&hQ_G?$QdF%(eoRY9w$Jj~LX^h@;wg;+dMJ zE3R!Y+W4@;3L&Io_^ldbewYmKg=VxH*H(F@gWySCGmQi&J+)ZD$wiLwa2X^@6sw3U zi$NhT$1;kFOypi4E4AhQx&CN^5*3H17B2(gSXA}2A{m3)@7 z5DV1e=VUZ26U*Tu4nP2WdaaxRm*6*cX$QRJKcE zJPW%qXHq{6dzkd1c_~OzX*2g=+Qg%zFBTumrSo%f$t31d5=aqGJ4kN5xEiaU9^c<+A{ zpZ9}1z|BC!|F?k8fV06e@Csu7zXLnKJ>Uyq6NrEht^j9)lfcV}?>_||1m6PJfc4;V zuo|oYX91B9unatb`2K@nJGdV7z~x{ySOLxgM}t2jzJDM13fKZ>!KZ)@jsb^)1Hf*? z_n!q1gPTAERs##jU>W!u;`$=~{{(mp`~rL*+zQr#GrnVN7~>P(LJWS3ihix)vG)0<(~W+Kcybxn$j9SNo%|I z?4a} z1o6T}#Tst1<_8UtN=s#0~rQkaVeoX65R zc~1QeRePz(Mqwv#?W%p66qD&1`(b_<1}MgfEiU7XTS#ZIJi|f0k%39V2^dlQK=Wa= zHKj4JWd&R#7kY?PohCVgQ2}H{R0~Yg15?9XZC;>JHyH+aYXfY5x(j0J+zuSVsR?({ z43l__>qLVvf#UhxV~uGC=cGLZQ4>UPmdO60WuZk;>1jd@$DNoxW1(l#V{BPJjK_kUv;5!#37rFHTo9v*eZs1 zRw@=El$68>upz)$kzlIJsg=U}_TaWGTj7Y96W`G>CaKGagFy=C3v|^qP0szsF)8$t z&P@h!WB!j2jrcX|H08W7-yCLqc9d`jRVwKy@T$EWoA01dSl(!=X%H3Jk`M~tTm#t{ zs_NRdp$5p#Yjmtjip(u()i85Qx_Ch299d=6{w}BW$t(4cg}sd?^+)6R Date: Fri, 2 Jan 2026 01:42:40 -0800 Subject: [PATCH 03/17] update config.json --- config.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config.json b/config.json index dc82ef67..2c4111f1 100644 --- a/config.json +++ b/config.json @@ -1314,14 +1314,6 @@ "practices": [], "prerequisites": [], "difficulty": 5 - }, - { - "slug": "inline-test", - "name": "inline-test", - "uuid": "3d2caa7a-28c2-4266-8b50-fec285836d88", - "practices": [], - "prerequisites": [], - "difficulty": 1 } ], "foregone": [ From eee65f8c59e1d5d60f3e56de0fc37cc8b4cf7f50 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:20:17 -0500 Subject: [PATCH 04/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 340a1259..6d05aecc 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -722,7 +722,7 @@ public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls(): void $game->roll(0); $game->roll(0); - // Frame 10 - Spare (10) with bonus roll + // Frame 10 - Strike with spare as bonus rolls $game->roll(10); $game->roll(7); $game->roll(3); From 0b50c1d72d238d74ffd5bdd024ee3cb3923bb897 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:20:34 -0500 Subject: [PATCH 05/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 6d05aecc..33266689 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -684,7 +684,7 @@ public function testLastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints(): #[TestDox('a strike with the one roll bonus after a spare in the last frame does not get a bonus')] public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls(): void { - $game = new Game(); + $game = new Game(); // Frame 1 $game->roll(0); From 521d89bbddf4557bd3116bc5a37f2f9bfc71d900 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:20:40 -0500 Subject: [PATCH 06/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 33266689..ddaf9f9f 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -633,7 +633,7 @@ public function testRollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll(): void #[TestDox('last two strikes followed by only last bonus with non strike points')] public function testLastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints(): void { - $game = new Game(); + $game = new Game(); // Frame 1 $game->roll(0); From b690b449f9a1c859de91dff440c7a0d621e8e96d Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:20:51 -0500 Subject: [PATCH 07/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index ddaf9f9f..43182f4c 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -315,7 +315,7 @@ public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce(): vo $game->roll(0); $game->roll(0); - // Frame 10 - Spare (7 + 3 = 10) with bonus roll + // Frame 10 - Spare with bonus roll $game->roll(7); $game->roll(3); $game->roll(7); // Bonus roll From 11689cdfa0d4237a6d8366065020ad1d9425cdeb Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:21:01 -0500 Subject: [PATCH 08/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 43182f4c..37d036a8 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -318,7 +318,7 @@ public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce(): vo // Frame 10 - Spare with bonus roll $game->roll(7); $game->roll(3); - $game->roll(7); // Bonus roll + $game->roll(7); $this->assertEquals(17, $game->score()); } From cba740385b3b07e2f7387975bb814cc6aeb9ee90 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:21:08 -0500 Subject: [PATCH 09/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 37d036a8..0387dd08 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -232,7 +232,7 @@ public function testConsecutiveSparesEachGetAOneRollBonus(): void $game->roll(5); $game->roll(5); - // Frame 2 - Spare (3 + 7 = 10) + // Frame 2 - Spare $game->roll(3); $game->roll(7); From fc10eb1f54206b2d04dd72b099b1a3797d8fa35a Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:21:19 -0500 Subject: [PATCH 10/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 0387dd08..11b0b52e 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -228,7 +228,7 @@ public function testConsecutiveSparesEachGetAOneRollBonus(): void { $game = new Game(); - // Frame 1 - Spare (5 + 5 = 10) + // Frame 1 - Spare $game->roll(5); $game->roll(5); From f914e5602fad504707481d5a3a5ab5eda4ccd773 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:21:26 -0500 Subject: [PATCH 11/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 11b0b52e..e1be2675 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -177,7 +177,7 @@ public function testPointsScoredInTheRollAfterASpareAreCountedTwice(): void { $game = new Game(); - // Frame 1 - Spare (6 + 4 = 10) + // Frame 1 - Spare $game->roll(6); $game->roll(4); From b89bf8f330ce4b271dd7b950b8e9acbe26e82da4 Mon Sep 17 00:00:00 2001 From: Lily Qin Date: Sat, 3 Jan 2026 02:21:35 -0500 Subject: [PATCH 12/17] Update exercises/practice/bowling/BowlingTest.php Co-authored-by: mk-mxp <55182845+mk-mxp@users.noreply.github.com> --- exercises/practice/bowling/BowlingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index e1be2675..a5cc3bf4 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -126,7 +126,7 @@ public function testASpareFollowedByZerosIsWorthTenPoints(): void { $game = new Game(); - // Frame 1 - Spare (6 + 4 = 10) + // Frame 1 - Spare $game->roll(6); $game->roll(4); From 728b459d21fd27d6d82efc51bba2d0a5f3950e83 Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Mon, 5 Jan 2026 00:02:20 -0800 Subject: [PATCH 13/17] update example.php --- exercises/practice/bowling/.meta/example.php | 39 +++++++++++++++++++- exercises/practice/bowling/BowlingTest.php | 36 ++++++++++++++++++ php | 0 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 php diff --git a/exercises/practice/bowling/.meta/example.php b/exercises/practice/bowling/.meta/example.php index b008f5fa..b1caceee 100644 --- a/exercises/practice/bowling/.meta/example.php +++ b/exercises/practice/bowling/.meta/example.php @@ -9,13 +9,50 @@ class Game { private $rolls = []; + private $currentFrame = 1; + private $rollsInFrame = 0; + private $firstRollPins = 0; public function roll($pins): void { if ($pins < 0 || $pins > 10) { throw new Exception('Pins must be between 0 and 10'); } - $this->rolls[] = $pins; + // For frames 1-9 + if ($this->currentFrame < 10) { + if ($this->rollsInFrame == 0) { + // First roll of frame + $this->firstRollPins = $pins; + $this->rollsInFrame = 1; + + if ($pins == 10) { // Strike + $this->currentFrame++; + $this->rollsInFrame = 0; + } + } else { + // Second roll of frame + if ($this->firstRollPins + $pins > 10) { + throw new Exception("Pin count exceeds pins on the lane"); + } + $this->currentFrame++; + $this->rollsInFrame = 0; + } + } else { + // Frame 10 special handling + if ($this->rollsInFrame == 0) { + $this->firstRollPins = $pins; + $this->rollsInFrame = 1; + } elseif ($this->rollsInFrame == 1) { + // Second roll in frame 10 + if ($this->firstRollPins < 10 && $this->firstRollPins + $pins > 10) { + throw new Exception("Pin count exceeds pins on the lane"); + } + $this->rollsInFrame = 2; + } else { + // Third roll in frame 10 (only valid after strike or spare) + $this->rollsInFrame = 3; + } + } } public function score() diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index a5cc3bf4..12b4e08e 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -812,6 +812,42 @@ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void // Frame 1 $game->roll(5); $game->roll(6); + + // Frame 2 + $game->roll(0); + $game->roll(0); + + // Frame 3 + $game->roll(0); + $game->roll(0); + + // Frame 4 + $game->roll(0); + $game->roll(0); + + // Frame 5 + $game->roll(0); + $game->roll(0); + + // Frame 6 + $game->roll(0); + $game->roll(0); + + // Frame 7 + $game->roll(0); + $game->roll(0); + + // Frame 8 + $game->roll(0); + $game->roll(0); + + // Frame 9 + $game->roll(0); + $game->roll(0); + + // Frame 10 + $game->roll(0); + $game->roll(0); } /** diff --git a/php b/php new file mode 100644 index 00000000..e69de29b From f8516a7ead55519ca07ea0786e46a8da687d9648 Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Mon, 5 Jan 2026 00:07:11 -0800 Subject: [PATCH 14/17] remove php --- php | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 php diff --git a/php b/php deleted file mode 100644 index e69de29b..00000000 From 825c0acc02dd3b768ec69b28c62c632dd3bc6b3f Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Tue, 6 Jan 2026 00:31:45 -0800 Subject: [PATCH 15/17] fix scoring --- exercises/practice/bowling/.meta/example.php | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/practice/bowling/.meta/example.php b/exercises/practice/bowling/.meta/example.php index b1caceee..da247ffb 100644 --- a/exercises/practice/bowling/.meta/example.php +++ b/exercises/practice/bowling/.meta/example.php @@ -53,6 +53,7 @@ public function roll($pins): void $this->rollsInFrame = 3; } } + $this->rolls[] = $pins; } public function score() From a33a3a4b5b256abdab461bf3a37d8167e3cfb55c Mon Sep 17 00:00:00 2001 From: lilyqin7 Date: Tue, 6 Jan 2026 11:44:26 -0800 Subject: [PATCH 16/17] fix style --- exercises/practice/bowling/.meta/example.php | 2 +- exercises/practice/bowling/BowlingTest.php | 315 +++++++++---------- 2 files changed, 158 insertions(+), 159 deletions(-) diff --git a/exercises/practice/bowling/.meta/example.php b/exercises/practice/bowling/.meta/example.php index da247ffb..9863ecb6 100644 --- a/exercises/practice/bowling/.meta/example.php +++ b/exercises/practice/bowling/.meta/example.php @@ -24,7 +24,7 @@ public function roll($pins): void // First roll of frame $this->firstRollPins = $pins; $this->rollsInFrame = 1; - + if ($pins == 10) { // Strike $this->currentFrame++; $this->rollsInFrame = 0; diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 12b4e08e..83a61b15 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -23,7 +23,7 @@ public static function setUpBeforeClass(): void public function testShouldBeAbleToScoreAGameWithAllZeros(): void { $game = new Game(); - + // Frame 1 $game->roll(0); $game->roll(0); @@ -39,27 +39,27 @@ public function testShouldBeAbleToScoreAGameWithAllZeros(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -125,43 +125,43 @@ public function testShouldBeAbleToScoreAGameWithNoStrikesOrSpares(): void public function testASpareFollowedByZerosIsWorthTenPoints(): void { $game = new Game(); - + // Frame 1 - Spare $game->roll(6); $game->roll(4); - + // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -180,7 +180,7 @@ public function testPointsScoredInTheRollAfterASpareAreCountedTwice(): void // Frame 1 - Spare $game->roll(6); $game->roll(4); - + // Frame 2 $game->roll(3); $game->roll(0); @@ -192,27 +192,27 @@ public function testPointsScoredInTheRollAfterASpareAreCountedTwice(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -235,35 +235,35 @@ public function testConsecutiveSparesEachGetAOneRollBonus(): void // Frame 2 - Spare $game->roll(3); $game->roll(7); - + // Frame 3 $game->roll(4); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -278,43 +278,43 @@ public function testConsecutiveSparesEachGetAOneRollBonus(): void public function testASpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce(): void { $game = new Game(); - + // Frame 1 $game->roll(0); $game->roll(0); - + // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Spare with bonus roll $game->roll(7); $game->roll(3); @@ -391,31 +391,31 @@ public function testPointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -447,23 +447,23 @@ public function testConsecutiveStrikesEachGetTheTwoRollBonus(): void // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -486,31 +486,31 @@ public function testAStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce(): v // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -538,31 +538,31 @@ public function testAStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGe // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -590,31 +590,31 @@ public function testRollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll(): void // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -642,31 +642,31 @@ public function testLastTwoStrikesFollowedByOnlyLastBonusWithNonStrikePoints(): // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 - Strike $game->roll(10); @@ -693,31 +693,31 @@ public function testStrikesWithTheTwoRollBonusDoNotGetBonusRolls(): void // Frame 2 $game->roll(0); $game->roll(0); - + // Frame 3 $game->roll(0); $game->roll(0); - + // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -809,7 +809,7 @@ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void $this->expectException(Exception::class); - // Frame 1 + // Frame 1 $game->roll(5); $game->roll(6); @@ -824,23 +824,23 @@ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -875,23 +875,23 @@ public function testBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Poi // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -929,23 +929,23 @@ public function testTwoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10 // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -981,23 +981,23 @@ public function testTwoBonusRollsAfterAStrikeInTheLastFramCanScoreMoreThan10Poin // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -1035,23 +1035,23 @@ public function testTheSecondBonusRollsAfterAStrikeInTheLastFrameCannotBeAStrike // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -1087,23 +1087,23 @@ public function testSecondBonusRollAfterAStrikeInTheLastFrameCannotScoreMoreThan // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); @@ -1152,7 +1152,7 @@ public function testAnIncompleteGameCanNotBeScored(): void public function testCannotRollIfGameAlreadyHasTenFrames(): void { $game = new Game(); - + $this->expectException(Exception::class); // Frame 1 @@ -1170,27 +1170,27 @@ public function testCannotRollIfGameAlreadyHasTenFrames(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 $game->roll(0); $game->roll(0); @@ -1225,27 +1225,27 @@ public function testBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCan // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Strike with two bonus rolls $game->roll(10); @@ -1277,27 +1277,27 @@ public function testBothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScor // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Strike with two bonus rolls $game->roll(10); $game->roll(10); @@ -1330,27 +1330,27 @@ public function testBonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBe // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Spare with bonus roll $game->roll(7); $game->roll(3); @@ -1383,27 +1383,27 @@ public function testCannotRollAfterBonusRollForSpare(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Spare with bonus roll $game->roll(7); $game->roll(3); @@ -1438,27 +1438,27 @@ public function testCannotRollAfterBonusRollsForStrike(): void // Frame 4 $game->roll(0); $game->roll(0); - + // Frame 5 $game->roll(0); $game->roll(0); - + // Frame 6 $game->roll(0); $game->roll(0); - + // Frame 7 $game->roll(0); $game->roll(0); - + // Frame 8 $game->roll(0); $game->roll(0); - + // Frame 9 $game->roll(0); $game->roll(0); - + // Frame 10 - Strike with two bonus rolls $game->roll(10); $game->roll(3); @@ -1467,5 +1467,4 @@ public function testCannotRollAfterBonusRollsForStrike(): void $game->score(); } - } From 0b2697c350a83f727f659d0ec68656ede33f4f5e Mon Sep 17 00:00:00 2001 From: mk-mxp <55182845+mk-mxp@users.noreply.github.com> Date: Sat, 10 Jan 2026 10:56:01 +0100 Subject: [PATCH 17/17] Ensure backward compatibility --- exercises/practice/bowling/BowlingTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/practice/bowling/BowlingTest.php b/exercises/practice/bowling/BowlingTest.php index 83a61b15..945fc284 100644 --- a/exercises/practice/bowling/BowlingTest.php +++ b/exercises/practice/bowling/BowlingTest.php @@ -848,6 +848,8 @@ public function testTwoRollsInAFrameCanNotScoreMoreThan10Points(): void // Frame 10 $game->roll(0); $game->roll(0); + + $game->score(); } /**