Use common library in 86_Target

This commit is contained in:
Andrew Cooper
2022-03-05 15:43:03 +11:00
parent 2c1e4af702
commit 8165f7a161
9 changed files with 82 additions and 124 deletions

View File

@@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common", "Games.Commo
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common.Test", "Games.Common.Test\Games.Common.Test.csproj", "{8369DA66-0414-4A14-B5BE-73B0159498A2}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common.Test", "Games.Common.Test\Games.Common.Test.csproj", "{8369DA66-0414-4A14-B5BE-73B0159498A2}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Games.Common.Sample", "Games.Common.Sample\Games.Common.Sample.csproj", "{395FBF0D-404E-495B-9760-8BEE3A6F5B62}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{8369DA66-0414-4A14-B5BE-73B0159498A2}.Release|Any CPU.Build.0 = 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 EndGlobalSection
EndGlobal EndGlobal

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.IO;
namespace Games.Common.IO; namespace Games.Common.IO;
@@ -66,7 +67,7 @@ public interface IReadWrite
/// Writes a <see cref="string" /> to output, followed by a new-line. /// Writes a <see cref="string" /> to output, followed by a new-line.
/// </summary> /// </summary>
/// <param name="message">The <see cref="string" /> to be written.</param> /// <param name="message">The <see cref="string" /> to be written.</param>
void WriteLine(string message); void WriteLine(string message = "");
/// <summary> /// <summary>
/// Writes a <see cref="float" /> to output, formatted per the BASIC interpreter, with leading and trailing spaces. /// Writes a <see cref="float" /> to output, formatted per the BASIC interpreter, with leading and trailing spaces.
@@ -80,4 +81,10 @@ public interface IReadWrite
/// </summary> /// </summary>
/// <param name="value">The <see cref="float" /> to be written.</param> /// <param name="value">The <see cref="float" /> to be written.</param>
void WriteLine(float value); void WriteLine(float value);
/// <summary>
/// Writes the contents of a <see cref="Stream" /> to output.
/// </summary>
/// <param name="stream">The <see cref="Stream" /> to be written.</param>
void Write(Stream stream);
} }

View File

@@ -89,11 +89,20 @@ public class TextIO : IReadWrite
public void Write(string value) => _output.Write(value); 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 Write(float value) => _output.Write(GetString(value));
public void WriteLine(float value) => _output.WriteLine(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} "; private string GetString(float value) => value < 0 ? $"{value} " : $" {value} ";
} }

View File

