diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 3c382521..4d4551d1 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -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"); - _io.WriteLine($" {tempX[9]} {tempY[9]} "); - _io.WriteLine($" {tempX[10]} {tempY[10]} "); + _io.WriteLine(temp[9]); + _io.WriteLine(temp[10]); _io.WriteLine("DESTROYER"); - _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.", .5F => "YOU HIT MY DESTROYER.", - _ => 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"); } - else if (humanGrid[tempX[i],tempY[i]] == .5F) + else if (humanGrid[temp[i].X,temp[i].Y] == .5F) { _io.WriteLine("I HIT YOUR DESTROYER"); } 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]=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); +}