diff --git a/31 Depth Charge/csharp/DepthCharge.sln b/31 Depth Charge/csharp/DepthCharge.sln
new file mode 100644
index 00000000..8d56c717
--- /dev/null
+++ b/31 Depth Charge/csharp/DepthCharge.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31129.286
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {738F08DD-89E9-44C5-B5AC-3F21C6AEEFA1}
+ EndGlobalSection
+EndGlobal
diff --git a/31 Depth Charge/csharp/Game.csproj b/31 Depth Charge/csharp/Game.csproj
new file mode 100644
index 00000000..3028f277
--- /dev/null
+++ b/31 Depth Charge/csharp/Game.csproj
@@ -0,0 +1,9 @@
+
+
+
+ Exe
+ net5.0
+ DepthCharge
+
+
+
diff --git a/31 Depth Charge/csharp/src/Controller.cs b/31 Depth Charge/csharp/src/Controller.cs
new file mode 100644
index 00000000..7669e67c
--- /dev/null
+++ b/31 Depth Charge/csharp/src/Controller.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace DepthCharge
+{
+ ///
+ /// Contains functions for reading input from the user.
+ ///
+ static class Controller
+ {
+ ///
+ /// Retrives a dimension for the play area from the user.
+ ///
+ ///
+ /// Note that the original BASIC version would allow dimension values
+ /// of 0 or less. We're doing a little extra validation here in order
+ /// to avoid strange behaviour.
+ ///
+ public static int InputDimension()
+ {
+ View.PromptDimension();
+
+ while (true)
+ {
+ if (!Int32.TryParse(Console.ReadLine(), out var dimension))
+ View.ShowInvalidNumber();
+ else
+ if (dimension < 1)
+ View.ShowInvalidDimension();
+ else
+ return dimension;
+ }
+ }
+
+ ///
+ /// Retrieves a set of coordinates from the user.
+ ///
+ ///
+ /// The current trail number.
+ ///
+ public static (int x, int y, int depth) InputCoordinates(int trailNumber)
+ {
+ View.PromptGuess(trailNumber);
+
+ while (true)
+ {
+ var coordinates = Console.ReadLine().Split(',');
+
+ if (coordinates.Length < 3)
+ View.ShowTooFewCoordinates();
+ else
+ if (coordinates.Length > 3)
+ View.ShowTooManyCoordinates();
+ else
+ if (!Int32.TryParse(coordinates[0], out var x) ||
+ !Int32.TryParse(coordinates[1], out var y) ||
+ !Int32.TryParse(coordinates[2], out var depth))
+ View.ShowInvalidNumber();
+ else
+ return (x, y, depth);
+ }
+ }
+
+ ///
+ /// Retrieves the user's intention to play again (or not).
+ ///
+ public static bool InputPlayAgain()
+ {
+ View.PromptPlayAgain();
+
+ while (true)
+ {
+ switch (Console.ReadLine())
+ {
+ case "Y":
+ return true;
+ case "N":
+ return false;
+ default:
+ View.ShowInvalidYesOrNo();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/31 Depth Charge/csharp/src/Program.cs b/31 Depth Charge/csharp/src/Program.cs
new file mode 100644
index 00000000..de3db6d9
--- /dev/null
+++ b/31 Depth Charge/csharp/src/Program.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace DepthCharge
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var random = new Random();
+
+ View.ShowBanner();
+
+ var dimension = Controller.InputDimension();
+ var maximumGuesses = CalculateMaximumGuesses();
+
+ View.ShowInstructions(maximumGuesses);
+
+ do
+ {
+ View.ShowStartGame();
+
+ var submarineCoordinates = PlaceSubmarine();
+ var trailNumber = 1;
+ var guess = (0, 0, 0);
+
+ do
+ {
+ guess = Controller.InputCoordinates(trailNumber);
+ if (guess != submarineCoordinates)
+ View.ShowGuessPlacement(submarineCoordinates, guess);
+ }
+ while (guess != submarineCoordinates && trailNumber++ < maximumGuesses);
+
+ View.ShowGameResult(submarineCoordinates, guess, trailNumber);
+ }
+ while (Controller.InputPlayAgain());
+
+ View.ShowFarewell();
+
+ int CalculateMaximumGuesses() =>
+ (int)Math.Log2(dimension) + 1;
+
+ (int x, int y, int depth) PlaceSubmarine() =>
+ (random.Next(dimension), random.Next(dimension), random.Next(dimension));
+ }
+ }
+}
diff --git a/31 Depth Charge/csharp/src/View.cs b/31 Depth Charge/csharp/src/View.cs
new file mode 100644
index 00000000..71e83a9f
--- /dev/null
+++ b/31 Depth Charge/csharp/src/View.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace DepthCharge
+{
+ ///
+ /// Contains methods for displaying information to the user.
+ ///
+ static class View
+ {
+ public static void ShowBanner()
+ {
+ Console.WriteLine(" DEPTH CHARGE");
+ Console.WriteLine(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+
+ public static void ShowInstructions(int maximumGuesses)
+ {
+ Console.WriteLine("YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER");
+ Console.WriteLine("AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR");
+ Console.WriteLine($"MISSION IS TO DESTROY IT. YOU HAVE {maximumGuesses} SHOTS.");
+ Console.WriteLine("SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A");
+ Console.WriteLine("TRIO OF NUMBERS -- THE FIRST TWO ARE THE");
+ Console.WriteLine("SURFACE COORDINATES; THE THIRD IS THE DEPTH.");
+ Console.WriteLine();
+ }
+
+ public static void ShowStartGame()
+ {
+ Console.WriteLine("GOOD LUCK !");
+ Console.WriteLine();
+ }
+
+ public static void ShowGuessPlacement((int x, int y, int depth) actual, (int x, int y, int depth) guess)
+ {
+ Console.Write("SONAR REPORTS SHOT WAS ");
+ if (guess.y > actual.y)
+ Console.Write("NORTH");
+ if (guess.y < actual.y)
+ Console.Write("SOUTH");
+ if (guess.x > actual.x)
+ Console.Write("EAST");
+ if (guess.x < actual.x)
+ Console.Write("WEST");
+ if (guess.y != actual.y || guess.x != actual.y)
+ Console.Write(" AND");
+ if (guess.depth > actual.depth)
+ Console.Write (" TOO LOW.");
+ if (guess.depth < actual.depth)
+ Console.Write(" TOO HIGH.");
+ if (guess.depth == actual.depth)
+ Console.Write(" DEPTH OK.");
+
+ Console.WriteLine();
+ }
+
+ public static void ShowGameResult((int x, int y, int depth) submarineLocation, (int x, int y, int depth) finalGuess, int trailNumber)
+ {
+ Console.WriteLine();
+
+ if (submarineLocation == finalGuess)
+ {
+ Console.WriteLine($"B O O M ! ! YOU FOUND IT IN {trailNumber} TRIES!");
+ }
+ else
+ {
+ Console.WriteLine("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!");
+ Console.WriteLine($"THE SUBMARINE WAS AT {submarineLocation.x}, {submarineLocation.y}, {submarineLocation.depth}");
+ }
+ }
+
+ public static void ShowFarewell()
+ {
+ Console.WriteLine ("OK. HOPE YOU ENJOYED YOURSELF.");
+ }
+
+ public static void ShowInvalidNumber()
+ {
+ Console.WriteLine("PLEASE ENTER A NUMBER");
+ }
+
+ public static void ShowInvalidDimension()
+ {
+ Console.WriteLine("PLEASE ENTER A VALID DIMENSION");
+ }
+
+ public static void ShowTooFewCoordinates()
+ {
+ Console.WriteLine("TOO FEW COORDINATES");
+ }
+
+ public static void ShowTooManyCoordinates()
+ {
+ Console.WriteLine("TOO MANY COORDINATES");
+ }
+
+ public static void ShowInvalidYesOrNo()
+ {
+ Console.WriteLine("PLEASE ENTER Y OR N");
+ }
+
+ public static void PromptDimension()
+ {
+ Console.Write("DIMENSION OF SEARCH AREA? ");
+ }
+
+ public static void PromptGuess(int trailNumber)
+ {
+ Console.WriteLine();
+ Console.Write($"TRIAL #{trailNumber}? ");
+ }
+
+ public static void PromptPlayAgain()
+ {
+ Console.WriteLine();
+ Console.Write("ANOTHER GAME (Y OR N)? ");
+ }
+ }
+}