diff --git a/08 Batnum/csharp/Batnum.csproj b/08 Batnum/csharp/Batnum.csproj new file mode 100644 index 00000000..8a87960b --- /dev/null +++ b/08 Batnum/csharp/Batnum.csproj @@ -0,0 +1,24 @@ + + + + Exe + net5.0 + en-US + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/08 Batnum/csharp/Batnum.sln b/08 Batnum/csharp/Batnum.sln new file mode 100644 index 00000000..1e80320b --- /dev/null +++ b/08 Batnum/csharp/Batnum.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31019.35 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Batnum", "Batnum.csproj", "{64F32165-9D67-42B1-B04C-953CC756A170}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {64F32165-9D67-42B1-B04C-953CC756A170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64F32165-9D67-42B1-B04C-953CC756A170}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64F32165-9D67-42B1-B04C-953CC756A170}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64F32165-9D67-42B1-B04C-953CC756A170}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {73E40CC2-0E4E-48CF-8BDD-D6B6E995C14F} + EndGlobalSection +EndGlobal diff --git a/08 Batnum/csharp/BatnumGame.cs b/08 Batnum/csharp/BatnumGame.cs new file mode 100644 index 00000000..1c702840 --- /dev/null +++ b/08 Batnum/csharp/BatnumGame.cs @@ -0,0 +1,114 @@ +using Batnum.Properties; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Batnum +{ + public enum WinOptions + { + /// + /// Last person to play wins + /// + WinWithTakeLast = 1, + /// + /// Last person to play loses + /// + WinWithAvoidLast = 2 + } + + public enum Players + { + Computer = 1, + Human = 2 + } + + public class BatnumGame + { + public BatnumGame(int pileSize, WinOptions winCriteria, int minTake, int maxtake, Players firstPlayer, FuncaskPlayerCallback) + { + this.pileSize = pileSize; + this.winCriteria = winCriteria; + this.minTake = minTake; + this.maxTake = maxtake; + this.currentPlayer = firstPlayer; + this.askPlayerCallback = askPlayerCallback; + } + + private int pileSize; + private WinOptions winCriteria; + private int minTake; + private int maxTake; + private Players currentPlayer; + private Func askPlayerCallback; + + /// + /// Returns true if the game is running + /// + public bool IsRunning => pileSize > 0; + + /// + /// Takes the next turn + /// + /// A message to be displayed to the player + public string TakeTurn() + { + //Edge condition - can occur when minTake is more > 1 + if (pileSize < minTake) + { + pileSize = 0; + return string.Format(Resources.END_DRAW, minTake); + } + return currentPlayer == Players.Computer ? ComputerTurn() : PlayerTurn(); + } + + private string PlayerTurn() + { + int draw = askPlayerCallback(Resources.INPUT_TURN); + if (draw == 0) + { + pileSize = 0; + return Resources.INPUT_ZERO; + } + if (draw < minTake || draw > maxTake || draw > pileSize) + { + return Resources.INPUT_ILLEGAL; + } + pileSize = pileSize - draw; + if (pileSize == 0) + { + return winCriteria == WinOptions.WinWithTakeLast ? Resources.END_PLAYERWIN : Resources.END_PLAYERLOSE; + } + currentPlayer = Players.Computer; + return ""; + } + + private string ComputerTurn() + { + //first calculate the move to play + int sumTake = minTake + maxTake; + int draw = pileSize - sumTake * (int)(pileSize / (float)sumTake); + draw = Math.Clamp(draw, minTake, maxTake); + + //detect win/lose conditions + switch (winCriteria) + { + case WinOptions.WinWithAvoidLast when (pileSize == minTake): //lose condition + pileSize = 0; + return string.Format(Resources.END_COMPLOSE, minTake); + case WinOptions.WinWithAvoidLast when (pileSize <= maxTake): //avoid automatic loss on next turn + draw = Math.Clamp(draw, minTake, pileSize - 1); + break; + case WinOptions.WinWithTakeLast when pileSize <= maxTake: // win condition + draw = Math.Min(pileSize, maxTake); + pileSize = 0; + return string.Format(Resources.END_COMPWIN, draw); + } + pileSize -= draw; + currentPlayer = Players.Human; + return string.Format(Resources.COMPTURN, draw, pileSize); + } + } +} diff --git a/08 Batnum/csharp/ConsoleUtilities.cs b/08 Batnum/csharp/ConsoleUtilities.cs new file mode 100644 index 00000000..2dd5f09b --- /dev/null +++ b/08 Batnum/csharp/ConsoleUtilities.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Batnum +{ + public static class ConsoleUtilities + { + /// + /// Ask the user a question and expects a comma separated pair of numbers representing a number range in response + /// the range provided must have a maximum which is greater than the minimum + /// + /// The question to ask + /// The minimum value expected + /// The maximum value expected + /// A pair of numbers representing the minimum and maximum of the range + public static (int min, int max) AskNumberRangeQuestion(string question, Func Validate) + { + while (true) + { + Console.Write(question); + Console.Write(" "); + string[] rawInput = Console.ReadLine().Split(','); + if (rawInput.Length == 2) + { + if (int.TryParse(rawInput[0], out int min) && int.TryParse(rawInput[1], out int max)) + { + if (Validate(min, max)) + { + return (min, max); + } + } + } + Console.WriteLine(); + } + } + + /// + /// Ask the user a question and expects a number in response + /// + /// The question to ask + /// A minimum value expected + /// A maximum value expected + /// The number the user entered + public static int AskNumberQuestion(string question, Func Validate) + { + while (true) + { + Console.Write(question); + Console.Write(" "); + string rawInput = Console.ReadLine(); + if (int.TryParse(rawInput, out int number)) + { + if (Validate(number)) + { + return number; + } + } + Console.WriteLine(); + } + } + + /// + /// Align content to center of console. + /// + /// Content to center + /// Center aligned text + public static string CenterText(string content) + { + int windowWidth = Console.WindowWidth; + return String.Format("{0," + ((windowWidth / 2) + (content.Length / 2)) + "}", content); + } + + /// + /// Writes the specified data, followed by the current line terminator, to the standard output stream, while wrapping lines that would otherwise break words. + /// source: https://stackoverflow.com/questions/20534318/make-console-writeline-wrap-words-instead-of-letters + /// + /// The value to write. + /// The value that indicates the column width of tab characters. + public static void WriteLineWordWrap(string paragraph, int tabSize = 4) + { + string[] lines = paragraph + .Replace("\t", new String(' ', tabSize)) + .Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + + for (int i = 0; i < lines.Length; i++) + { + string process = lines[i]; + List wrapped = new List(); + + while (process.Length > Console.WindowWidth) + { + int wrapAt = process.LastIndexOf(' ', Math.Min(Console.WindowWidth - 1, process.Length)); + if (wrapAt <= 0) break; + + wrapped.Add(process.Substring(0, wrapAt)); + process = process.Remove(0, wrapAt + 1); + } + + foreach (string wrap in wrapped) + { + Console.WriteLine(wrap); + } + + Console.WriteLine(process); + } + } + } +} diff --git a/08 Batnum/csharp/Program.cs b/08 Batnum/csharp/Program.cs new file mode 100644 index 00000000..08e6b304 --- /dev/null +++ b/08 Batnum/csharp/Program.cs @@ -0,0 +1,30 @@ +using Batnum; +using Batnum.Properties; +using System; + +Console.WriteLine(ConsoleUtilities.CenterText(Resources.GAME_NAME)); +Console.WriteLine(ConsoleUtilities.CenterText(Resources.INTRO_HEADER)); +Console.WriteLine(); +Console.WriteLine(); +Console.WriteLine(); +ConsoleUtilities.WriteLineWordWrap(Resources.INTRO_PART1); +Console.WriteLine(); +ConsoleUtilities.WriteLineWordWrap(Resources.INTRO_PART2); + +while (true) +{ + Console.WriteLine(); + int pileSize = ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_PILESIZE, (n) => n > 1); + WinOptions winOption = (WinOptions)ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_WINOPTION, (n) => Enum.IsDefined(typeof(WinOptions), n)); + (int minTake, int maxTake) = ConsoleUtilities.AskNumberRangeQuestion(Resources.START_QUESTION_DRAWMINMAX, (min,max) => min >= 1 && max < pileSize && max > min); + Players currentPlayer = (Players)ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_WHOSTARTS, (n) => Enum.IsDefined(typeof(Players), n)); + + BatnumGame game = new BatnumGame(pileSize, winOption, minTake, maxTake, currentPlayer, (question) => ConsoleUtilities.AskNumberQuestion(question, (c) => true)); + while(game.IsRunning) + { + string message = game.TakeTurn(); + Console.WriteLine(message); + } + +} + diff --git a/08 Batnum/csharp/Properties/Resources.Designer.cs b/08 Batnum/csharp/Properties/Resources.Designer.cs new file mode 100644 index 00000000..b0cc5dd9 --- /dev/null +++ b/08 Batnum/csharp/Properties/Resources.Designer.cs @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Batnum.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Batnum.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to COMPUTER TAKES {0} AND LEAVES {1}. + /// + internal static string COMPTURN { + get { + return ResourceManager.GetString("COMPTURN", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to COMPUTER TAKES {0} AND LOSES. + /// + internal static string END_COMPLOSE { + get { + return ResourceManager.GetString("END_COMPLOSE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to COMPUTER TAKES {0} AND WINS. + /// + internal static string END_COMPWIN { + get { + return ResourceManager.GetString("END_COMPWIN", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT. + /// + internal static string END_DRAW { + get { + return ResourceManager.GetString("END_DRAW", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TOUGH LUCK, YOU LOSE.. + /// + internal static string END_PLAYERLOSE { + get { + return ResourceManager.GetString("END_PLAYERLOSE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CONGRATULATIONS, YOU WIN.. + /// + internal static string END_PLAYERWIN { + get { + return ResourceManager.GetString("END_PLAYERWIN", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BATNUM. + /// + internal static string GAME_NAME { + get { + return ResourceManager.GetString("GAME_NAME", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ILLEGAL MOVE, RENETER IT. + /// + internal static string INPUT_ILLEGAL { + get { + return ResourceManager.GetString("INPUT_ILLEGAL", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to YOUR MOVE ?. + /// + internal static string INPUT_TURN { + get { + return ResourceManager.GetString("INPUT_TURN", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.. + /// + internal static string INPUT_ZERO { + get { + return ResourceManager.GetString("INPUT_ZERO", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CREATIVE COMPUTING MORRISTOWN, NEW JERSEY. + /// + internal static string INTRO_HEADER { + get { + return ResourceManager.GetString("INTRO_HEADER", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to THIS PROGRAM IS A 'BATTLE' OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT. + /// + internal static string INTRO_PART1 { + get { + return ResourceManager.GetString("INTRO_PART1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON'T USER ZERO, HOWWEVER, IN PLAYING THE GAME.. + /// + internal static string INTRO_PART2 { + get { + return ResourceManager.GetString("INTRO_PART2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ENTER MIN AND MAX ?. + /// + internal static string START_QUESTION_DRAWMINMAX { + get { + return ResourceManager.GetString("START_QUESTION_DRAWMINMAX", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ENTER PILE SIZE ?. + /// + internal static string START_QUESTION_PILESIZE { + get { + return ResourceManager.GetString("START_QUESTION_PILESIZE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ?. + /// + internal static string START_QUESTION_WHOSTARTS { + get { + return ResourceManager.GetString("START_QUESTION_WHOSTARTS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ?. + /// + internal static string START_QUESTION_WINOPTION { + get { + return ResourceManager.GetString("START_QUESTION_WINOPTION", resourceCulture); + } + } + } +} diff --git a/08 Batnum/csharp/Properties/Resources.en.resx b/08 Batnum/csharp/Properties/Resources.en.resx new file mode 100644 index 00000000..746d8a12 --- /dev/null +++ b/08 Batnum/csharp/Properties/Resources.en.resx @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + COMPUTER TAKES {0} AND LEAVES {1} + + + COMPUTER TAKES {0} AND LOSES + + + COMPUTER TAKES {0} AND WINS + + + ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT + + + TOUGH LUCK, YOU LOSE. + + + CONGRATULATIONS, YOU WIN. + + + BATNUM + + + ILLEGAL MOVE, RENETER IT + + + YOUR MOVE ? + + + I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT. + + + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + THIS PROGRAM IS A 'BATTLE' OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT + + + THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON'T USER ZERO, HOWWEVER, IN PLAYING THE GAME. + + + ENTER MIN AND MAX ? + + + ENTER PILE SIZE ? + + + ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ? + + + ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ? + + \ No newline at end of file diff --git a/08 Batnum/csharp/Properties/Resources.fr.resx b/08 Batnum/csharp/Properties/Resources.fr.resx new file mode 100644 index 00000000..410562e2 --- /dev/null +++ b/08 Batnum/csharp/Properties/Resources.fr.resx @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + L'ORDINATEUR PREND {0} ET LAISSE {1} + + + L'ORDINATEUR PREND {0} ET PERD + + + L'ORDINATEUR PREND {0} ET GAGNE + + + MATCH NUL, IL RESTE SEULEMENT {0} PIECES + + + PAS DE CHANCE. TU AS PERDU. + + + BRAVO! TU AS GAGNE + + + BATNUM + + + CE COUP EST INTERDIT. RE-ESSAIE + + + TON TOUR ? + + + JE TE DIS DE NE PAS UTILISER LE ZERO! L'ORDINATEUR GAGNE PAR DEFAUT. + + + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + CE PROGRAMME EST UN JEU 'BATAILLE' DE NOMBRES, OU L'ORDINATEUR EST TON ADVERSAIRE + + + LE JEU COMMENCE AVEC UNE NOMBRE D'OBJETS DEFINI. TOI ET TON ADVERSAIRE ENLEVEZ EN ALTERNANCE UN NOMBRE D'OBJETS. LES CONDITIONS DE VICTOIRE SON DÉFINIES À L'AVANCE COMME PRENDRE OU NE PAS PRENDRE LE DERNIER OBJET. VOUS POUVEZ ÉGALEMENT PRÉCISER D'AUTRES CONDITIONS DES LE DÉBUT. TOUTEFOIS, N'UTILISEZ PAS LE CHIFFRE ZERO. + + + ENTRE LE MINIMUM ET MAXIMUM D'OBJETS A RETIRER POUR CHAQUE TOUR ? + + + ENTRE LE NOMBRE D'OBJETS ? + + + ENTRE QUI COMMENCE - 1 L'ORDINATEUR, 2 TOI ? + + + ENTRE LA CONDITION DE VICTOIRE - 1 PRENDRE LA DERNIERE PIECE, 2 EVITER LA DERNIERE PIECE ? + + \ No newline at end of file diff --git a/08 Batnum/csharp/Properties/Resources.resx b/08 Batnum/csharp/Properties/Resources.resx new file mode 100644 index 00000000..746d8a12 --- /dev/null +++ b/08 Batnum/csharp/Properties/Resources.resx @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + COMPUTER TAKES {0} AND LEAVES {1} + + + COMPUTER TAKES {0} AND LOSES + + + COMPUTER TAKES {0} AND WINS + + + ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT + + + TOUGH LUCK, YOU LOSE. + + + CONGRATULATIONS, YOU WIN. + + + BATNUM + + + ILLEGAL MOVE, RENETER IT + + + YOUR MOVE ? + + + I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT. + + + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + THIS PROGRAM IS A 'BATTLE' OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT + + + THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON'T USER ZERO, HOWWEVER, IN PLAYING THE GAME. + + + ENTER MIN AND MAX ? + + + ENTER PILE SIZE ? + + + ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ? + + + ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ? + + \ No newline at end of file diff --git a/08 Batnum/csharp/README.md b/08 Batnum/csharp/README.md index 4daabb5c..cd054abd 100644 --- a/08 Batnum/csharp/README.md +++ b/08 Batnum/csharp/README.md @@ -1,3 +1,11 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) + +This conversion uses C#9 and is built for .net 5.0 + +Functional changes from Original +- handle edge condition for end game where the minimum draw amount is greater than the number of items remaining in the pile +- Takes into account the width of the console +- Mulilingual Support (English/French currently) +