mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 15:16:33 -08:00
94 lines
3.7 KiB
C#
94 lines
3.7 KiB
C#
using Games.Common.IO;
|
|
using Games.Common.Randomness;
|
|
|
|
namespace Basketball.Plays;
|
|
|
|
internal class HomeTeamPlay : Play
|
|
{
|
|
private readonly TextIO _io;
|
|
private readonly IRandom _random;
|
|
private readonly Clock _clock;
|
|
private readonly Defense _defense;
|
|
private readonly BallContest _ballContest;
|
|
|
|
public HomeTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense)
|
|
: base(io, random, clock)
|
|
{
|
|
_io = io;
|
|
_random = random;
|
|
_clock = clock;
|
|
_defense = defense;
|
|
_ballContest = new BallContest(0.5f, "Shot is blocked. Ball controlled by {0}.", _io, _random);
|
|
}
|
|
|
|
internal override bool Resolve(Scoreboard scoreboard)
|
|
{
|
|
var shot = _io.ReadShot("Your shot");
|
|
|
|
if (_random.NextFloat() >= 0.5f && _clock.IsFullTime) { return true; }
|
|
|
|
if (shot is null)
|
|
{
|
|
_defense.Set(_io.ReadDefense("Your new defensive alignment is"));
|
|
_io.WriteLine();
|
|
return false;
|
|
}
|
|
|
|
if (shot is JumpShot jumpShot)
|
|
{
|
|
if (ClockIncrementsToHalfTime(scoreboard)) { return false; }
|
|
if (!Resolve(jumpShot, scoreboard)) { return false; }
|
|
}
|
|
|
|
do
|
|
{
|
|
if (ClockIncrementsToHalfTime(scoreboard)) { return false; }
|
|
} while (Resolve(shot, scoreboard));
|
|
|
|
return false;
|
|
}
|
|
|
|
// The Resolve* methods resolve the probabilistic outcome of the current game state.
|
|
// They return true if the Home team should continue the play and attempt a layup, false otherwise.
|
|
private bool Resolve(JumpShot shot, Scoreboard scoreboard) =>
|
|
Resolve(shot.ToString(), _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 bool Resolve(Shot shot, Scoreboard scoreboard) =>
|
|
Resolve(shot.ToString(), _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 bool ResolveShotOffTarget(Scoreboard scoreboard) =>
|
|
Resolve("Shot is off target", 6 / _defense)
|
|
.Do(0.45f, () => ResolveHomeRebound(scoreboard, ResolvePossibleSteal))
|
|
.Or(() => scoreboard.Turnover($"Rebound to {scoreboard.Visitors}"));
|
|
|
|
private bool ResolveHomeRebound(Scoreboard scoreboard, Action<Scoreboard> endOfPlayAction) =>
|
|
Resolve($"{scoreboard.Home} controls the rebound.")
|
|
.Do(0.4f, () => 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.")));
|
|
}
|