Merge pull request #48 from jamescurran/main

Added 05 Bagels for C#
This commit is contained in:
Jeff Atwood
2021-02-19 20:36:52 -08:00
committed by GitHub
7 changed files with 327 additions and 12 deletions

16
.gitignore vendored
View File

@@ -1,12 +1,4 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################
/01 Acey Ducey/csharp/obj
/47 Hi-Lo/csharp/obj
/.vs
/33 Dice/csharp/obj
/01 Acey Ducey/csharp/.vs/AceyDucey
/01 Acey Ducey/csharp/bin/Debug/netcoreapp3.1
/33 Dice/csharp/bin/Debug/net5.0
/basic-computer-games-dot-net/.vs/basic-computer-games-dot-net/v16
/**/obj/
/**/.vs/
/**/bin/
/**/*.user

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BasicComputerGames.Bagels
{
public enum BagelValidation
{
Valid,
WrongLength,
NotUnique,
NonDigit
};
public class BagelNumber
{
private static readonly Random Rnd = new Random();
private readonly int[] _digits;
public override string ToString()
{
return String.Join('-', _digits);
}
public static BagelNumber CreateSecretNumber(int numDigits)
{
if (numDigits < 3 || numDigits > 9)
throw new ArgumentOutOfRangeException(nameof(numDigits),
"Number of digits must be between 3 and 9, inclusive");
var digits = GetDigits(numDigits);
return new BagelNumber(digits);
}
public static BagelValidation IsValid(string number, int length)
{
if (number.Length != length)
return BagelValidation.WrongLength;
if (!number.All(Char.IsDigit))
return BagelValidation.NonDigit;
if (new HashSet<char>(number).Count != length)
return BagelValidation.NotUnique;
return BagelValidation.Valid;
}
public BagelNumber(string number)
{
if (number.Any(d => !Char.IsDigit(d)))
throw new ArgumentException("Number must be all unique digits", nameof(number));
_digits = number.Select(d => d - '0').ToArray();
}
//public BagelNumber(long number)
//{
// var digits = new List<int>();
// if (number >= 1E10)
// throw new ArgumentOutOfRangeException(nameof(number), "Number can be no more than 9 digits");
// while (number > 0)
// {
// long num = number / 10;
// int digit = (int)(number - (num * 10));
// number = num;
// digits.Add(digit);
// }
// _digits = digits.ToArray();
//}
public BagelNumber(int[] digits)
{
_digits = digits;
}
private static int[] GetDigits(int numDigits)
{
int[] digits = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Shuffle(digits);
return digits.Take(numDigits).ToArray();
}
private static void Shuffle(int[] digits)
{
for (int i = digits.Length - 1; i > 0; --i)
{
int pos = Rnd.Next(i);
var t = digits[i];
digits[i] = digits[pos];
digits[pos] = t;
}
}
public (int pico, int fermi) CompareTo(BagelNumber other)
{
int pico = 0;
int fermi = 0;
for (int i = 0; i < _digits.Length; i++)
{
for (int j = 0; j < other._digits.Length; j++)
{
if (_digits[i] == other._digits[j])
{
if (i == j)
++fermi;
else
++pico;
}
}
}
return (pico, fermi);
}
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>BasicComputerGames.Bagels</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Remove="TextUtil.cs" />
</ItemGroup>
</Project>

124
05 Bagels/csharp/Game.cs Normal file
View File

@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace BasicComputerGames.Bagels
{
public class Game : GameBase
{
public void GameLoop()
{
DisplayIntroText();
int points = 0;
do
{
var result =PlayRound();
if (result)
++points;
} while (TryAgain());
Console.WriteLine();
Console.WriteLine($"A {points} point Bagels buff!!");
Console.WriteLine("Hope you had fun. Bye.");
}
private const int Length = 3;
private const int MaxGuesses = 20;
private bool PlayRound()
{
var secret = BagelNumber.CreateSecretNumber(Length);
Console.WriteLine("O.K. I have a number in mind.");
for (int guessNo = 1; guessNo <= MaxGuesses; ++guessNo)
{
string strGuess;
BagelValidation isValid;
do
{
Console.WriteLine($"Guess #{guessNo}");
strGuess = Console.ReadLine();
isValid = BagelNumber.IsValid(strGuess, Length);
PrintError(isValid);
} while (isValid != BagelValidation.Valid);
var guess = new BagelNumber(strGuess);
var fermi = 0;
var pico = 0;
(pico, fermi) = secret.CompareTo(guess);
if(pico + fermi == 0)
Console.Write("BAGELS!");
else if (fermi == Length)
{
Console.WriteLine("You got it!");
return true;
}
else
{
PrintList("Pico ", pico);
PrintList("Fermi ", fermi);
}
Console.WriteLine();
}
Console.WriteLine("Oh, well.");
Console.WriteLine($"That's {MaxGuesses} guesses. My Number was {secret}");
return false;
}
private void PrintError(BagelValidation isValid)
{
switch (isValid)
{
case BagelValidation.NonDigit:
Console.WriteLine("What?");
break;
case BagelValidation.NotUnique:
Console.WriteLine("Oh, I forgot to tell you that the number I have in mind has no two digits the same.");
break;
case BagelValidation.WrongLength:
Console.WriteLine($"Try guessing a {Length}-digit number.");
break;
case BagelValidation.Valid:
break;
}
}
private void PrintList(string msg, int repeat)
{
for(int i=0; i<repeat; ++i)
Console.Write(msg);
}
private void DisplayIntroText()
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Bagels");
Console.WriteLine("Creating Computing, Morristown, New Jersey.");
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine(
"Original code author unknow but suspected to be from Lawrence Hall of Science, U.C. Berkley");
Console.WriteLine("Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.");
Console.WriteLine("Modernized and converted to C# in 2021 by James Curran (noveltheory.com).");
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("I am thinking of a three-digit number. Try to guess");
Console.WriteLine("my number and I will give you clues as follows:");
Console.WriteLine(" pico - One digit correct but in the wrong position");
Console.WriteLine(" fermi - One digit correct and in the right position");
Console.WriteLine(" bagels - No digits correct");
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Press any key start the game.");
Console.ReadKey(true);
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
namespace BasicComputerGames.Bagels
{
public class GameBase
{
protected Random Rnd { get; } = new Random();
/// <summary>
/// Prompt the player to try again, and wait for them to press Y or N.
/// </summary>
/// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>
protected bool TryAgain()
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Would you like to try again? (Press 'Y' for yes or 'N' for no)");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("> ");
char pressedKey;
// Keep looping until we get a recognised input
do
{
// Read a key, don't display it on screen
ConsoleKeyInfo key = Console.ReadKey(true);
// Convert to upper-case so we don't need to care about capitalisation
pressedKey = Char.ToUpper(key.KeyChar);
// Is this a key we recognise? If not, keep looping
} while (pressedKey != 'Y' && pressedKey != 'N');
// Display the result on the screen
Console.WriteLine(pressedKey);
// Return true if the player pressed 'Y', false for anything else.
return (pressedKey == 'Y');
}
}
}

View File

@@ -0,0 +1,14 @@
namespace BasicComputerGames.Bagels
{
public class Program
{
public static void Main(string[] args)
{
// Create an instance of our main Game class
var game = new Game();
// Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.
game.GameLoop();
}
}
}

View File

@@ -21,6 +21,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "csharp", "csharp", "{04298E
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hi-lo", "..\47 Hi-Lo\csharp\hi-lo.csproj", "{9B8FB4D6-EB62-47CC-A89D-96D330E96FF6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05 Bagels", "05 Bagels", "{946C0E7C-8A83-4C7F-9959-1AF0AEF4A027}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "csharp", "csharp", "{91DA95EE-DD42-4AEC-A886-07F834061BFC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bagels", "..\05 Bagels\csharp\Bagels.csproj", "{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +45,10 @@ Global
{9B8FB4D6-EB62-47CC-A89D-96D330E96FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B8FB4D6-EB62-47CC-A89D-96D330E96FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B8FB4D6-EB62-47CC-A89D-96D330E96FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -50,6 +60,8 @@ Global
{26D086DE-0BBD-4A18-AC63-2476A7DB52D3} = {AC302ACD-C3B2-460D-BA1A-0A511C36A848}
{04298EE8-0EF3-475C-9427-E04C267BBEFB} = {A2BC8E4A-B977-46A6-B897-7E675ACB96F0}
{9B8FB4D6-EB62-47CC-A89D-96D330E96FF6} = {04298EE8-0EF3-475C-9427-E04C267BBEFB}
{91DA95EE-DD42-4AEC-A886-07F834061BFC} = {946C0E7C-8A83-4C7F-9959-1AF0AEF4A027}
{DC32ED10-ACEA-4B09-8B2A-54E1F7277C0A} = {91DA95EE-DD42-4AEC-A886-07F834061BFC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {703D538E-7F20-4DD0-A3DD-7BBE36AC82AF}