From 1ce5f7b3a7b05fe9f8ce89aecac5716687caf9a4 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 6 Apr 2022 23:07:35 +1000 Subject: [PATCH] Resolve play resolution helper methods --- 07_Basketball/csharp/Plays/HomeTeamPlay.cs | 108 ++++++++++-------- 07_Basketball/csharp/Plays/Play.cs | 10 +- .../csharp/Plays/VisitingTeamPlay.cs | 45 +++++--- 3 files changed, 93 insertions(+), 70 deletions(-) diff --git a/07_Basketball/csharp/Plays/HomeTeamPlay.cs b/07_Basketball/csharp/Plays/HomeTeamPlay.cs index fe30ff8f..4f6532dd 100644 --- a/07_Basketball/csharp/Plays/HomeTeamPlay.cs +++ b/07_Basketball/csharp/Plays/HomeTeamPlay.cs @@ -1,4 +1,3 @@ -using Basketball.Resources; using Games.Common.IO; using Games.Common.Randomness; @@ -10,9 +9,10 @@ internal class HomeTeamPlay : Play private readonly IRandom _random; private readonly Clock _clock; private readonly Defense _defense; + private bool _playContinues; public HomeTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense) - : base(io, random) + : base(io, random, clock) { _io = io; _random = random; @@ -33,61 +33,69 @@ internal class HomeTeamPlay : Play return false; } - var playContinues = shot >= 3; - if (shot == 1 || shot == 2) { - _clock.Increment(scoreboard); - if (_clock.IsHalfTime) { return false; } - - var ballContest = new BallContest(0.5f, "Shot is blocked. Ball controlled by {0}.", _io, _random); - - Resolve("Jump shot", _defense / 8) - .Do(0.341f, () => scoreboard.AddBasket("Shot is good")) - .Or(0.682f, () => ResolveShotOffTarget()) - .Or(0.782f, () => ballContest.Resolve(scoreboard)) - .Or(0.843f, () => ResolveFreeThrows(scoreboard, "Shooter is fouled. Two shots.")) - .Or(() => scoreboard.Turnover("Charging foul. Dartmouth loses ball.")); + if (ClockIncrementsToHalfTime(scoreboard)) { return false; } + ResolveJumpShot(scoreboard); } - while (playContinues) + _playContinues |= shot >= 3; + + while (_playContinues) { - _clock.Increment(scoreboard); - if (_clock.IsHalfTime) { return false; } - - playContinues = false; - - Resolve(shot == 3 ? "Lay up." : "Set shot.", _defense / 7) - .Do(0.4f, () => scoreboard.AddBasket("Shot is good. Two points.")) - .Or(0.7f, () => ResolveShotOffTheRim()) - .Or(0.875f, () => ResolveFreeThrows(scoreboard, "Shooter fouled. Two shots.")) - .Or(0.925f, () => scoreboard.Turnover($"Shot blocked. {scoreboard.Visitors}'s ball.")) - .Or(() => scoreboard.Turnover("Charging foul. Dartmouth loses ball.")); + if (ClockIncrementsToHalfTime(scoreboard)) { return false; } + ResolveLayupOrSetShot(scoreboard, shot); } return false; - - void ResolveShotOffTarget() => - Resolve("Shot is off target", 6 / _defense) - .Do(0.45f, () => Resolve("Dartmouth controls the rebound.") - .Do(0.4f, () => playContinues = true) - .Or(() => - { - if (_defense == 6 && _random.NextFloat() > 0.6f) - { - scoreboard.Turnover(); - scoreboard.AddBasket($"Pass stolen by {scoreboard.Visitors} easy layup."); - _io.WriteLine(); - } - _io.Write("Ball passed back to you. "); - })) - .Or(() => scoreboard.Turnover($"Rebound to {scoreboard.Visitors}")); - - void ResolveShotOffTheRim() => - Resolve("Shot is off the rim.") - .Do(2 / 3f, () => scoreboard.Turnover($"{scoreboard.Visitors} controls the rebound.")) - .Or(() => Resolve("Dartmouth controls the rebound") - .Do(0.4f, () => playContinues = true) - .Or(() => _io.WriteLine("Ball passed back to you."))); } + + private void ResolveJumpShot(Scoreboard scoreboard) + { + var ballContest = new BallContest(0.5f, "Shot is blocked. Ball controlled by {0}.", _io, _random); + + Resolve("Jump shot", _defense / 8) + .Do(0.341f, () => scoreboard.AddBasket("Shot is good")) + .Or(0.682f, () => ResolveShotOffTarget(scoreboard)) + .Or(0.782f, () => ballContest.Resolve(scoreboard)) + .Or(0.843f, () => ResolveFreeThrows(scoreboard, "Shooter is fouled. Two shots.")) + .Or(() => scoreboard.Turnover($"Charging foul. {scoreboard.Home} loses ball.")); + } + + private void ResolveLayupOrSetShot(Scoreboard scoreboard, int shot) + { + _playContinues = false; + + Resolve(shot == 3 ? "Lay up." : "Set shot.", _defense / 7) + .Do(0.4f, () => scoreboard.AddBasket("Shot is good. Two points.")) + .Or(0.7f, () => ResolveShotOffTheRim(scoreboard)) + .Or(0.875f, () => ResolveFreeThrows(scoreboard, "Shooter fouled. Two shots.")) + .Or(0.925f, () => scoreboard.Turnover($"Shot blocked. {scoreboard.Visitors}'s ball.")) + .Or(() => scoreboard.Turnover($"Charging foul. {scoreboard.Home} loses ball.")); + } + + private void ResolveShotOffTarget(Scoreboard scoreboard) => + Resolve("Shot is off target", 6 / _defense) + .Do(0.45f, () => ResolveHomeRebound(scoreboard, ResolvePossibleSteal)) + .Or(() => scoreboard.Turnover($"Rebound to {scoreboard.Visitors}")); + + private void ResolveHomeRebound(Scoreboard scoreboard, Action endOfPlayAction) => + Resolve($"{scoreboard.Home} controls the rebound.") + .Do(0.4f, () => _playContinues = true) + .Or(() => endOfPlayAction.Invoke(scoreboard)); + private void ResolvePossibleSteal(Scoreboard scoreboard) + { + if (_defense == 6 && _random.NextFloat() > 0.6f) + { + scoreboard.Turnover(); + scoreboard.AddBasket($"Pass stolen by {scoreboard.Visitors} easy layup."); + _io.WriteLine(); + } + _io.Write("Ball passed back to you. "); + } + + private void ResolveShotOffTheRim(Scoreboard scoreboard) => + Resolve("Shot is off the rim.") + .Do(2 / 3f, () => scoreboard.Turnover($"{scoreboard.Visitors} controls the rebound.")) + .Or(() => ResolveHomeRebound(scoreboard, _ => _io.WriteLine("Ball passed back to you."))); } diff --git a/07_Basketball/csharp/Plays/Play.cs b/07_Basketball/csharp/Plays/Play.cs index 0edba943..9b82a74e 100644 --- a/07_Basketball/csharp/Plays/Play.cs +++ b/07_Basketball/csharp/Plays/Play.cs @@ -7,11 +7,19 @@ internal abstract class Play { private readonly IReadWrite _io; private readonly IRandom _random; + private readonly Clock _clock; - public Play(IReadWrite io, IRandom random) + public Play(IReadWrite io, IRandom random, Clock clock) { _io = io; _random = random; + _clock = clock; + } + + protected bool ClockIncrementsToHalfTime(Scoreboard scoreboard) + { + _clock.Increment(scoreboard); + return _clock.IsHalfTime; } internal abstract bool Resolve(Scoreboard scoreboard); diff --git a/07_Basketball/csharp/Plays/VisitingTeamPlay.cs b/07_Basketball/csharp/Plays/VisitingTeamPlay.cs index ab526562..85591a97 100644 --- a/07_Basketball/csharp/Plays/VisitingTeamPlay.cs +++ b/07_Basketball/csharp/Plays/VisitingTeamPlay.cs @@ -7,52 +7,59 @@ internal class VisitingTeamPlay : Play { private readonly TextIO _io; private readonly IRandom _random; - private readonly Clock _clock; private readonly Defense _defense; private bool _playContinues; public VisitingTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense) - : base(io, random) + : base(io, random, clock) { _io = io; _random = random; - _clock = clock; _defense = defense; } internal override bool Resolve(Scoreboard scoreboard) { - _clock.Increment(scoreboard); - if (_clock.IsHalfTime) { return false; } + if (ClockIncrementsToHalfTime(scoreboard)) { return false; } _io.WriteLine(); var shot = _random.NextFloat(1, 3.5f); - _playContinues = shot > 2; if (shot <= 2) { - Resolve("Jump shot.", _defense / 8) - .Do(0.35f, () => scoreboard.AddBasket("Shot is good.")) - .Or(0.75f, () => ResolveBadShot(scoreboard, "Shot is off the rim.", _defense * 6)) - .Or(0.9f, () => ResolveFreeThrows(scoreboard, "Player fouled. Two shots.")) - .Or(() => _io.WriteLine("Offensive foul. Dartmouth's ball.")); - - _io.WriteLine(); + ResolveJumpShot(scoreboard); } + _playContinues |= shot > 2; + while (_playContinues) { - _playContinues = false; - - Resolve(shot > 3 ? "Set shot." : "Lay up.", _defense / 7) - .Do(0.413f, () => scoreboard.AddBasket("Shot is good.")) - .Or(() => ResolveBadShot(scoreboard, "Shot is missed.", 6 / _defense)); - _io.WriteLine(); + ResolveLayupOrSetShot(scoreboard, shot); } return false; } + private void ResolveJumpShot(Scoreboard scoreboard) + { + Resolve("Jump shot.", _defense / 8) + .Do(0.35f, () => scoreboard.AddBasket("Shot is good.")) + .Or(0.75f, () => ResolveBadShot(scoreboard, "Shot is off the rim.", _defense * 6)) + .Or(0.9f, () => ResolveFreeThrows(scoreboard, "Player fouled. Two shots.")) + .Or(() => _io.WriteLine("Offensive foul. Dartmouth's ball.")); + _io.WriteLine(); + } + + private void ResolveLayupOrSetShot(Scoreboard scoreboard, float shot) + { + _playContinues = false; + + Resolve(shot > 3 ? "Set shot." : "Lay up.", _defense / 7) + .Do(0.413f, () => scoreboard.AddBasket("Shot is good.")) + .Or(() => ResolveBadShot(scoreboard, "Shot is missed.", 6 / _defense)); + _io.WriteLine(); + } + void ResolveBadShot(Scoreboard scoreboard, string message, float defenseFactor) => Resolve(message, defenseFactor) .Do(0.5f, () => scoreboard.Turnover("Dartmouth controls the rebound."))