Split out play resolution

This commit is contained in:
Andrew Cooper
2022-03-30 16:50:48 +11:00
parent 741b135d99
commit 1ba6dd48aa
5 changed files with 252 additions and 214 deletions

View File

@@ -0,0 +1,32 @@
using Basketball.Resources;
using Games.Common.IO;
namespace Basketball;
internal class Clock
{
private readonly IReadWrite _io;
private int time;
public Clock(IReadWrite io) => _io = io;
public bool IsHalfTime => time == 50;
public bool IsFullTime => time >= 100;
public bool TwoMinutesLeft => time == 92;
public void Increment(Scoreboard scoreboard)
{
time += 1;
if (IsHalfTime)
{
scoreboard.Display(Resource.Formats.EndOfFirstHalf);
// Loop back to center jump;
}
if (TwoMinutesLeft)
{
_io.Write(Resource.Streams.TwoMinutesLeft);
}
}
public void StartOvertime() => time = 93;
}

View File

@@ -0,0 +1,12 @@
namespace Basketball;
internal class Defense
{
private float _value;
public Defense(float value) => Set(value);
public void Set(float value) => _value = value;
public static implicit operator float(Defense defense) => defense._value;
}

View File

@@ -19,32 +19,41 @@ internal class Game
{ {
_io.Write(Resource.Streams.Introduction); _io.Write(Resource.Streams.Introduction);
var defense = _io.ReadDefense("Your starting defense will be"); var defense = new Defense(_io.ReadDefense("Your starting defense will be"));
var clock = new Clock(_io);
var homeTeam = new Team("Dartmouth");
_io.WriteLine(); _io.WriteLine();
var visitingTeam = new Team(_io.ReadString("Choose your opponent"));
var time = 0; var scoreboard = new Scoreboard(
var scoreboard = new Scoreboard(homeTeam, visitingTeam, _io); new Team("Dartmouth", HomeTeamPlay(clock, defense)),
new Team(_io.ReadString("Choose your opponent"), VisitingTeamPlay(clock, defense)),
_io);
while (true)
{
_io.WriteLine("Center jump"); _io.WriteLine("Center jump");
scoreboard.Offense = ContestBall(0.6f, visitingTeam, homeTeam, "{0} controls the tap"); scoreboard.Offense = ContestBall(0.4f, scoreboard, "{0} controls the tap");
_io.WriteLine(); _io.WriteLine();
if (scoreboard.Offense == homeTeam) while (true)
{
scoreboard.Offense.ResolvePlay(scoreboard);
}
}
}
private Action<Scoreboard> HomeTeamPlay(Clock clock, Defense defense) => scoreboard =>
{ {
var shot = _io.ReadShot("Your shot"); var shot = _io.ReadShot("Your shot");
if (_random.NextFloat() >= 0.5f && time >= 100) if (_random.NextFloat() >= 0.5f && clock.IsFullTime)
{ {
_io.WriteLine(); _io.WriteLine();
if (scoreboard.ScoresAreEqual) if (scoreboard.ScoresAreEqual)
{ {
scoreboard.Display(Resource.Formats.EndOfSecondHalf); scoreboard.Display(Resource.Formats.EndOfSecondHalf);
time = 93; clock.StartOvertime();
// Loop back to center jump // Loop back to center jump
} }
else else
@@ -57,22 +66,17 @@ internal class Game
{ {
if (shot == 0) if (shot == 0)
{ {
defense = _io.ReadDefense("Your new defensive alignment is"); defense.Set(_io.ReadDefense("Your new defensive alignment is"));
// go to next shot // go to next shot
} }
if (shot == 1 || shot == 2) if (shot == 1 || shot == 2)
{ {
time++; clock.Increment(scoreboard);
if (time == 50) if (clock.IsHalfTime)
{ {
scoreboard.Display(Resource.Formats.EndOfFirstHalf);
// Loop back to center jump; // Loop back to center jump;
} }
if (time == 92)
{
_io.Write(Resource.Streams.TwoMinutesLeft);
}
_io.WriteLine("Jump shot"); _io.WriteLine("Jump shot");
if (_random.NextFloat() <= 0.341f * defense / 8) if (_random.NextFloat() <= 0.341f * defense / 8)
{ {
@@ -84,7 +88,7 @@ internal class Game
_io.WriteLine("Shot is off target"); _io.WriteLine("Shot is off target");
if (defense / 6 * _random.NextFloat() > 0.45f) if (defense / 6 * _random.NextFloat() > 0.45f)
{ {
scoreboard.Turnover($"Rebound to {visitingTeam}"); scoreboard.Turnover($"Rebound to {scoreboard.Visitors}");
// over to opponent // over to opponent
} }
else else
@@ -101,7 +105,7 @@ internal class Game
if (_random.NextFloat() > 0.6f) if (_random.NextFloat() > 0.6f)
{ {
scoreboard.Turnover(); scoreboard.Turnover();
scoreboard.AddBasket($"Pass stolen by {visitingTeam} easy layup."); scoreboard.AddBasket($"Pass stolen by {scoreboard.Visitors} easy layup.");
_io.WriteLine(); _io.WriteLine();
} }
} }
@@ -112,13 +116,12 @@ internal class Game
} }
else if (_random.NextFloat() <= 0.782f * defense / 8) else if (_random.NextFloat() <= 0.782f * defense / 8)
{ {
scoreboard.Offense = scoreboard.Offense = ContestBall(0.5f, scoreboard, "Shot is blocked. Ball controlled by {0}.");
ContestBall(0.5f, homeTeam, visitingTeam, "Shot is blocked. Ball controlled by {0}.");
// go to next shot // go to next shot
} }
else if (_random.NextFloat() <= 0.843f * defense / 8) else if (_random.NextFloat() <= 0.843f * defense / 8)
{ {
FreeThrows("Shooter is fouled. Two shots."); FreeThrows(scoreboard, "Shooter is fouled. Two shots.");
// over to opponent // over to opponent
} }
else else
@@ -128,16 +131,11 @@ internal class Game
} }
} }
// 1300 // 1300
time++; clock.Increment(scoreboard);
if (time == 50) if (clock.IsHalfTime)
{ {
scoreboard.Display(Resource.Formats.EndOfFirstHalf);
// Loop back to center jump; // Loop back to center jump;
} }
if (time == 92)
{
_io.Write(Resource.Streams.TwoMinutesLeft);
}
_io.WriteLine(shot == 3 ? "Lay up." : "Set shot."); _io.WriteLine(shot == 3 ? "Lay up." : "Set shot.");
@@ -151,7 +149,7 @@ internal class Game
_io.WriteLine("Shot is off the rim."); _io.WriteLine("Shot is off the rim.");
if (_random.NextFloat() <= 2 / 3f) if (_random.NextFloat() <= 2 / 3f)
{ {
scoreboard.Turnover($"{visitingTeam} controls the rebound."); scoreboard.Turnover($"{scoreboard.Visitors} controls the rebound.");
// over to opponent // over to opponent
} }
else else
@@ -170,12 +168,12 @@ internal class Game
} }
else if (_random.NextFloat() <= 0.875f * defense / 7) else if (_random.NextFloat() <= 0.875f * defense / 7)
{ {
FreeThrows("Shooter fouled. Two shots."); FreeThrows(scoreboard, "Shooter fouled. Two shots.");
// over to opponent // over to opponent
} }
else if (_random.NextFloat() <= 0.925f * defense / 7) else if (_random.NextFloat() <= 0.925f * defense / 7)
{ {
scoreboard.Turnover($"Shot blocked. {visitingTeam}'s ball."); scoreboard.Turnover($"Shot blocked. {scoreboard.Visitors}'s ball.");
// over to opponent // over to opponent
} }
else else
@@ -184,19 +182,15 @@ internal class Game
// over to opponent // over to opponent
} }
} }
} };
else
private Action<Scoreboard> VisitingTeamPlay(Clock clock, Defense defense) => scoreboard =>
{ {
time++; clock.Increment(scoreboard);
if (time == 50) if (clock.IsHalfTime)
{ {
scoreboard.Display(Resource.Formats.EndOfFirstHalf);
// Loop back to center jump; // Loop back to center jump;
} }
if (time == 92)
{
_io.Write(Resource.Streams.TwoMinutesLeft);
}
_io.WriteLine(); _io.WriteLine();
var shot = _random.NextFloat(1, 3.5f); var shot = _random.NextFloat(1, 3.5f);
@@ -219,7 +213,7 @@ internal class Game
} }
else else
{ {
_io.WriteLine($"{visitingTeam} controls the rebound."); _io.WriteLine($"{scoreboard.Visitors} controls the rebound.");
if (defense == 6) if (defense == 6)
{ {
if (_random.NextFloat() <= 0.25f) if (_random.NextFloat() <= 0.25f)
@@ -232,7 +226,7 @@ internal class Game
} }
if (_random.NextFloat() <= 0.5f) if (_random.NextFloat() <= 0.5f)
{ {
_io.WriteLine($"Pass back to {visitingTeam} guard."); _io.WriteLine($"Pass back to {scoreboard.Visitors} guard.");
// next opponent shot // next opponent shot
} }
// goto 3500 // goto 3500
@@ -240,7 +234,7 @@ internal class Game
} }
else if (_random.NextFloat() <= 0.9f * defense / 8) else if (_random.NextFloat() <= 0.9f * defense / 8)
{ {
FreeThrows("Player fouled. Two shots."); FreeThrows(scoreboard, "Player fouled. Two shots.");
// next Dartmouth shot // next Dartmouth shot
} }
else else
@@ -268,7 +262,7 @@ internal class Game
} }
else else
{ {
_io.WriteLine($"{visitingTeam} controls the rebound."); _io.WriteLine($"{scoreboard.Visitors} controls the rebound.");
if (defense == 6) if (defense == 6)
{ {
if (_random.NextFloat() <= 0.25f) if (_random.NextFloat() <= 0.25f)
@@ -281,22 +275,22 @@ internal class Game
} }
if (_random.NextFloat() <= 0.5f) if (_random.NextFloat() <= 0.5f)
{ {
_io.WriteLine($"Pass back to {visitingTeam} guard."); _io.WriteLine($"Pass back to {scoreboard.Visitors} guard.");
// next opponent shot // next opponent shot
} }
// goto 3500 // goto 3500
} }
} }
} };
Team ContestBall(float probability, Team a, Team b, string messageFormat) Team ContestBall(float probability, Scoreboard scoreboard, string messageFormat)
{ {
var winner = _random.NextFloat() <= probability ? a : b; var winner = _random.NextFloat() <= probability ? scoreboard.Home : scoreboard.Visitors;
_io.WriteLine(messageFormat, winner); _io.WriteLine(messageFormat, winner);
return winner; return winner;
} }
void FreeThrows(string message) void FreeThrows(Scoreboard scoreboard, string message)
{ {
_io.WriteLine(message); _io.WriteLine(message);
@@ -314,4 +308,3 @@ internal class Game
} }
} }
} }
}

