mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-18 07:45:53 -08:00
Add SearchPatternShotSelector
This commit is contained in:
@@ -28,7 +28,8 @@ internal class Game
|
||||
}
|
||||
var computerGrid = new Grid(_random);
|
||||
var humanGrid = new Grid(_io);
|
||||
var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid);
|
||||
var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid, _io);
|
||||
var computerShotSelector = new SearchPatternShotSelector(computerGrid, humanGrid, _random);
|
||||
var startResponse = _io.ReadString(Prompts.Start);
|
||||
while (startResponse == Strings.WhereAreYourShips)
|
||||
{
|
||||
@@ -45,7 +46,7 @@ L1930: if (startResponse != "YES") { goto L2620; }
|
||||
L1950: if (startResponse != "YES") { goto L1990; }
|
||||
L1960: turnNumber++;
|
||||
L1980: _io.Write(Strings.Turn(turnNumber));
|
||||
L1990: var numberOfShots = humanShotSelector.GetShotCount();
|
||||
L1990: var numberOfShots = humanShotSelector.NumberOfShots;
|
||||
L2220: _io.Write(Strings.YouHaveShots(numberOfShots));
|
||||
if (numberOfShots == 0) { goto L2270; }
|
||||
L2230: if (numberOfShots > computerGrid.UntriedSquareCount)
|
||||
@@ -53,7 +54,7 @@ L2230: if (numberOfShots > computerGrid.UntriedSquareCount)
|
||||
_io.WriteLine(Streams.YouHaveMoreShotsThanSquares);
|
||||
L2250: goto L2890;
|
||||
}
|
||||
foreach (var shot1 in humanShotSelector.GetShots(_io))
|
||||
foreach (var shot1 in humanShotSelector.GetShots())
|
||||
{
|
||||
if (computerGrid.IsHit(shot1, turnNumber, out var shipName))
|
||||
{
|
||||
@@ -63,7 +64,7 @@ L2250: goto L2890;
|
||||
L2620: if (startResponse == "YES") { goto L2670; }
|
||||
L2640: turnNumber++;
|
||||
L2660: _io.Write(Strings.Turn(turnNumber));
|
||||
L2670: numberOfShots = computerGrid.Ships.Sum(s => s.Shots);
|
||||
L2670: numberOfShots = computerShotSelector.NumberOfShots;
|
||||
L2840: _io.Write(Strings.IHaveShots(numberOfShots));
|
||||
L2850: if (humanGrid.UntriedSquareCount > numberOfShots) { goto L2880; }
|
||||
L2860: _io.Write(Streams.IHaveMoreShotsThanSquares);
|
||||
@@ -78,70 +79,28 @@ L2960: for (var i = 1; i <= 12; i++)
|
||||
// if damaged ships
|
||||
L2970: if (hitShipValue[i]>0) { goto L3800; }
|
||||
}
|
||||
L3000: var shotCount=0;
|
||||
L3010: var shotAttempts=0;
|
||||
L3020: var (shot, _) = _random.NextShipPosition();
|
||||
L3030: var strategyNumber=0; //RESTORE
|
||||
L3050: shotAttempts++;
|
||||
L3060: if (shotAttempts>100) { goto L3010; }
|
||||
// ensure shot is in range
|
||||
L3070: shot = shot.BringIntoRange(_random);
|
||||
L3170: goto L3270;
|
||||
// record shot
|
||||
L3180: temp[shotCount]=shot;
|
||||
L3200: if (shotCount==numberOfShots) { goto L3380; }
|
||||
L3210: if (strategyNumber==6) { goto L3030; }
|
||||
L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1
|
||||
var data = new Offset[] { new(1,1),new(-1,1),new(1,-3),new(1,1),new(0,2),new(-1,1) };
|
||||
L3220: //READ X1,Y1
|
||||
var offset = data[strategyNumber++];
|
||||
L3250: shot+=offset;
|
||||
// is the shot in range?
|
||||
L3270: if (!shot.IsInRange) { goto L3210; }
|
||||
// have we fired here before
|
||||
L3310: if (humanGrid[shot]>10) { goto L3210; }
|
||||
// have we already selected this shot?
|
||||
L3320: for (var i = 1; i <= shotCount; i++)
|
||||
{
|
||||
L3330: if (temp[i] == shot) { goto L3210; }
|
||||
}
|
||||
L3360: shotCount++;
|
||||
L3370: goto L3180;
|
||||
temp = computerShotSelector.GetShots().ToArray();
|
||||
// display shots
|
||||
L3380: if (seeShotsResponse != "YES") { goto L3420; }
|
||||
L3390: for (var i = 1; i <= numberOfShots; i++)
|
||||
L3380: if (seeShotsResponse == "yes")
|
||||
{
|
||||
L3400: _io.WriteLine(temp[i]);
|
||||
}
|
||||
L3420: for (var i = 1; i <= numberOfShots; i++)
|
||||
{
|
||||
L3430: if (humanGrid[temp[i]] == 3)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR BATTLESHIP");
|
||||
}
|
||||
else if (humanGrid[temp[i]] == 2)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR CRUISER");
|
||||
}
|
||||
else if (humanGrid[temp[i]] == 1)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR DESTROYER<A>");
|
||||
}
|
||||
else if (humanGrid[temp[i]] == .5F)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR DESTROYER<B>");
|
||||
}
|
||||
else
|
||||
foreach (var shot in temp)
|
||||
{
|
||||
humanGrid[temp[i]]=10+turnNumber;
|
||||
_io.WriteLine(shot);
|
||||
}
|
||||
}
|
||||
foreach (var shot in temp)
|
||||
{
|
||||
if (!humanGrid.IsHit(shot, turnNumber, out var shipName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_io.WriteLine(Strings.IHit(shipName));
|
||||
L3570: for (var j = 1; j <= 12; j++)
|
||||
{
|
||||
// record hit
|
||||
L3580: if (hitTurnRecord[j] != -1) { continue; }
|
||||
L3590: hitTurnRecord[j]=10+turnNumber;
|
||||
L3600: hitShipValue[j]=humanGrid[temp[i]];
|
||||
L3600: hitShipValue[j]=humanGrid[shot];
|
||||
// look for past hits on same ship
|
||||
L3610: var shipHits=0;
|
||||
L3620: for (var k = 1; k <= 12; k++)
|
||||
@@ -169,7 +128,7 @@ L3760: _io.WriteLine($"{nameof(hitTurnRecord)}( {j} ) = {hitTurnRecord[
|
||||
L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}");
|
||||
}
|
||||
return;
|
||||
L3470: humanGrid[temp[i]]=10+turnNumber;
|
||||
L3470: humanGrid[shot]=10+turnNumber;
|
||||
}
|
||||
L3490: goto L1950;
|
||||
L3800: //REM************************USINGEARRAY
|
||||
|
||||
@@ -21,6 +21,7 @@ internal static class Resource
|
||||
public static string YouHaveShots(int number) => Format(number);
|
||||
public static string IHaveShots(int number) => Format(number);
|
||||
public static string YouHit(string shipName) => Format(shipName);
|
||||
public static string IHit(string shipName) => Format(shipName);
|
||||
public static string ShotBefore(int turnNumber) => Format(turnNumber);
|
||||
public static string Turn(int number) => Format(number);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Salvo.Targetting;
|
||||
|
||||
internal abstract class ComputerShotSelector : ShotSelector
|
||||
internal class ComputerShotSelector : ShotSelector
|
||||
{
|
||||
private readonly bool _displayShots;
|
||||
|
||||
|
||||
@@ -2,23 +2,26 @@ namespace Salvo.Targetting;
|
||||
|
||||
internal class HumanShotSelector : ShotSelector
|
||||
{
|
||||
public HumanShotSelector(Grid source, Grid target)
|
||||
private readonly IReadWrite _io;
|
||||
|
||||
internal HumanShotSelector(Grid source, Grid target, IReadWrite io)
|
||||
: base(source, target)
|
||||
{
|
||||
_io = io;
|
||||
}
|
||||
|
||||
public IEnumerable<Position> GetShots(IReadWrite io)
|
||||
internal override IEnumerable<Position> GetShots()
|
||||
{
|
||||
var shots = new Position[GetShotCount()];
|
||||
var shots = new Position[NumberOfShots()];
|
||||
|
||||
for (var i = 0; i < shots.Length; i++)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var position = io.ReadValidPosition();
|
||||
var position = _io.ReadValidPosition();
|
||||
if (Target.WasTargetedAt(position, out var turnTargeted))
|
||||
{
|
||||
io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}");
|
||||
_io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}");
|
||||
continue;
|
||||
}
|
||||
shots[i] = position;
|
||||
|
||||
22
77_Salvo/csharp/Targetting/SearchPattern.cs
Normal file
22
77_Salvo/csharp/Targetting/SearchPattern.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Salvo.Targetting;
|
||||
|
||||
internal class SearchPattern
|
||||
{
|
||||
private static readonly ImmutableArray<Offset> _offsets =
|
||||
ImmutableArray.Create<Offset>(new(1, 1), new(-1, 1), new(1, -3), new(1, 1), new(0, 2), new(-1, 1));
|
||||
|
||||
private int _nextIndex;
|
||||
|
||||
internal bool TryGetOffset(out Offset offset)
|
||||
{
|
||||
offset = default;
|
||||
if (_nextIndex >= _offsets.Length) { return false; }
|
||||
|
||||
offset = _offsets[_nextIndex++];
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Reset() => _nextIndex = 0;
|
||||
}
|
||||
54
77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs
Normal file
54
77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
namespace Salvo.Targetting;
|
||||
|
||||
internal class SearchPatternShotSelector : ShotSelector
|
||||
{
|
||||
private const int MaxSearchPatternAttempts = 100;
|
||||
private readonly IRandom _random;
|
||||
private readonly SearchPattern _searchPattern = new();
|
||||
private readonly List<Position> _shots = new();
|
||||
|
||||
internal SearchPatternShotSelector(Grid source, Grid target, IRandom random)
|
||||
: base(source, target)
|
||||
{
|
||||
_random = random;
|
||||
}
|
||||
|
||||
internal override IEnumerable<Position> GetShots()
|
||||
{
|
||||
while(_shots.Count < NumberOfShots)
|
||||
{
|
||||
var (seed, _) = _random.NextShipPosition();
|
||||
SearchFrom(seed);
|
||||
}
|
||||
return _shots;
|
||||
}
|
||||
|
||||
private void SearchFrom(Position candidateShot)
|
||||
{
|
||||
var attemptsLeft = MaxSearchPatternAttempts;
|
||||
while (true)
|
||||
{
|
||||
_searchPattern.Reset();
|
||||
if (attemptsLeft-- == 0) { return; }
|
||||
candidateShot = candidateShot.BringIntoRange(_random);
|
||||
if (FindValidShots(candidateShot)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
private bool FindValidShots(Position candidateShot)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (IsValidShot(candidateShot))
|
||||
{
|
||||
_shots.Add(candidateShot);
|
||||
if (_shots.Count == NumberOfShots) { return true; }
|
||||
}
|
||||
if (!_searchPattern.TryGetOffset(out var offset)) { return false; }
|
||||
candidateShot += offset;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValidShot(Position candidate)
|
||||
=> candidate.IsInRange && !Target.WasTargetedAt(candidate, out _) && !_shots.Contains(candidate);
|
||||
}
|
||||
@@ -11,5 +11,7 @@ internal abstract class ShotSelector
|
||||
protected Grid Source { get; }
|
||||
protected Grid Target { get; }
|
||||
|
||||
public int GetShotCount() => Source.Ships.Sum(s => s.Shots);
|
||||
internal int NumberOfShots => Source.Ships.Sum(s => s.Shots);
|
||||
|
||||
internal abstract IEnumerable<Position> GetShots();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user