mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-08 19:33:31 -08:00
Introduce Coordinate and Offset
This commit is contained in:
@@ -21,14 +21,10 @@ internal class Game
|
||||
{
|
||||
_io.Write(Streams.Title);
|
||||
|
||||
|
||||
L1040:
|
||||
var humanGrid = new float[11,11];
|
||||
var shotsX = new int[8];
|
||||
var shotsY = new int[8];
|
||||
L1040: var humanGrid = new float[11,11];
|
||||
var hitTurnRecord = new int[13];
|
||||
var tempX = new int[13];
|
||||
var tempY = new int[13];
|
||||
var shots = new Coordinates[8];
|
||||
var temp = new Coordinates[13];
|
||||
var hitShipValue = new float[13];
|
||||
L1060: for (var i = 1; i <= 12; i++)
|
||||
{
|
||||
@@ -39,14 +35,13 @@ L1190: var computerGrid = new float[11,11];
|
||||
L1240: for (var K = 3; K >= 0; K--)
|
||||
{
|
||||
L1250: var shipGenerationAttempts=0;
|
||||
L1260: var (startX, startY, deltaY, deltaX) = GetRandomShipCoordinatesInRange(K);
|
||||
L1260: var (start, delta) = GetRandomShipCoordinatesInRange(K);
|
||||
L1340: shipGenerationAttempts++;
|
||||
L1350: if (shipGenerationAttempts>25) { goto L1190; }
|
||||
// determine ship coordinates
|
||||
L1360: for (var i = 0; i <= _shipSize[K] - 1; i++)
|
||||
L1360: for (var i = _shipFirstIndex[K]; i <= _shipFirstIndex[K] + _shipSize[K] - 1; i++)
|
||||
{
|
||||
tempX[i+_shipFirstIndex[K]]=startX+deltaX*i;
|
||||
L1380: tempY[i+_shipFirstIndex[K]]=startY+deltaY*i;
|
||||
temp[i] = start + delta * i;
|
||||
}
|
||||
L1400: var firstIndex=_shipFirstIndex[K];
|
||||
// detect proximity to previous ships
|
||||
@@ -55,13 +50,13 @@ L1400: var firstIndex=_shipFirstIndex[K];
|
||||
L1415: if (firstIndex<2) { continue; } // Only true for the Battleship
|
||||
L1420: for (var j = 1; j <= firstIndex-1; j++)
|
||||
{
|
||||
L1430: if (Math.Sqrt((tempX[j]-tempX[i])*(tempX[j]-tempX[i]) + (tempY[j]-tempY[i])*(tempY[j]-tempY[i])) < 3.59) { goto L1260; }
|
||||
L1430: if (temp[j].DistanceTo(temp[i]) < 3.59) { goto L1260; }
|
||||
}
|
||||
}
|
||||
// put ship on board
|
||||
L1460: for (var i = firstIndex; i <= firstIndex + _shipSize[K] - 1; i++)
|
||||
{
|
||||
computerGrid[tempX[i], tempY[i]] = _shipValue[K];
|
||||
computerGrid[temp[i].X, temp[i].Y] = _shipValue[K];
|
||||
}
|
||||
}
|
||||
L1500: _io.WriteLine("ENTER COORDINATES FOR...");
|
||||
@@ -95,18 +90,18 @@ L1730: while (startResponse == "WHERE ARE YOUR SHIPS?")
|
||||
_io.WriteLine("BATTLESHIP");
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
_io.WriteLine($" {tempX[i]} {tempY[i]} ");
|
||||
_io.WriteLine(temp[i]);
|
||||
}
|
||||
_io.WriteLine("CRUISER");
|
||||
_io.WriteLine($" {tempX[6]} {tempY[6]} ");
|
||||
_io.WriteLine($" {tempX[7]} {tempY[7]} ");
|
||||
_io.WriteLine($" {tempX[8]} {tempY[8]} ");
|
||||
_io.WriteLine(temp[6]);
|
||||
_io.WriteLine(temp[7]);
|
||||
_io.WriteLine(temp[8]);
|
||||
_io.WriteLine("DESTROYER<A>");
|
||||
_io.WriteLine($" {tempX[9]} {tempY[9]} ");
|
||||
_io.WriteLine($" {tempX[10]} {tempY[10]} ");
|
||||
_io.WriteLine(temp[9]);
|
||||
_io.WriteLine(temp[10]);
|
||||
_io.WriteLine("DESTROYER<B>");
|
||||
_io.WriteLine($" {tempX[11]} {tempY[11]} ");
|
||||
_io.WriteLine($" {tempX[12]} {tempY[12]} ");
|
||||
_io.WriteLine(temp[11]);
|
||||
_io.WriteLine(temp[12]);
|
||||
|
||||
startResponse = _io.ReadString("DO YOU WANT TO START");
|
||||
}
|
||||
@@ -133,7 +128,7 @@ L2070: maxShotCount+=(int)(shipValue+.5F);
|
||||
}
|
||||
L2090: for (var i = 1; i <= 7; i++)
|
||||
{
|
||||
L2100: shotsX[i] = shotsY[i] = tempX[i] = tempY[i] = 0;
|
||||
shots[i] = temp[i] = 0;
|
||||
}
|
||||
L2150: var untriedSquareCount=0;
|
||||
L2160: for (var x = 1; x <= 10; x++)
|
||||
@@ -160,22 +155,21 @@ L2390: if (computerGrid[x,y]>10)
|
||||
_io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[x,y]-10}");
|
||||
continue;
|
||||
}
|
||||
shotsX[i]=x;
|
||||
shotsY[i]=y;
|
||||
shots[i]= new(x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
L2460: for (var W = 1; W <= maxShotCount; W++)
|
||||
{
|
||||
_io.WriteLine(computerGrid[shotsX[W],shotsY[W]] switch
|
||||
_io.WriteLine(computerGrid[shots[W].X,shots[W].Y] switch
|
||||
{
|
||||
3 => "YOU HIT MY BATTLESHIP.",
|
||||
2 => "YOU HIT MY CRUISER.",
|
||||
1 => "YOU HIT MY DESTROYER<A>.",
|
||||
.5F => "YOU HIT MY DESTROYER<B>.",
|
||||
_ => throw new InvalidOperationException($"Unexpected value {computerGrid[shotsX[W],shotsY[W]]}")
|
||||
_ => throw new InvalidOperationException($"Unexpected value {computerGrid[shots[W].X,shots[W].Y]}")
|
||||
});
|
||||
L2510: computerGrid[shotsX[W],shotsY[W]] = 10+turnNumber;
|
||||
L2510: computerGrid[shots[W].X,shots[W].Y] = 10+turnNumber;
|
||||
}
|
||||
L2620: if (startResponse == "YES") { goto L2670; }
|
||||
L2640: turnNumber++;
|
||||
@@ -221,47 +215,30 @@ L2970: if (hitShipValue[i]>0) { goto L3800; }
|
||||
}
|
||||
L3000: var shotCount=0;
|
||||
L3010: var shotAttempts=0;
|
||||
L3020: var (shotX, shotY, _, _) = GetRandomShipCoordinates();
|
||||
L3030: //RESTORE
|
||||
var index = 0;
|
||||
L3040: var strategyNumber=0;
|
||||
L3020: var (shot, _) = GetRandomShipCoordinates();
|
||||
L3030: var strategyNumber=0; //RESTORE
|
||||
L3050: shotAttempts++;
|
||||
L3060: if (shotAttempts>100) { goto L3010; }
|
||||
// ensure shot is in range
|
||||
L3070: if (shotX>10) { goto L3110; }
|
||||
L3080: if (shotX>0) { goto L3120; }
|
||||
L3090: shotX = 1 + (int)_random.NextFloat(2.5F);
|
||||
L3100: goto L3120;
|
||||
L3110: shotX = 10 - (int)_random.NextFloat(2.5F);
|
||||
L3120: if (shotY>10) { goto L3160; }
|
||||
L3130: if (shotY>0) { goto L3270; }
|
||||
L3140: shotY=1+(int)_random.NextFloat(2.5F);
|
||||
L3150: goto L3270;
|
||||
L3160: shotY=10-(int)_random.NextFloat(2.5F);
|
||||
L3070: shot = shot.BringIntoRange(_random);
|
||||
L3170: goto L3270;
|
||||
// record shot
|
||||
L3180: tempX[shotCount]=shotX;
|
||||
L3190: tempY[shotCount]=shotY;
|
||||
L3180: temp[shotCount]=shot;
|
||||
L3200: if (shotCount==maxShotCount) { 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[] { 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 (xOffset, yOffset) = (data[index++], data[index++]);
|
||||
L3230: strategyNumber++;
|
||||
L3250: shotX+=xOffset;
|
||||
L3260: shotY+=yOffset;
|
||||
var offset = data[strategyNumber++];
|
||||
L3250: shot+=offset;
|
||||
// is the shot in range?
|
||||
L3270: if (shotX>10) { goto L3210; }
|
||||
L3280: if (shotX<1) { goto L3210; }
|
||||
L3290: if (shotY>10) { goto L3210; }
|
||||
L3300: if (shotY<1) { goto L3210; }
|
||||
L3270: if (!shot.IsInRange) { goto L3210; }
|
||||
// have we fired here before
|
||||
L3310: if (humanGrid[shotX,shotY]>10) { goto L3210; }
|
||||
L3310: if (humanGrid[shot.X,shot.Y]>10) { goto L3210; }
|
||||
// have we already selected this shot?
|
||||
L3320: for (var i = 1; i <= shotCount; i++)
|
||||
{
|
||||
L3330: if (tempX[i] == shotX && tempY[i] == shotY) { goto L3210; }
|
||||
L3330: if (temp[i] == shot) { goto L3210; }
|
||||
}
|
||||
L3360: shotCount++;
|
||||
L3370: goto L3180;
|
||||
@@ -269,29 +246,29 @@ L3370: goto L3180;
|
||||
L3380: if (seeShotsResponse != "YES") { goto L3420; }
|
||||
L3390: for (var i = 1; i <= maxShotCount; i++)
|
||||
{
|
||||
L3400: _io.WriteLine($" {tempX[i]} {tempY[i]}");
|
||||
L3400: _io.WriteLine(temp[i]);
|
||||
}
|
||||
L3420: for (var i = 1; i <= maxShotCount; i++)
|
||||
{
|
||||
L3430: if (humanGrid[tempX[i],tempY[i]] == 3)
|
||||
L3430: if (humanGrid[temp[i].X,temp[i].Y] == 3)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR BATTLESHIP");
|
||||
}
|
||||
else if (humanGrid[tempX[i],tempY[i]] == 2)
|
||||
else if (humanGrid[temp[i].X,temp[i].Y] == 2)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR CRUISER");
|
||||
}
|
||||
else if (humanGrid[tempX[i],tempY[i]] == 1)
|
||||
else if (humanGrid[temp[i].X,temp[i].Y] == 1)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR DESTROYER<A>");
|
||||
}
|
||||
else if (humanGrid[tempX[i],tempY[i]] == .5F)
|
||||
else if (humanGrid[temp[i].X,temp[i].Y] == .5F)
|
||||
{
|
||||
_io.WriteLine("I HIT YOUR DESTROYER<B>");
|
||||
}
|
||||
else
|
||||
{
|
||||
humanGrid[tempX[i],tempY[i]]=10+turnNumber;
|
||||
humanGrid[temp[i].X,temp[i].Y]=10+turnNumber;
|
||||
continue;
|
||||
}
|
||||
L3570: for (var j = 1; j <= 12; j++)
|
||||
@@ -299,7 +276,7 @@ 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[tempX[i],tempY[i]];
|
||||
L3600: hitShipValue[j]=humanGrid[temp[i].X,temp[i].Y];
|
||||
// look for past hits on same ship
|
||||
L3610: var shipHits=0;
|
||||
L3620: for (var k = 1; k <= 12; k++)
|
||||
@@ -327,11 +304,11 @@ L3760: _io.WriteLine($"{nameof(hitTurnRecord)}( {j} ) = {hitTurnRecord[
|
||||
L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}");
|
||||
}
|
||||
return;
|
||||
L3470: humanGrid[tempX[i],tempY[i]]=10+turnNumber;
|
||||
L3470: humanGrid[temp[i].X,temp[i].Y]=10+turnNumber;
|
||||
}
|
||||
L3490: goto L1950;
|
||||
L3800: //REM************************USINGEARRAY
|
||||
var temp = new int[11,11];
|
||||
var tempGrid = new int[11,11];
|
||||
L3860: for (var i = 1; i <= 12; i++)
|
||||
{
|
||||
L3870: if (hitTurnRecord[i]<10) { continue; }
|
||||
@@ -348,22 +325,21 @@ L3940: for (var dY = Math.Sign(1-y); dY <= Math.Sign(10-y);
|
||||
L3950: if (dX == 0 && dY ==0) { continue; }
|
||||
L3960: if (humanGrid[x+dX,y+dY] == hitTurnRecord[i])
|
||||
{
|
||||
L3970: temp[x,y]=temp[x,y]+hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F);
|
||||
L3970: tempGrid[x,y] += hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
L3910: temp[x,y]=-10000000;
|
||||
L3910: tempGrid[x,y]=-10000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
L4030: for (var i = 1; i <= maxShotCount; i++)
|
||||
{
|
||||
L4040: tempX[i]=i;
|
||||
L4050: tempY[i]=i;
|
||||
L4040: temp[i]=i;
|
||||
}
|
||||
L4070: for (var x = 1; x <= 10; x++)
|
||||
{
|
||||
@@ -372,19 +348,18 @@ L4080: for (var y = 1; y <= 10; y++)
|
||||
L4090: var Q9=1;
|
||||
L4100: for (var i = 1; i <= maxShotCount; i++)
|
||||
{
|
||||
L4110: if (temp[tempX[i],tempY[i]]>=temp[tempX[Q9],tempY[Q9]]) { continue; }
|
||||
L4110: if (tempGrid[temp[i].X,temp[i].Y]>=tempGrid[temp[Q9].X,temp[Q9].Y]) { continue; }
|
||||
L4120: Q9=i;
|
||||
}
|
||||
L4131: if (x>maxShotCount) { goto L4140; }
|
||||
L4132: if (x==y) { goto L4210; }
|
||||
L4140: if (temp[x,y]<temp[tempX[Q9],tempY[Q9]]) { goto L4210; }
|
||||
L4140: if (tempGrid[x,y]<tempGrid[temp[Q9].X,temp[Q9].Y]) { goto L4210; }
|
||||
L4150: for (var i = 1; i <= maxShotCount; i++)
|
||||
{
|
||||
L4160: if (tempX[i] != x) { break; }
|
||||
L4170: if (tempY[i] == y) { goto L4210; }
|
||||
L4160: if (temp[i].X != x) { break; }
|
||||
L4170: if (temp[i].Y == y) { goto L4210; }
|
||||
}
|
||||
L4190: tempX[Q9]=x;
|
||||
L4200: tempY[Q9]=y;
|
||||
L4190: temp[Q9]=new(x, y);
|
||||
L4210: x=x;// NoOp - NEXT S
|
||||
}
|
||||
}
|
||||
@@ -392,26 +367,25 @@ L4230: goto L3380;
|
||||
|
||||
}
|
||||
|
||||
private (int, int, int, int) GetRandomShipCoordinates()
|
||||
private (Coordinates, Offset) GetRandomShipCoordinates()
|
||||
{
|
||||
var startX = _random.Next(1, 11);
|
||||
var startY = _random.Next(1, 11);
|
||||
var deltaY = _random.Next(-1, 2);
|
||||
var deltaX = _random.Next(-1, 2);
|
||||
return (startX, startY, deltaY, deltaX);
|
||||
return (new(startX, startY), new(deltaX, deltaY));
|
||||
}
|
||||
|
||||
private (int, int, int, int) GetRandomShipCoordinatesInRange(int shipNumber)
|
||||
private (Coordinates, Offset) GetRandomShipCoordinatesInRange(int shipNumber)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var (startX, startY, deltaY, deltaX) = GetRandomShipCoordinates();
|
||||
var (start, delta) = GetRandomShipCoordinates();
|
||||
var shipSizeLessOne = _shipSize[shipNumber] - 1;
|
||||
var endX = startX + deltaX * shipSizeLessOne;
|
||||
var endY = startY + deltaY * shipSizeLessOne;
|
||||
if ((deltaX != 0 || deltaY != 0) && endX>=1 && endX<=10 && endY>=1 && endY<=10)
|
||||
var end = start + delta * shipSizeLessOne;
|
||||
if (delta != 0 && end.IsInRange)
|
||||
{
|
||||
return (startX, startY, deltaX, deltaY);
|
||||
return (start, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,3 +412,42 @@ internal static class IOExtensions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal record struct Coordinates(int X, int Y)
|
||||
{
|
||||
internal Coordinates(float x, float y)
|
||||
: this((int)x, (int)y)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsInRange => X is >= 1 and <= 10 && Y is >= 1 and <= 10;
|
||||
|
||||
internal double DistanceTo(Coordinates other)
|
||||
=> Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y));
|
||||
|
||||
internal Coordinates BringIntoRange(IRandom random)
|
||||
=> IsInRange ? this : new(BringIntoRange(X, random), BringIntoRange(Y, random));
|
||||
|
||||
private int BringIntoRange(int value, IRandom random)
|
||||
=> value switch
|
||||
{
|
||||
< 1 => 1 + (int)random.NextFloat(2.5F),
|
||||
> 10 => 10 - (int)random.NextFloat(2.5F),
|
||||
_ => value
|
||||
};
|
||||
|
||||
public static Coordinates operator +(Coordinates coordinates, Offset offset)
|
||||
=> new(coordinates.X + offset.X, coordinates.Y + offset.Y);
|
||||
|
||||
public static implicit operator Coordinates(int value) => new(value, value);
|
||||
|
||||
public override string ToString() => $" {X} {Y} ";
|
||||
}
|
||||
|
||||
internal record struct Offset(int X, int Y)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user