From 3e4fb4fe237bbea7232232551a4b36960c418f03 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 22 Apr 2023 08:09:50 +1000 Subject: [PATCH] Split classes to files --- 77_Salvo/csharp/Coordinate.cs | 45 ++ 77_Salvo/csharp/Extensions/IOExtensions.cs | 27 ++ .../csharp/Extensions/RandomExtensions.cs | 32 ++ 77_Salvo/csharp/Game.cs | 419 +----------------- 77_Salvo/csharp/Grid.cs | 89 ++++ 77_Salvo/csharp/Offset.cs | 25 ++ 77_Salvo/csharp/Position.cs | 52 +++ 77_Salvo/csharp/Program.cs | 3 +- 77_Salvo/csharp/Ships/Battleship.cs | 18 + 77_Salvo/csharp/Ships/Cruiser.cs | 18 + 77_Salvo/csharp/Ships/Destroyer.cs | 18 + 77_Salvo/csharp/Ships/Ship.cs | 38 ++ .../csharp/Targetting/ComputerShotSelector.cs | 23 + .../csharp/Targetting/HumanShotSelector.cs | 31 ++ 77_Salvo/csharp/Targetting/ShotSelector.cs | 15 + 15 files changed, 434 insertions(+), 419 deletions(-) create mode 100644 77_Salvo/csharp/Coordinate.cs create mode 100644 77_Salvo/csharp/Extensions/IOExtensions.cs create mode 100644 77_Salvo/csharp/Extensions/RandomExtensions.cs create mode 100644 77_Salvo/csharp/Grid.cs create mode 100644 77_Salvo/csharp/Offset.cs create mode 100644 77_Salvo/csharp/Position.cs create mode 100644 77_Salvo/csharp/Ships/Battleship.cs create mode 100644 77_Salvo/csharp/Ships/Cruiser.cs create mode 100644 77_Salvo/csharp/Ships/Destroyer.cs create mode 100644 77_Salvo/csharp/Ships/Ship.cs create mode 100644 77_Salvo/csharp/Targetting/ComputerShotSelector.cs create mode 100644 77_Salvo/csharp/Targetting/HumanShotSelector.cs create mode 100644 77_Salvo/csharp/Targetting/ShotSelector.cs diff --git a/77_Salvo/csharp/Coordinate.cs b/77_Salvo/csharp/Coordinate.cs new file mode 100644 index 00000000..45d149c1 --- /dev/null +++ b/77_Salvo/csharp/Coordinate.cs @@ -0,0 +1,45 @@ +namespace Salvo; + +internal record struct Coordinate(int Value) +{ + public const int MinValue = 0; + public const int MaxValue = 9; + + public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); + + public bool IsInRange => Value is >= MinValue and <= MaxValue; + + public static Coordinate Create(float value) => new((int)value - 1); + + public static bool TryCreateValid(float value, out Coordinate coordinate) + { + coordinate = default; + if (value != (int)value) { return false; } + + var result = Create(value); + + if (result.IsInRange) + { + coordinate = result; + return true; + } + + return false; + } + + public Coordinate BringIntoRange(IRandom random) + => Value switch + { + < MinValue => new(MinValue + (int)random.NextFloat(2.5F)), + > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)), + _ => this + }; + + public static implicit operator Coordinate(float value) => new((int)value); + public static implicit operator int(Coordinate coordinate) => coordinate.Value; + + public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); + public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; + + public override string ToString() => $" {Value + 1} "; +} diff --git a/77_Salvo/csharp/Extensions/IOExtensions.cs b/77_Salvo/csharp/Extensions/IOExtensions.cs new file mode 100644 index 00000000..b9eaa2c4 --- /dev/null +++ b/77_Salvo/csharp/Extensions/IOExtensions.cs @@ -0,0 +1,27 @@ +namespace Games.Common.IO; + +internal static class IOExtensions +{ + internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers("")); + + internal static Position ReadValidPosition(this IReadWrite io) + { + while (true) + { + if (Position.TryCreateValid(io.Read2Numbers(""), out var position)) + { + return position; + } + io.WriteLine("ILLEGAL, ENTER AGAIN."); + } + } + + internal static IEnumerable ReadPositions(this IReadWrite io, string shipName, int shipSize) + { + io.WriteLine(shipName); + for (var i = 0; i < shipSize; i++) + { + yield return io.ReadPosition(); + } + } +} diff --git a/77_Salvo/csharp/Extensions/RandomExtensions.cs b/77_Salvo/csharp/Extensions/RandomExtensions.cs new file mode 100644 index 00000000..e83ab265 --- /dev/null +++ b/77_Salvo/csharp/Extensions/RandomExtensions.cs @@ -0,0 +1,32 @@ +namespace Games.Common.Randomness; + +internal static class RandomExtensions +{ + internal static (Position, Offset) NextShipPosition(this IRandom random) + { + var startX = random.NextCoordinate(); + var startY = random.NextCoordinate(); + var deltaY = random.NextOffset(); + var deltaX = random.NextOffset(); + return (new(startX, startY), new(deltaX, deltaY)); + } + + private static Coordinate NextCoordinate(this IRandom random) + => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1); + + private static int NextOffset(this IRandom random) => random.Next(-1, 2); + + internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize) + { + while (true) + { + var (start, delta) = random.NextShipPosition(); + var shipSizeLessOne = shipSize - 1; + var end = start + delta * shipSizeLessOne; + if (delta != 0 && end.IsInRange) + { + return (start, delta); + } + } + } +} diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 491cebdb..2afac1bd 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -1,5 +1,4 @@ -using System.Collections.Immutable; -using Games.Common.Randomness; +using Salvo.Targetting; namespace Salvo; @@ -224,419 +223,3 @@ L4210: ;// NoOp - NEXT S L4230: goto L3380; } } - -internal abstract class ShotSelector -{ - internal ShotSelector(Grid source, Grid target) - { - Source = source; - Target = target; - } - - protected Grid Source { get; } - protected Grid Target { get; } - - public int GetShotCount() => Source.Ships.Sum(s => s.Shots); -} - -internal abstract class ComputerShotSelector : ShotSelector -{ - private readonly bool _displayShots; - - internal ComputerShotSelector(Grid source, Grid target, bool displayShots) - : base(source, target) - { - _displayShots = displayShots; - } - - private void DisplayShots(IEnumerable shots, IReadWrite io) - { - if (_displayShots) - { - foreach (var shot in shots) - { - io.WriteLine(shot); - } - } - } -} - -internal class HumanShotSelector : ShotSelector -{ - public HumanShotSelector(Grid source, Grid target) - : base(source, target) - { - } - - public IEnumerable GetShots(IReadWrite io) - { - var shots = new Position[GetShotCount()]; - - for (var i = 0; i < shots.Length; i++) - { - while (true) - { - var position = io.ReadValidPosition(); - if (Target.WasTargetedAt(position, out var turnTargeted)) - { - io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); - continue; - } - shots[i] = position; - break; - } - } - - return shots; - } -} - -internal abstract class Ship -{ - private readonly List _positions = new(); - - protected Ship(IReadWrite io, string? nameSuffix = null) - { - Name = GetType().Name + nameSuffix; - _positions = io.ReadPositions(Name, Size).ToList(); - } - - protected Ship(IRandom random, string? nameSuffix = null) - { - Name = GetType().Name + nameSuffix; - - var (start, delta) = random.GetRandomShipPositionInRange(Size); - for (var i = 0; i < Size; i++) - { - _positions.Add(start + delta * i); - } - } - - internal string Name { get; } - internal abstract int Shots { get; } - internal abstract int Size { get; } - internal abstract float Value { get; } - internal IEnumerable Positions => _positions; - internal bool IsDestroyed => _positions.Count == 0; - - internal bool IsHit(Position position) => _positions.Remove(position); - - internal float DistanceTo(Ship other) - => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min(); - - public override string ToString() - => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name)); -} - -internal sealed class Battleship : Ship -{ - internal Battleship(IReadWrite io) - : base(io) - { - } - - internal Battleship(IRandom random) - : base(random) - { - } - - internal override int Shots => 3; - internal override int Size => 5; - internal override float Value => 3; -} - -internal sealed class Cruiser : Ship -{ - internal Cruiser(IReadWrite io) - : base(io) - { - } - - internal Cruiser(IRandom random) - : base(random) - { - } - - internal override int Shots => 2; - internal override int Size => 3; - internal override float Value => 2; -} - -internal sealed class Destroyer : Ship -{ - internal Destroyer(string nameIndex, IReadWrite io) - : base(io, $"<{nameIndex}>") - { - } - - internal Destroyer(string nameIndex, IRandom random) - : base(random, $"<{nameIndex}>") - { - } - - internal override int Shots => 1; - internal override int Size => 2; - internal override float Value => Name.EndsWith("") ? 1 : 0.5F; -} - -internal static class RandomExtensions -{ - internal static (Position, Offset) NextShipPosition(this IRandom random) - { - var startX = random.NextCoordinate(); - var startY = random.NextCoordinate(); - var deltaY = random.NextOffset(); - var deltaX = random.NextOffset(); - return (new(startX, startY), new(deltaX, deltaY)); - } - - private static Coordinate NextCoordinate(this IRandom random) - => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1); - - private static int NextOffset(this IRandom random) => random.Next(-1, 2); - - internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize) - { - while (true) - { - var (start, delta) = random.NextShipPosition(); - var shipSizeLessOne = shipSize - 1; - var end = start + delta * shipSizeLessOne; - if (delta != 0 && end.IsInRange) - { - return (start, delta); - } - } - } -} - -internal class Grid -{ - private readonly List _ships; - private readonly Dictionary _shots = new(); - - internal Grid() - { - _ships = new(); - } - - internal Grid(IReadWrite io) - { - io.WriteLine("ENTER COORDINATES FOR..."); - _ships = new() - { - new Battleship(io), - new Cruiser(io), - new Destroyer("A", io), - new Destroyer("B", io) - }; - } - - internal Grid(IRandom random) - { - _ships = new(); - while (true) - { - _ships.Add(new Battleship(random)); - if (TryPositionShip(() => new Cruiser(random)) && - TryPositionShip(() => new Destroyer("A", random)) && - TryPositionShip(() => new Destroyer("B", random))) - { - return; - } - _ships.Clear(); - } - - bool TryPositionShip(Func shipFactory) - { - var shipGenerationAttempts = 0; - while (true) - { - var ship = shipFactory.Invoke(); - shipGenerationAttempts++; - if (shipGenerationAttempts > 25) { return false; } - if (_ships.Min(ship.DistanceTo) >= 3.59) - { - _ships.Add(ship); - return true; - } - } - } - } - - public float this[Position position] - { - get => _shots.TryGetValue(position, out var value) - ? value + 10 - : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; - set - { - _ = _ships.FirstOrDefault(s => s.IsHit(position)); - _shots[position] = (int)value - 10; - } - } - - internal int UntriedSquareCount => 100 - _shots.Count; - internal IEnumerable Ships => _ships.AsEnumerable(); - - internal bool WasTargetedAt(Position position, out int turnTargeted) - => _shots.TryGetValue(position, out turnTargeted); - - internal bool IsHit(Position position, int turnNumber, out string? shipName) - { - shipName = null; - _shots[position] = turnNumber; - - var ship = _ships.FirstOrDefault(s => s.IsHit(position)); - if (ship == null) { return false; } - - if (ship.IsDestroyed) { _ships.Remove(ship); } - - return true; - } -} - -internal static class IOExtensions -{ - internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers("")); - - internal static Position ReadValidPosition(this IReadWrite io) - { - while (true) - { - if (Position.TryCreateValid(io.Read2Numbers(""), out var position)) - { - return position; - } - io.WriteLine("ILLEGAL, ENTER AGAIN."); - } - } - - internal static IEnumerable ReadPositions(this IReadWrite io, string shipName, int shipSize) - { - io.WriteLine(shipName); - for (var i = 0; i < shipSize; i++) - { - yield return io.ReadPosition(); - } - } -} - -internal record struct Position(Coordinate X, Coordinate Y) -{ - public bool IsInRange => X.IsInRange && Y.IsInRange; - public bool IsOnDiagonal => X == Y; - - public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y); - - public static bool TryCreateValid((float X, float Y) coordinates, out Position position) - { - if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y)) - { - position = new(x, y); - return true; - } - - position = default; - return false; - } - - public static IEnumerable All - => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y))); - - public IEnumerable Neighbours - { - get - { - foreach (var offset in Offset.Units) - { - var neighbour = this + offset; - if (neighbour.IsInRange) { yield return neighbour; } - } - } - } - - internal float DistanceTo(Position other) - { - var (deltaX, deltaY) = (X - other.X, Y - other.Y); - return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY); - } - - internal Position BringIntoRange(IRandom random) - => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); - - public static Position operator +(Position position, Offset offset) - => new(position.X + offset.X, position.Y + offset.Y); - - public static implicit operator Position(int value) => new(value, value); - - public override string ToString() => $"{X}{Y}"; -} - -internal record struct Coordinate(int Value) -{ - public const int MinValue = 0; - public const int MaxValue = 9; - - public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); - - public bool IsInRange => Value is >= MinValue and <= MaxValue; - - public static Coordinate Create(float value) => new((int)value - 1); - - public static bool TryCreateValid(float value, out Coordinate coordinate) - { - coordinate = default; - if (value != (int)value) { return false; } - - var result = Create(value); - - if (result.IsInRange) - { - coordinate = result; - return true; - } - - return false; - } - - public Coordinate BringIntoRange(IRandom random) - => Value switch - { - < MinValue => new(MinValue + (int)random.NextFloat(2.5F)), - > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)), - _ => this - }; - - public static implicit operator Coordinate(float value) => new((int)value); - public static implicit operator int(Coordinate coordinate) => coordinate.Value; - - public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); - public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; - - public override string ToString() => $" {Value + 1} "; -} - -internal record struct Offset(int X, int Y) -{ - public static readonly Offset Zero = 0; - - public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); - - public static implicit operator Offset(int value) => new(value, value); - - public static IEnumerable Units - { - get - { - for (int x = -1; x <= 1; x++) - { - for (int y = -1; y <= 1; y++) - { - var offset = new Offset(x, y); - if (offset != Zero) { yield return offset; } - } - } - } - } -} diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Grid.cs new file mode 100644 index 00000000..c3d04dff --- /dev/null +++ b/77_Salvo/csharp/Grid.cs @@ -0,0 +1,89 @@ +using System.Collections.Immutable; + +namespace Salvo; + +internal class Grid +{ + private readonly List _ships; + private readonly Dictionary _shots = new(); + + internal Grid() + { + _ships = new(); + } + + internal Grid(IReadWrite io) + { + io.WriteLine("ENTER COORDINATES FOR..."); + _ships = new() + { + new Battleship(io), + new Cruiser(io), + new Destroyer("A", io), + new Destroyer("B", io) + }; + } + + internal Grid(IRandom random) + { + _ships = new(); + while (true) + { + _ships.Add(new Battleship(random)); + if (TryPositionShip(() => new Cruiser(random)) && + TryPositionShip(() => new Destroyer("A", random)) && + TryPositionShip(() => new Destroyer("B", random))) + { + return; + } + _ships.Clear(); + } + + bool TryPositionShip(Func shipFactory) + { + var shipGenerationAttempts = 0; + while (true) + { + var ship = shipFactory.Invoke(); + shipGenerationAttempts++; + if (shipGenerationAttempts > 25) { return false; } + if (_ships.Min(ship.DistanceTo) >= 3.59) + { + _ships.Add(ship); + return true; + } + } + } + } + + public float this[Position position] + { + get => _shots.TryGetValue(position, out var value) + ? value + 10 + : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; + set + { + _ = _ships.FirstOrDefault(s => s.IsHit(position)); + _shots[position] = (int)value - 10; + } + } + + internal int UntriedSquareCount => 100 - _shots.Count; + internal IEnumerable Ships => _ships.AsEnumerable(); + + internal bool WasTargetedAt(Position position, out int turnTargeted) + => _shots.TryGetValue(position, out turnTargeted); + + internal bool IsHit(Position position, int turnNumber, out string? shipName) + { + shipName = null; + _shots[position] = turnNumber; + + var ship = _ships.FirstOrDefault(s => s.IsHit(position)); + if (ship == null) { return false; } + + if (ship.IsDestroyed) { _ships.Remove(ship); } + + return true; + } +} diff --git a/77_Salvo/csharp/Offset.cs b/77_Salvo/csharp/Offset.cs new file mode 100644 index 00000000..3c873f10 --- /dev/null +++ b/77_Salvo/csharp/Offset.cs @@ -0,0 +1,25 @@ +namespace Salvo; + +internal record struct Offset(int X, int Y) +{ + public static readonly Offset Zero = 0; + + public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); + + public static implicit operator Offset(int value) => new(value, value); + + public static IEnumerable Units + { + get + { + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + var offset = new Offset(x, y); + if (offset != Zero) { yield return offset; } + } + } + } + } +} diff --git a/77_Salvo/csharp/Position.cs b/77_Salvo/csharp/Position.cs new file mode 100644 index 00000000..3bafe217 --- /dev/null +++ b/77_Salvo/csharp/Position.cs @@ -0,0 +1,52 @@ +namespace Salvo; + +internal record struct Position(Coordinate X, Coordinate Y) +{ + public bool IsInRange => X.IsInRange && Y.IsInRange; + public bool IsOnDiagonal => X == Y; + + public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y); + + public static bool TryCreateValid((float X, float Y) coordinates, out Position position) + { + if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y)) + { + position = new(x, y); + return true; + } + + position = default; + return false; + } + + public static IEnumerable All + => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y))); + + public IEnumerable Neighbours + { + get + { + foreach (var offset in Offset.Units) + { + var neighbour = this + offset; + if (neighbour.IsInRange) { yield return neighbour; } + } + } + } + + internal float DistanceTo(Position other) + { + var (deltaX, deltaY) = (X - other.X, Y - other.Y); + return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY); + } + + internal Position BringIntoRange(IRandom random) + => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); + + public static Position operator +(Position position, Offset offset) + => new(position.X + offset.X, position.Y + offset.Y); + + public static implicit operator Position(int value) => new(value, value); + + public override string ToString() => $"{X}{Y}"; +} diff --git a/77_Salvo/csharp/Program.cs b/77_Salvo/csharp/Program.cs index b9d6a84c..6878fd38 100644 --- a/77_Salvo/csharp/Program.cs +++ b/77_Salvo/csharp/Program.cs @@ -1,7 +1,8 @@ global using System; global using Games.Common.IO; global using Games.Common.Randomness; +global using Salvo; +global using Salvo.Ships; global using static Salvo.Resources.Resource; -using Salvo; new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/77_Salvo/csharp/Ships/Battleship.cs b/77_Salvo/csharp/Ships/Battleship.cs new file mode 100644 index 00000000..1e57e59d --- /dev/null +++ b/77_Salvo/csharp/Ships/Battleship.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Battleship : Ship +{ + internal Battleship(IReadWrite io) + : base(io) + { + } + + internal Battleship(IRandom random) + : base(random) + { + } + + internal override int Shots => 3; + internal override int Size => 5; + internal override float Value => 3; +} diff --git a/77_Salvo/csharp/Ships/Cruiser.cs b/77_Salvo/csharp/Ships/Cruiser.cs new file mode 100644 index 00000000..33f30e38 --- /dev/null +++ b/77_Salvo/csharp/Ships/Cruiser.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Cruiser : Ship +{ + internal Cruiser(IReadWrite io) + : base(io) + { + } + + internal Cruiser(IRandom random) + : base(random) + { + } + + internal override int Shots => 2; + internal override int Size => 3; + internal override float Value => 2; +} diff --git a/77_Salvo/csharp/Ships/Destroyer.cs b/77_Salvo/csharp/Ships/Destroyer.cs new file mode 100644 index 00000000..0e2a023b --- /dev/null +++ b/77_Salvo/csharp/Ships/Destroyer.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Destroyer : Ship +{ + internal Destroyer(string nameIndex, IReadWrite io) + : base(io, $"<{nameIndex}>") + { + } + + internal Destroyer(string nameIndex, IRandom random) + : base(random, $"<{nameIndex}>") + { + } + + internal override int Shots => 1; + internal override int Size => 2; + internal override float Value => Name.EndsWith("") ? 1 : 0.5F; +} diff --git a/77_Salvo/csharp/Ships/Ship.cs b/77_Salvo/csharp/Ships/Ship.cs new file mode 100644 index 00000000..58f311c2 --- /dev/null +++ b/77_Salvo/csharp/Ships/Ship.cs @@ -0,0 +1,38 @@ +namespace Salvo.Ships; + +internal abstract class Ship +{ + private readonly List _positions = new(); + + protected Ship(IReadWrite io, string? nameSuffix = null) + { + Name = GetType().Name + nameSuffix; + _positions = io.ReadPositions(Name, Size).ToList(); + } + + protected Ship(IRandom random, string? nameSuffix = null) + { + Name = GetType().Name + nameSuffix; + + var (start, delta) = random.GetRandomShipPositionInRange(Size); + for (var i = 0; i < Size; i++) + { + _positions.Add(start + delta * i); + } + } + + internal string Name { get; } + internal abstract int Shots { get; } + internal abstract int Size { get; } + internal abstract float Value { get; } + internal IEnumerable Positions => _positions; + internal bool IsDestroyed => _positions.Count == 0; + + internal bool IsHit(Position position) => _positions.Remove(position); + + internal float DistanceTo(Ship other) + => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min(); + + public override string ToString() + => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name)); +} diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs new file mode 100644 index 00000000..1cf2a98a --- /dev/null +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -0,0 +1,23 @@ +namespace Salvo.Targetting; + +internal abstract class ComputerShotSelector : ShotSelector +{ + private readonly bool _displayShots; + + internal ComputerShotSelector(Grid source, Grid target, bool displayShots) + : base(source, target) + { + _displayShots = displayShots; + } + + private void DisplayShots(IEnumerable shots, IReadWrite io) + { + if (_displayShots) + { + foreach (var shot in shots) + { + io.WriteLine(shot); + } + } + } +} diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs new file mode 100644 index 00000000..6a50330a --- /dev/null +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -0,0 +1,31 @@ +namespace Salvo.Targetting; + +internal class HumanShotSelector : ShotSelector +{ + public HumanShotSelector(Grid source, Grid target) + : base(source, target) + { + } + + public IEnumerable GetShots(IReadWrite io) + { + var shots = new Position[GetShotCount()]; + + for (var i = 0; i < shots.Length; i++) + { + while (true) + { + var position = io.ReadValidPosition(); + if (Target.WasTargetedAt(position, out var turnTargeted)) + { + io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); + continue; + } + shots[i] = position; + break; + } + } + + return shots; + } +} diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs new file mode 100644 index 00000000..fae30f31 --- /dev/null +++ b/77_Salvo/csharp/Targetting/ShotSelector.cs @@ -0,0 +1,15 @@ +namespace Salvo.Targetting; + +internal abstract class ShotSelector +{ + internal ShotSelector(Grid source, Grid target) + { + Source = source; + Target = target; + } + + protected Grid Source { get; } + protected Grid Target { get; } + + public int GetShotCount() => Source.Ships.Sum(s => s.Shots); +}