mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Complete game
This commit is contained in:
@@ -1,36 +1,80 @@
|
||||
namespace Digits
|
||||
namespace Digits;
|
||||
|
||||
internal class GameSeries
|
||||
{
|
||||
internal class Game
|
||||
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)
|
||||
{
|
||||
private readonly IReadWrite _io;
|
||||
private readonly IRandom _random;
|
||||
_io = io;
|
||||
_random = random;
|
||||
}
|
||||
|
||||
public Game(IReadWrite io, IRandom random)
|
||||
internal void Play()
|
||||
{
|
||||
_io.Write(Streams.Introduction);
|
||||
|
||||
if (_io.ReadNumber(Prompts.ForInstructions) != 0)
|
||||
{
|
||||
_io = io;
|
||||
_random = random;
|
||||
_io.Write(Streams.Instructions);
|
||||
}
|
||||
|
||||
internal void Play()
|
||||
do
|
||||
{
|
||||
_io.Write(Streams.Introduction);
|
||||
new Game(_io, _random).Play();
|
||||
} while (_io.ReadNumber(Prompts.WantToTryAgain) == 1);
|
||||
|
||||
if (_io.ReadNumber(Prompts.ForInstructions) != 0)
|
||||
{
|
||||
_io.Write(Streams.Instructions);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
PlayOne();
|
||||
} while (_io.ReadNumber(Prompts.WantToTryAgain) == 1);
|
||||
|
||||
_io.Write(Streams.Thanks);
|
||||
}
|
||||
|
||||
private void PlayOne()
|
||||
{
|
||||
|
||||
}
|
||||
_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;
|
||||
}
|
||||
}
|
||||
52
34_Digits/csharp/Guesser.cs
Normal file
52
34_Digits/csharp/Guesser.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
namespace Digits;
|
||||
|
||||
internal class Guesser
|
||||
{
|
||||
private readonly IReadOnlyList<int> _weights = new List<int> { 0, 1, 3 }.AsReadOnly();
|
||||
private readonly int[][,] _matrices = new[] { new int[3, 3], new int[9, 3], new int[27, 3] };
|
||||
private readonly int[] _indices = new[] { 2, 8, 26 };
|
||||
private readonly IRandom _random;
|
||||
|
||||
public Guesser(IRandom random)
|
||||
{
|
||||
_random = random;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
for (int i = 0; i < 3; i++) { _matrices[0][i, j] = 9; }
|
||||
for (int i = 0; i < 9; i++) { _matrices[1][i, j] = i == 4 * j ? 2 : 3; }
|
||||
for (int i = 0; i < 27; i++) { _matrices[2][i, j] = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
public int GuessNextDigit()
|
||||
{
|
||||
var currentSum = 0;
|
||||
var guess = 0;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
var sum = Enumerable.Range(0, 3).Aggregate((s, i) => s + GetWeightedValue(i, j));
|
||||
if (sum > currentSum || _random.NextFloat() >= 0.5)
|
||||
{
|
||||
currentSum = sum;
|
||||
guess = j;
|
||||
}
|
||||
}
|
||||
|
||||
return guess;
|
||||
}
|
||||
|
||||
public void ObserveActualDigit(int digit)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
_matrices[i][_indices[i], digit]++;
|
||||
}
|
||||
_indices[2] = _indices[2] % 9 * 3 + digit;
|
||||
_indices[1] = _indices[2] % 9;
|
||||
_indices[0] = digit;
|
||||
}
|
||||
|
||||
private int GetWeightedValue(int matrix, int row) => _weights[matrix] * _matrices[matrix][_indices[matrix], row];
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@ global using Games.Common.IO;
|
||||
global using Games.Common.Randomness;
|
||||
global using static Digits.Resources.Resource;
|
||||
|
||||
new Game(new ConsoleIO(), new RandomNumberGenerator()).Play();
|
||||
new GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play();
|
||||
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}
|
||||
@@ -1 +1,3 @@
|
||||
|
||||
My guess Your no. Result No. right
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ internal static class Resource
|
||||
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);
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
Ten numbers, please
|
||||
Reference in New Issue
Block a user