diff --git a/67_One_Check/csharp/Board.cs b/67_One_Check/csharp/Board.cs new file mode 100644 index 00000000..2e68072d --- /dev/null +++ b/67_One_Check/csharp/Board.cs @@ -0,0 +1,64 @@ +namespace OneCheck; + +internal class Board +{ + private readonly bool[][] _checkers; + private int _pieceCount; + private int _moveCount; + + public Board() + { + _checkers = + Enumerable.Range(0, 8) + .Select(r => Enumerable.Range(0, 8) + .Select(c => r <= 1 || r >= 6 || c <= 1 || c >= 6).ToArray()) + .ToArray(); + _pieceCount = 48; + } + + private bool this[int index] + { + get => _checkers[index / 8][index % 8]; + set => _checkers[index / 8][index % 8] = value; + } + + public bool PlayMove(IReadWrite io) + { + while (true) + { + var from = (int)io.ReadNumber(Prompts.From); + if (from == 0) { return false; } + + var move = new Move { From = from - 1, To = (int)io.ReadNumber(Prompts.To) - 1 }; + + if (TryMove(move)) + { + _moveCount++; + return true; + } + + io.Write(Streams.IllegalMove); + } + } + + public bool TryMove(Move move) + { + if (move.IsInRange && move.IsTwoSpacesDiagonally && IsPieceJumpingPieceToEmptySpace(move)) + { + this[move.From] = false; + this[move.Jumped] = false; + this[move.To] = true; + _pieceCount--; + return true; + } + + return false; + } + + private bool IsPieceJumpingPieceToEmptySpace(Move move) => this[move.From] && this[move.Jumped] && !this[move.To]; + + public string GetReport() => string.Format(Formats.Results, _moveCount, _pieceCount); + + public override string ToString() => + string.Join(Environment.NewLine, _checkers.Select(r => string.Join(" ", r.Select(c => c ? " 1" : " 0")))); +} diff --git a/67_One_Check/csharp/Game.cs b/67_One_Check/csharp/Game.cs new file mode 100644 index 00000000..d9e64e26 --- /dev/null +++ b/67_One_Check/csharp/Game.cs @@ -0,0 +1,45 @@ +namespace OneCheck; + +internal class Game +{ + private readonly IReadWrite _io; + + public Game(IReadWrite io) + { + _io = io; + } + + public void Play() + { + _io.Write(Streams.Introduction); + + do + { + var board = new Board(); + do + { + _io.WriteLine(board); + _io.WriteLine(); + } while (board.PlayMove(_io)); + + _io.WriteLine(board.GetReport()); + } while (_io.ReadYesNo(Prompts.TryAgain) == "yes"); + + _io.Write(Streams.Bye); + } +} + +internal static class IOExtensions +{ + internal static string ReadYesNo(this IReadWrite io, string prompt) + { + while (true) + { + var response = io.ReadString(prompt).ToLower(); + + if (response == "yes" || response == "no") { return response; } + + io.Write(Streams.YesOrNo); + } + } +} diff --git a/67_One_Check/csharp/Move.cs b/67_One_Check/csharp/Move.cs new file mode 100644 index 00000000..0b48659e --- /dev/null +++ b/67_One_Check/csharp/Move.cs @@ -0,0 +1,13 @@ +namespace OneCheck; + +internal class Move +{ + public int From { get; init; } + public int To { get; init; } + public int Jumped => (From + To) / 2; + + public bool IsInRange => From >= 0 && From <= 63 && To >= 0 && To <= 63; + public bool IsTwoSpacesDiagonally => RowDelta == 2 && ColumnDelta == 2; + private int RowDelta => Math.Abs(From / 8 - To / 8); + private int ColumnDelta => Math.Abs(From % 8 - To % 8); +} \ No newline at end of file diff --git a/67_One_Check/csharp/OneCheck.csproj b/67_One_Check/csharp/OneCheck.csproj index d3fe4757..3870320c 100644 --- a/67_One_Check/csharp/OneCheck.csproj +++ b/67_One_Check/csharp/OneCheck.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/67_One_Check/csharp/Program.cs b/67_One_Check/csharp/Program.cs new file mode 100644 index 00000000..4a3ab83b --- /dev/null +++ b/67_One_Check/csharp/Program.cs @@ -0,0 +1,5 @@ +global using Games.Common.IO; +global using static OneCheck.Resources.Resource; +using OneCheck; + +new Game(new ConsoleIO()).Play(); diff --git a/67_One_Check/csharp/Resources/Bye.txt b/67_One_Check/csharp/Resources/Bye.txt new file mode 100644 index 00000000..ee4ddab1 --- /dev/null +++ b/67_One_Check/csharp/Resources/Bye.txt @@ -0,0 +1,2 @@ + +O.K. Hope you had fun!! \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/From.txt b/67_One_Check/csharp/Resources/From.txt new file mode 100644 index 00000000..bb4c7a2d --- /dev/null +++ b/67_One_Check/csharp/Resources/From.txt @@ -0,0 +1 @@ +Jump from \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/IllegalMove.txt b/67_One_Check/csharp/Resources/IllegalMove.txt new file mode 100644 index 00000000..a96b6e81 --- /dev/null +++ b/67_One_Check/csharp/Resources/IllegalMove.txt @@ -0,0 +1 @@ +Illegal move. Try again... \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/Introduction.txt b/67_One_Check/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..409f6b37 --- /dev/null +++ b/67_One_Check/csharp/Resources/Introduction.txt @@ -0,0 +1,30 @@ + One Check + Creative Computing Morristown, New Jersey + + + +Solitaire checker puzzle by David Ahl + +48 checkers and placed on the 2 outside spaces of a +standard 64-square checkerboard. The object is to +remove as many checkers as possible by diagonal jumps +(as in standard checkers). Use the numbered board to +indicate the square you wish to jump from and to. On +the board printed out on each turn '1' indicates a +checker and '0' an empty square. When you have no +possible jumps remaining, input a '0' in response to +question 'Jump from ?' + +Here is the numerical board: + + 1 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 + 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 + 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 + 57 58 59 60 61 62 63 64 + +And here is the opening position of the checkers. + diff --git a/67_One_Check/csharp/Resources/Resource.cs b/67_One_Check/csharp/Resources/Resource.cs new file mode 100644 index 00000000..7095d7ec --- /dev/null +++ b/67_One_Check/csharp/Resources/Resource.cs @@ -0,0 +1,45 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace OneCheck.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream IllegalMove => GetStream(); + public static Stream YesOrNo => GetStream(); + public static Stream Bye => GetStream(); + } + + internal static class Formats + { + public static string Results => GetString(); + } + + internal static class Prompts + { + public static string From => GetString(); + public static string To => GetString(); + public static string TryAgain => GetString(); + } + + internal static class Strings + { + public static string TooManyColumns => GetString(); + public static string TooManyRows => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/Results.txt b/67_One_Check/csharp/Resources/Results.txt new file mode 100644 index 00000000..a8771b6b --- /dev/null +++ b/67_One_Check/csharp/Resources/Results.txt @@ -0,0 +1,3 @@ + +You made {0} jumps and had {1} pieces +remaining on the board. diff --git a/67_One_Check/csharp/Resources/To.txt b/67_One_Check/csharp/Resources/To.txt new file mode 100644 index 00000000..788636ff --- /dev/null +++ b/67_One_Check/csharp/Resources/To.txt @@ -0,0 +1 @@ +to \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/TryAgain.txt b/67_One_Check/csharp/Resources/TryAgain.txt new file mode 100644 index 00000000..c65e51fc --- /dev/null +++ b/67_One_Check/csharp/Resources/TryAgain.txt @@ -0,0 +1 @@ +Try again \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/YesOrNo.txt b/67_One_Check/csharp/Resources/YesOrNo.txt new file mode 100644 index 00000000..703d4ad6 --- /dev/null +++ b/67_One_Check/csharp/Resources/YesOrNo.txt @@ -0,0 +1 @@ +Please answer 'Yes' or 'No'. \ No newline at end of file