@@ -1,25 +1,23 @@
using System; using Games.Common.Randomness;
namespace Target namespace Target
{ {
internal class FiringRange internal class FiringRange
{ {
private readonly Random random; private readonly IRandom _random;
private Point _targetPosition;
public FiringRange() public FiringRange(IRandom random)
{ {
random = new Random(); _random = random;
NextTarget();
} }
public Point TargetPosition { get; private set; } public Point NextTarget() => _targetPosition = _random.NextPosition();
public void NextTarget() => TargetPosition = random.NextPosition();
public Explosion Fire(Angle angleFromX, Angle angleFromZ, float distance) public Explosion Fire(Angle angleFromX, Angle angleFromZ, float distance)
{ {
var explosionPosition = new Point(angleFromX, angleFromZ, distance); var explosionPosition = new Point(angleFromX, angleFromZ, distance);
var targetOffset = explosionPosition - TargetPosition; var targetOffset = explosionPosition - _targetPosition;
return new (explosionPosition, targetOffset); return new (explosionPosition, targetOffset);
} }
} }

View File

@@ -1,39 +1,41 @@
using System; using System;
using Games.Common.IO;
namespace Target namespace Target
{ {
internal class Game internal class Game
{ {
private readonly IReadWrite _io;
private readonly FiringRange _firingRange; private readonly FiringRange _firingRange;
private int _shotCount; private int _shotCount;
private Game(FiringRange firingRange) public Game(IReadWrite io, FiringRange firingRange)
{ {
_io = io;
_firingRange = firingRange; _firingRange = firingRange;
} }
public static void Play(FiringRange firingRange) => new Game(firingRange).Play(); public void Play()
private void Play()
{ {
var target = _firingRange.TargetPosition; _shotCount = 0;
Console.WriteLine(target.GetBearing()); var target = _firingRange.NextTarget();
Console.WriteLine($"Target sighted: approximate coordinates: {target}"); _io.WriteLine(target.GetBearing());
_io.WriteLine($"Target sighted: approximate coordinates: {target}");
while (true) while (true)
{ {
Console.WriteLine($" Estimated distance: {target.EstimateDistance()}"); _io.WriteLine($" Estimated distance: {target.EstimateDistance()}");
Console.WriteLine(); _io.WriteLine();
var explosion = Shoot(); var explosion = Shoot();
if (explosion.IsTooClose) if (explosion.IsTooClose)
{ {
Console.WriteLine("You blew yourself up!!"); _io.WriteLine("You blew yourself up!!");
return; return;
} }
Console.WriteLine(explosion.GetBearing()); _io.WriteLine(explosion.GetBearing());
if (explosion.IsHit) if (explosion.IsHit)
{ {
@@ -47,31 +49,32 @@ namespace Target
private Explosion Shoot() 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++; _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) private void ReportHit(float distance)
{ {
Console.WriteLine(); _io.WriteLine();
Console.WriteLine($" * * * HIT * * * Target is non-functional"); _io.WriteLine($" * * * HIT * * * Target is non-functional");
Console.WriteLine(); _io.WriteLine();
Console.WriteLine($"Distance of explosion from target was {distance} kilometers."); _io.WriteLine($"Distance of explosion from target was {distance} kilometers.");
Console.WriteLine(); _io.WriteLine();
Console.WriteLine($"Mission accomplished in {_shotCount} shots."); _io.WriteLine($"Mission accomplished in {_shotCount} shots.");
} }
private void ReportMiss(Explosion explosion) private void ReportMiss(Explosion explosion)
{ {
ReportMiss(explosion.FromTarget); ReportMiss(explosion.FromTarget);
Console.WriteLine($"Approx position of explosion: {explosion.Position}"); _io.WriteLine($"Approx position of explosion: {explosion.Position}");
Console.WriteLine($" Distance from target = {explosion.DistanceToTarget}"); _io.WriteLine($" Distance from target = {explosion.DistanceToTarget}");
Console.WriteLine(); _io.WriteLine();
Console.WriteLine(); _io.WriteLine();
Console.WriteLine(); _io.WriteLine();
} }
private void ReportMiss(Offset targetOffset) private void ReportMiss(Offset targetOffset)
@@ -82,7 +85,7 @@ namespace Target
} }
private void ReportMiss(float delta, string positiveText, string negativeText) => 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."; private static string GetOffsetText(string text, float distance) => $"Shot {text} target {distance} kilometers.";
} }

View File

@@ -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<float> ReadNumbers(string prompt, int requiredCount)
{
var numbers = new List<float>();
while (!TryReadNumbers(prompt, requiredCount, numbers))
{
numbers.Clear();
prompt = "";
}
return numbers;
}
private static bool TryReadNumbers(string prompt, int requiredCount, List<float> 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;
}
}
}

View File

@@ -1,39 +1,43 @@
using System; using System;
using System.Reflection; using System.Reflection;
using Games.Common.IO;
using Games.Common.Randomness;
namespace Target namespace Target
{ {
class Program 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<bool> playAgain)
{
DisplayTitleAndInstructions(io);
while (playAgain())
{ {
Game.Play(firingRange); game.Play();
Console.WriteLine(); io.WriteLine();
Console.WriteLine(); io.WriteLine();
Console.WriteLine(); io.WriteLine();
Console.WriteLine(); io.WriteLine();
Console.WriteLine(); io.WriteLine();
Console.WriteLine("Next target..."); io.WriteLine("Next target...");
Console.WriteLine(); io.WriteLine();
firingRange.NextTarget();
} }
} }
private static void DisplayTitleAndInstructions() private static void DisplayTitleAndInstructions(TextIO io)
{ {
using var stream = Assembly.GetExecutingAssembly() using var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("Target.Strings.TitleAndInstructions.txt"); .GetManifestResourceStream("Target.Strings.TitleAndInstructions.txt");
using var stdout = Console.OpenStandardOutput(); io.Write(stream);
stream.CopyTo(stdout);
} }
} }
} }

View File

@@ -1,12 +1,10 @@
using System; using Games.Common.Randomness;
namespace Target namespace Target
{ {
internal static class RandomExtensions internal static class RandomExtensions
{ {
public static float NextFloat(this Random rnd) => (float)rnd.NextDouble(); public static Point NextPosition(this IRandom rnd) => new (
public static Point NextPosition(this Random rnd) => new (
Angle.InRotations(rnd.NextFloat()), Angle.InRotations(rnd.NextFloat()),
Angle.InRotations(rnd.NextFloat()), Angle.InRotations(rnd.NextFloat()),
100000 * rnd.NextFloat() + rnd.NextFloat()); 100000 * rnd.NextFloat() + rnd.NextFloat());

View File

@@ -9,4 +9,8 @@
<EmbeddedResource Include="Strings\TitleAndInstructions.txt" /> <EmbeddedResource Include="Strings\TitleAndInstructions.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\00_Common\dotnet\Games.Common\Games.Common.csproj" />
</ItemGroup>
</Project> </Project>