diff --git a/00_Common/dotnet/Games.Common.sln b/00_Common/dotnet/Games.Common.sln index 3498c7d1..e0f51d4b 100644 --- a/00_Common/dotnet/Games.Common.sln +++ b/00_Common/dotnet/Games.Common.sln @@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common", "Games.Commo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common.Test", "Games.Common.Test\Games.Common.Test.csproj", "{8369DA66-0414-4A14-B5BE-73B0159498A2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common.Sample", "Games.Common.Sample\Games.Common.Sample.csproj", "{395FBF0D-404E-495B-9760-8BEE3A6F5B62}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,9 +24,5 @@ Global {8369DA66-0414-4A14-B5BE-73B0159498A2}.Debug|Any CPU.Build.0 = Debug|Any CPU {8369DA66-0414-4A14-B5BE-73B0159498A2}.Release|Any CPU.ActiveCfg = Release|Any CPU {8369DA66-0414-4A14-B5BE-73B0159498A2}.Release|Any CPU.Build.0 = Release|Any CPU - {395FBF0D-404E-495B-9760-8BEE3A6F5B62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {395FBF0D-404E-495B-9760-8BEE3A6F5B62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {395FBF0D-404E-495B-9760-8BEE3A6F5B62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {395FBF0D-404E-495B-9760-8BEE3A6F5B62}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/00_Common/dotnet/Games.Common/IO/IReadWrite.cs b/00_Common/dotnet/Games.Common/IO/IReadWrite.cs index 2a6433e1..27bd6986 100644 --- a/00_Common/dotnet/Games.Common/IO/IReadWrite.cs +++ b/00_Common/dotnet/Games.Common/IO/IReadWrite.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace Games.Common.IO; @@ -66,7 +67,7 @@ public interface IReadWrite /// Writes a to output, followed by a new-line. /// /// The to be written. - void WriteLine(string message); + void WriteLine(string message = ""); /// /// Writes a to output, formatted per the BASIC interpreter, with leading and trailing spaces. @@ -80,4 +81,10 @@ public interface IReadWrite /// /// The to be written. void WriteLine(float value); + + /// + /// Writes the contents of a to output. + /// + /// The to be written. + void Write(Stream stream); } diff --git a/00_Common/dotnet/Games.Common/IO/TextIO.cs b/00_Common/dotnet/Games.Common/IO/TextIO.cs index 9c3d6ba9..d5e9f9f6 100644 --- a/00_Common/dotnet/Games.Common/IO/TextIO.cs +++ b/00_Common/dotnet/Games.Common/IO/TextIO.cs @@ -89,11 +89,20 @@ public class TextIO : IReadWrite public void Write(string value) => _output.Write(value); - public void WriteLine(string value) => _output.WriteLine(value); + public void WriteLine(string value = "") => _output.WriteLine(value); public void Write(float value) => _output.Write(GetString(value)); public void WriteLine(float value) => _output.WriteLine(GetString(value)); + public void Write(Stream stream) + { + using var reader = new StreamReader(stream); + while (!reader.EndOfStream) + { + _output.WriteLine(reader.ReadLine()); + } + } + private string GetString(float value) => value < 0 ? $"{value} " : $" {value} "; } diff --git a/86_Target/csharp/FiringRange.cs b/86_Target/csharp/FiringRange.cs index 368dc453..b8a6399c 100644 --- a/86_Target/csharp/FiringRange.cs +++ b/86_Target/csharp/FiringRange.cs @@ -1,25 +1,23 @@ -using System; +using Games.Common.Randomness; namespace Target { internal class FiringRange { - private readonly Random random; + private readonly IRandom _random; + private Point _targetPosition; - public FiringRange() + public FiringRange(IRandom random) { - random = new Random(); - NextTarget(); + _random = random; } - public Point TargetPosition { get; private set; } - - public void NextTarget() => TargetPosition = random.NextPosition(); + public Point NextTarget() => _targetPosition = _random.NextPosition(); public Explosion Fire(Angle angleFromX, Angle angleFromZ, float distance) { var explosionPosition = new Point(angleFromX, angleFromZ, distance); - var targetOffset = explosionPosition - TargetPosition; + var targetOffset = explosionPosition - _targetPosition; return new (explosionPosition, targetOffset); } } diff --git a/86_Target/csharp/Game.cs b/86_Target/csharp/Game.cs index 2cef015a..4bb4f9b2 100644 --- a/86_Target/csharp/Game.cs +++ b/86_Target/csharp/Game.cs @@ -1,39 +1,41 @@ using System; +using Games.Common.IO; namespace Target { internal class Game { + private readonly IReadWrite _io; private readonly FiringRange _firingRange; private int _shotCount; - private Game(FiringRange firingRange) + public Game(IReadWrite io, FiringRange firingRange) { + _io = io; _firingRange = firingRange; } - public static void Play(FiringRange firingRange) => new Game(firingRange).Play(); - - private void Play() + public void Play() { - var target = _firingRange.TargetPosition; - Console.WriteLine(target.GetBearing()); - Console.WriteLine($"Target sighted: approximate coordinates: {target}"); + _shotCount = 0; + var target = _firingRange.NextTarget(); + _io.WriteLine(target.GetBearing()); + _io.WriteLine($"Target sighted: approximate coordinates: {target}"); while (true) { - Console.WriteLine($" Estimated distance: {target.EstimateDistance()}"); - Console.WriteLine(); + _io.WriteLine($" Estimated distance: {target.EstimateDistance()}"); + _io.WriteLine(); var explosion = Shoot(); if (explosion.IsTooClose) { - Console.WriteLine("You blew yourself up!!"); + _io.WriteLine("You blew yourself up!!"); return; } - Console.WriteLine(explosion.GetBearing()); + _io.WriteLine(explosion.GetBearing()); if (explosion.IsHit) { @@ -47,31 +49,32 @@ namespace Target private Explosion Shoot() { - var input = Input.ReadNumbers("Input angle deviation from X, angle deviation from Z, distance", 3); + var (xDeviation, zDeviation, distance) = _io.Read3Numbers( + "Input angle deviation from X, angle deviation from Z, distance"); _shotCount++; - Console.WriteLine(); + _io.WriteLine(); - return _firingRange.Fire(Angle.InDegrees(input[0]), Angle.InDegrees(input[1]), input[2]); + return _firingRange.Fire(Angle.InDegrees(xDeviation), Angle.InDegrees(zDeviation), distance); } private void ReportHit(float distance) { - Console.WriteLine(); - Console.WriteLine($" * * * HIT * * * Target is non-functional"); - Console.WriteLine(); - Console.WriteLine($"Distance of explosion from target was {distance} kilometers."); - Console.WriteLine(); - Console.WriteLine($"Mission accomplished in {_shotCount} shots."); + _io.WriteLine(); + _io.WriteLine($" * * * HIT * * * Target is non-functional"); + _io.WriteLine(); + _io.WriteLine($"Distance of explosion from target was {distance} kilometers."); + _io.WriteLine(); + _io.WriteLine($"Mission accomplished in {_shotCount} shots."); } private void ReportMiss(Explosion explosion) { ReportMiss(explosion.FromTarget); - Console.WriteLine($"Approx position of explosion: {explosion.Position}"); - Console.WriteLine($" Distance from target = {explosion.DistanceToTarget}"); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); + _io.WriteLine($"Approx position of explosion: {explosion.Position}"); + _io.WriteLine($" Distance from target = {explosion.DistanceToTarget}"); + _io.WriteLine(); + _io.WriteLine(); + _io.WriteLine(); } private void ReportMiss(Offset targetOffset) @@ -82,7 +85,7 @@ namespace Target } private void ReportMiss(float delta, string positiveText, string negativeText) => - Console.WriteLine(delta >= 0 ? GetOffsetText(positiveText, delta) : GetOffsetText(negativeText, -delta)); + _io.WriteLine(delta >= 0 ? GetOffsetText(positiveText, delta) : GetOffsetText(negativeText, -delta)); private static string GetOffsetText(string text, float distance) => $"Shot {text} target {distance} kilometers."; } diff --git a/86_Target/csharp/Input.cs b/86_Target/csharp/Input.cs deleted file mode 100644 index 3cfce2c0..00000000 --- a/86_Target/csharp/Input.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Target -{ - // Provides input methods which emulate the BASIC interpreter's keyboard input routines - internal static class Input - { - internal static void Prompt(string text = "") => Console.Write($"{text}? "); - - internal static List ReadNumbers(string prompt, int requiredCount) - { - var numbers = new List(); - - while (!TryReadNumbers(prompt, requiredCount, numbers)) - { - numbers.Clear(); - prompt = ""; - } - - return numbers; - } - - private static bool TryReadNumbers(string prompt, int requiredCount, List numbers) - { - Prompt(prompt); - var inputValues = ReadStrings(); - - foreach (var value in inputValues) - { - if (numbers.Count == requiredCount) - { - Console.WriteLine("!Extra input ingored"); - break; - } - - if (!TryParseNumber(value, out var number)) - { - return false; - } - - numbers.Add(number); - } - - return numbers.Count == requiredCount || TryReadNumbers("?", requiredCount, numbers); - } - - private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries); - - private static bool TryParseNumber(string text, out float number) - { - if (float.TryParse(text, out number)) { return true; } - - Console.WriteLine("!Number expected - retry input line"); - number = default; - return false; - } - } -} diff --git a/86_Target/csharp/Program.cs b/86_Target/csharp/Program.cs index b861f0e6..cafa559a 100644 --- a/86_Target/csharp/Program.cs +++ b/86_Target/csharp/Program.cs @@ -1,39 +1,43 @@ using System; using System.Reflection; +using Games.Common.IO; +using Games.Common.Randomness; namespace Target { class Program { - static void Main(string[] args) + static void Main() { - DisplayTitleAndInstructions(); + var io = new ConsoleIO(); + var game = new Game(io, new FiringRange(new RandomNumberGenerator())); - var firingRange = new FiringRange(); + Play(game, io, () => true); + } - while (true) + public static void Play(Game game, TextIO io, Func playAgain) + { + DisplayTitleAndInstructions(io); + + while (playAgain()) { - Game.Play(firingRange); + game.Play(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine("Next target..."); - Console.WriteLine(); - - firingRange.NextTarget(); + io.WriteLine(); + io.WriteLine(); + io.WriteLine(); + io.WriteLine(); + io.WriteLine(); + io.WriteLine("Next target..."); + io.WriteLine(); } } - private static void DisplayTitleAndInstructions() + private static void DisplayTitleAndInstructions(TextIO io) { using var stream = Assembly.GetExecutingAssembly() .GetManifestResourceStream("Target.Strings.TitleAndInstructions.txt"); - using var stdout = Console.OpenStandardOutput(); - - stream.CopyTo(stdout); + io.Write(stream); } } } diff --git a/86_Target/csharp/RandomExtensions.cs b/86_Target/csharp/RandomExtensions.cs index 45443c26..a76b0279 100644 --- a/86_Target/csharp/RandomExtensions.cs +++ b/86_Target/csharp/RandomExtensions.cs @@ -1,12 +1,10 @@ -using System; +using Games.Common.Randomness; namespace Target { internal static class RandomExtensions { - public static float NextFloat(this Random rnd) => (float)rnd.NextDouble(); - - public static Point NextPosition(this Random rnd) => new ( + public static Point NextPosition(this IRandom rnd) => new ( Angle.InRotations(rnd.NextFloat()), Angle.InRotations(rnd.NextFloat()), 100000 * rnd.NextFloat() + rnd.NextFloat()); diff --git a/86_Target/csharp/Target.csproj b/86_Target/csharp/Target.csproj index 2df33b67..ea8ff526 100644 --- a/86_Target/csharp/Target.csproj +++ b/86_Target/csharp/Target.csproj @@ -9,4 +9,8 @@ + + + +