mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-06 18:14:27 -08:00
@@ -6,4 +6,12 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources/*.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\00_Common\dotnet\Games.Common\Games.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
80
34_Digits/csharp/Game.cs
Normal file
80
34_Digits/csharp/Game.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace Digits;
|
||||
|
||||
internal class GameSeries
|
||||
{
|
||||
private readonly IReadOnlyList<int> _weights = new List<int> { 0, 1, 3 }.AsReadOnly();
|
||||
|
||||
private readonly IReadWrite _io;
|
||||
private readonly IRandom _random;
|
||||
|
||||
public GameSeries(IReadWrite io, IRandom random)
|
||||
{
|
||||
_io = io;
|
||||
_random = random;
|
||||
}
|
||||
|
||||
internal void Play()
|
||||
{
|
||||
_io.Write(Streams.Introduction);
|
||||
|
||||
if (_io.ReadNumber(Prompts.ForInstructions) != 0)
|
||||
{
|
||||
_io.Write(Streams.Instructions);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
new Game(_io, _random).Play();
|
||||
} while (_io.ReadNumber(Prompts.WantToTryAgain) == 1);
|
||||
|
||||
_io.Write(Streams.Thanks);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Game
|
||||
{
|
||||
private readonly IReadWrite _io;
|
||||
private readonly Guesser _guesser;
|
||||
|
||||
public Game(IReadWrite io, IRandom random)
|
||||
{
|
||||
_io = io;
|
||||
_guesser = new Guesser(random);
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
var correctGuesses = 0;
|
||||
|
||||
for (int round = 0; round < 3; round++)
|
||||
{
|
||||
var digits = _io.Read10Digits(Prompts.TenNumbers, Streams.TryAgain);
|
||||
|
||||
correctGuesses = GuessDigits(digits, correctGuesses);
|
||||
}
|
||||
|
||||
_io.Write(correctGuesses switch
|
||||
{
|
||||
< 10 => Streams.YouWin,
|
||||
10 => Streams.ItsATie,
|
||||
> 10 => Streams.IWin
|
||||
});
|
||||
}
|
||||
|
||||
private int GuessDigits(IEnumerable<int> digits, int correctGuesses)
|
||||
{
|
||||
_io.Write(Streams.Headings);
|
||||
|
||||
foreach (var digit in digits)
|
||||
{
|
||||
var guess = _guesser.GuessNextDigit();
|
||||
if (guess == digit) { correctGuesses++; }
|
||||
|
||||
_io.WriteLine(Formats.GuessResult, guess, digit, guess == digit ? "Right" : "Wrong", correctGuesses);
|
||||
|
||||
_guesser.ObserveActualDigit(digit);
|
||||
}
|
||||
|
||||
return correctGuesses;
|
||||
}
|
||||
}
|
||||
32
34_Digits/csharp/Guesser.cs
Normal file
32
34_Digits/csharp/Guesser.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace Digits;
|
||||
|
||||
internal class Guesser
|
||||
{
|
||||
private readonly Memory _matrices = new();
|
||||
private readonly IRandom _random;
|
||||
|
||||
public Guesser(IRandom random)
|
||||
{
|
||||
_random = random;
|
||||
}
|
||||
|
||||
public int GuessNextDigit()
|
||||
{
|
||||
var currentSum = 0;
|
||||
var guess = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var sum = _matrices.GetWeightedSum(i);
|
||||
if (sum > currentSum || _random.NextFloat() >= 0.5)
|
||||
{
|
||||
currentSum = sum;
|
||||
guess = i;
|
||||
}
|
||||
}
|
||||
|
||||
return guess;
|
||||
}
|
||||
|
||||
public void ObserveActualDigit(int digit) => _matrices.ObserveDigit(digit);
|
||||
}
|
||||
20
34_Digits/csharp/IOExtensions.cs
Normal file
20
34_Digits/csharp/IOExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Digits;
|
||||
|
||||
internal static class IOExtensions
|
||||
{
|
||||
internal static IEnumerable<int> Read10Digits(this IReadWrite io, string prompt, Stream retryText)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var numbers = new float[10];
|
||||
io.ReadNumbers(prompt, numbers);
|
||||
|
||||
if (numbers.All(n => n == 0 || n == 1 || n == 2))
|
||||
{
|
||||
return numbers.Select(n => (int)n);
|
||||
}
|
||||
|
||||
io.Write(retryText);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
34_Digits/csharp/Matrix.cs
Normal file
27
34_Digits/csharp/Matrix.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Digits;
|
||||
|
||||
internal class Matrix
|
||||
{
|
||||
private readonly int _weight;
|
||||
private readonly int[,] _values;
|
||||
|
||||
public Matrix(int width, int weight, Func<int, int, int> seedFactory)
|
||||
{
|
||||
_weight = weight;
|
||||
_values = new int[width, 3];
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
_values[i, j] = seedFactory.Invoke(i, j);
|
||||
}
|
||||
|
||||
Index = width - 1;
|
||||
}
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public int GetWeightedValue(int row) => _weight * _values[Index, row];
|
||||
|
||||
public int IncrementValue(int row) => _values[Index, row]++;
|
||||
}
|
||||
30
34_Digits/csharp/Memory.cs
Normal file
30
34_Digits/csharp/Memory.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Digits;
|
||||
|
||||
public class Memory
|
||||
{
|
||||
private readonly Matrix[] _matrices;
|
||||
|
||||
public Memory()
|
||||
{
|
||||
_matrices = new[]
|
||||
{
|
||||
new Matrix(27, 3, (_, _) => 1),
|
||||
new Matrix(9, 1, (i, j) => i == 4 * j ? 2 : 3),
|
||||
new Matrix(3, 0, (_, _) => 9)
|
||||
};
|
||||
}
|
||||
|
||||
public int GetWeightedSum(int row) => _matrices.Select(m => m.GetWeightedValue(row)).Sum();
|
||||
|
||||
public void ObserveDigit(int digit)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
_matrices[i].IncrementValue(digit);
|
||||
}
|
||||
|
||||
_matrices[0].Index = _matrices[0].Index % 9 * 3 + digit;
|
||||
_matrices[1].Index = _matrices[0].Index % 9;
|
||||
_matrices[2].Index = digit;
|
||||
}
|
||||
}
|
||||
6
34_Digits/csharp/Program.cs
Normal file
6
34_Digits/csharp/Program.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
global using Digits;
|
||||
global using Games.Common.IO;
|
||||
global using Games.Common.Randomness;
|
||||
global using static Digits.Resources.Resource;
|
||||
|
||||
new GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play();
|
||||
1
34_Digits/csharp/Resources/ForInstructions.txt
Normal file
1
34_Digits/csharp/Resources/ForInstructions.txt
Normal file
@@ -0,0 +1 @@
|
||||
For instructions, type '1', else type '0'
|
||||
1
34_Digits/csharp/Resources/GuessResult.txt
Normal file
1
34_Digits/csharp/Resources/GuessResult.txt
Normal file
@@ -0,0 +1 @@
|
||||
{0} {1} {2} {3}
|
||||
3
34_Digits/csharp/Resources/Headings.txt
Normal file
3
34_Digits/csharp/Resources/Headings.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
My guess Your no. Result No. right
|
||||
|
||||
4
34_Digits/csharp/Resources/IWin.txt
Normal file
4
34_Digits/csharp/Resources/IWin.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
I guessed more than 1/3 of your numbers.
|
||||
I win.
|
||||
|
||||
11
34_Digits/csharp/Resources/Instructions.txt
Normal file
11
34_Digits/csharp/Resources/Instructions.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
Please take a piece of paper and write down
|
||||
the digits '0', '1', or '2' thirty times at random.
|
||||
Arrange them in three lines of ten digits each.
|
||||
I will ask for then ten at a time.
|
||||
I will always guess them first and then look at your
|
||||
next number to see if I was right. By pure luck,
|
||||
I ought to be right ten times. But I hope to do better
|
||||
than that *****
|
||||
|
||||
|
||||
6
34_Digits/csharp/Resources/Introduction.txt
Normal file
6
34_Digits/csharp/Resources/Introduction.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Digits
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
This is a game of guessing.
|
||||
4
34_Digits/csharp/Resources/ItsATie.txt
Normal file
4
34_Digits/csharp/Resources/ItsATie.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
I guessed exactly 1/3 of your numbers.
|
||||
It's a tie game.
|
||||
|
||||
43
34_Digits/csharp/Resources/Resource.cs
Normal file
43
34_Digits/csharp/Resources/Resource.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Digits.Resources;
|
||||
|
||||
internal static class Resource
|
||||
{
|
||||
internal static class Streams
|
||||
{
|
||||
public static Stream Introduction => GetStream();
|
||||
public static Stream Instructions => GetStream();
|
||||
public static Stream TryAgain => GetStream();
|
||||
public static Stream ItsATie => GetStream();
|
||||
public static Stream IWin => GetStream();
|
||||
public static Stream YouWin => GetStream();
|
||||
public static Stream Thanks => GetStream();
|
||||
public static Stream Headings => GetStream();
|
||||
}
|
||||
|
||||
internal static class Prompts
|
||||
{
|
||||
public static string ForInstructions => GetString();
|
||||
public static string TenNumbers => GetString();
|
||||
public static string WantToTryAgain => GetString();
|
||||
}
|
||||
|
||||
internal static class Formats
|
||||
{
|
||||
public static string GuessResult => 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}'.");
|
||||
}
|
||||
2
34_Digits/csharp/Resources/TenNumbers.txt
Normal file
2
34_Digits/csharp/Resources/TenNumbers.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Ten numbers, please
|
||||
2
34_Digits/csharp/Resources/Thanks.txt
Normal file
2
34_Digits/csharp/Resources/Thanks.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Thanks for the game
|
||||
2
34_Digits/csharp/Resources/TryAgain.txt
Normal file
2
34_Digits/csharp/Resources/TryAgain.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Only use the digits '0', '1', or '2'.
|
||||
Let's try again.
|
||||
1
34_Digits/csharp/Resources/WantToTryAgain.txt
Normal file
1
34_Digits/csharp/Resources/WantToTryAgain.txt
Normal file
@@ -0,0 +1 @@
|
||||
Do you want to try again (1 for yes, 0 for no)
|
||||
4
34_Digits/csharp/Resources/YouWin.txt
Normal file
4
34_Digits/csharp/Resources/YouWin.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
I guessed less than 1/3 of your numbers.
|
||||
You beat me. Congratulations *****
|
||||
|
||||
Reference in New Issue
Block a user