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 @@
+
+
+
+