View File

@@ -8,20 +8,19 @@ internal class Scoreboard
private readonly Dictionary<Team, uint> _scores; private readonly Dictionary<Team, uint> _scores;
private readonly IReadWrite _io; private readonly IReadWrite _io;
private Team _home;
private Team _visitors;
public Scoreboard(Team home, Team visitors, IReadWrite io) public Scoreboard(Team home, Team visitors, IReadWrite io)
{ {
_scores = new() { [home] = 0, [visitors] = 0 }; _scores = new() { [home] = 0, [visitors] = 0 };
_home = home; Home = home;
_visitors = visitors; Visitors = visitors;
Offense = home; Offense = home;
_io = io; _io = io;
} }
public bool ScoresAreEqual => _scores[_home] == _scores[_visitors]; public bool ScoresAreEqual => _scores[Home] == _scores[Visitors];
public Team Offense { get; set; } public Team Offense { get; set; }
public Team Home { get; }
public Team Visitors { get; }
public void AddBasket(string message) => AddScore(2, message); public void AddBasket(string message) => AddScore(2, message);
@@ -39,9 +38,9 @@ internal class Scoreboard
{ {
if (message is not null) { _io.WriteLine(message); } if (message is not null) { _io.WriteLine(message); }
Offense = Offense == _home ? _visitors : _home; Offense = Offense == Home ? Visitors : Home;
} }
public void Display(string? format = null) => public void Display(string? format = null) =>
_io.WriteLine(format ?? Resource.Formats.Score, _home, _scores[_home], _visitors, _scores[_visitors]); _io.WriteLine(format ?? Resource.Formats.Score, Home, _scores[Home], Visitors, _scores[Visitors]);
} }

View File

@@ -1,6 +1,8 @@
namespace Basketball; namespace Basketball;
internal record Team(string Name) internal record Team(string Name, Action<Scoreboard> PlayResolution)
{ {
public override string ToString() => Name; public override string ToString() => Name;
public void ResolvePlay(Scoreboard scoreboard) => PlayResolution.Invoke(scoreboard);
} }