mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 07:40:50 -08:00
Add .Net usage README
This commit is contained in:
@@ -83,6 +83,9 @@ I propose to ignore this last behaviour - the interpreter crash - and instead tr
|
||||
of a quoted value. There are some additional behaviours to those shown above which can be seen in the unit tests for
|
||||
the C# implementation of the library.
|
||||
|
||||
Note also that BASIC numeric variables store a single-precision floating point value, so numeric input functions should
|
||||
return a value of that type.
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
The usage of the `INPUT` command in the BASIC code of the games was analysed, with the variables used designated as
|
||||
|
||||
181
00_Common/dotnet/README.md
Normal file
181
00_Common/dotnet/README.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# Games.Common
|
||||
|
||||
This is the common library for C# and VB.Net ports of the games.
|
||||
|
||||
## Overview
|
||||
|
||||
### Game Input/Output
|
||||
|
||||
* `TextIO` is the main class which manages text input and output for a game. It take a `TextReader` and a `TextWriter` in
|
||||
its constructor so it can be wired up in unit tests to test gameplay scenarios.
|
||||
* `ConsoleIO` derives from `TextIO` and binds it to `System.Console.In` and `System.Console.Out`.
|
||||
* `IReadWrite` is an interface implemented by `TextIO` which may be useful in some test scenarios.
|
||||
|
||||
```csharp
|
||||
public interface IReadWrite
|
||||
{
|
||||
// Reads a float value from input.
|
||||
float ReadNumber(string prompt);
|
||||
|
||||
// Reads 2 float values from input.
|
||||
(float, float) Read2Numbers(string prompt);
|
||||
|
||||
// Reads 3 float values from input.
|
||||
(float, float, float) Read3Numbers(string prompt);
|
||||
|
||||
// Reads 4 float values from input.
|
||||
(float, float, float, float) Read4Numbers(string prompt);
|
||||
|
||||
// Read numbers from input to fill an array.
|
||||
void ReadNumbers(string prompt, float[] values);
|
||||
|
||||
// Reads a string value from input.
|
||||
string ReadString(string prompt);
|
||||
|
||||
// Reads 2 string values from input.
|
||||
(string, string) Read2Strings(string prompt);
|
||||
|
||||
// Writes a string to output.
|
||||
void Write(string message);
|
||||
|
||||
// Writes a string to output, followed by a new-line.
|
||||
void WriteLine(string message = "");
|
||||
|
||||
// Writes a float to output, formatted per the BASIC interpreter, with leading and trailing spaces.
|
||||
void Write(float value);
|
||||
|
||||
// Writes a float to output, formatted per the BASIC interpreter, with leading and trailing spaces,
|
||||
// followed by a new-line.
|
||||
void WriteLine(float value);
|
||||
|
||||
// Writes the contents of a Stream to output.
|
||||
void Write(Stream stream);}
|
||||
```
|
||||
|
||||
### Random Number Generation
|
||||
|
||||
* `IRandom` is an interface that provides basic methods that parallel the 3 uses of BASIC's `RND(float)` function.
|
||||
* `RandomNumberGenerator` is an implementation of `IRandom` built around `System.Random`.
|
||||
* `IRandomExtensions` provides convenience extension methods for obtaining random numbers as `int` and also within a
|
||||
given range.
|
||||
|
||||
```csharp
|
||||
public interface IRandom
|
||||
{
|
||||
// Like RND(1), gets a random float such that 0 <= n < 1.
|
||||
float NextFloat();
|
||||
|
||||
// Like RND(0), Gets the float returned by the previous call to NextFloat.
|
||||
float PreviousFloat();
|
||||
|
||||
// Like RND(-x), Reseeds the random number generator.
|
||||
void Reseed(int seed);
|
||||
}
|
||||
```
|
||||
|
||||
Extension methods on `IRandom`:
|
||||
|
||||
```csharp
|
||||
// Gets a random float such that 0 <= n < exclusiveMaximum.
|
||||
float NextFloat(this IRandom random, float exclusiveMaximum);
|
||||
|
||||
// Gets a random float such that inclusiveMinimum <= n < exclusiveMaximum.
|
||||
float NextFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum);
|
||||
|
||||
// Gets a random int such that 0 <= n < exclusiveMaximum.
|
||||
int Next(this IRandom random, int exclusiveMaximum);
|
||||
|
||||
// Gets a random int such that inclusiveMinimum <= n < exclusiveMaximum.
|
||||
int Next(this IRandom random, int inclusiveMinimum, int exclusiveMaximum);
|
||||
|
||||
// Gets the previous unscaled float (between 0 and 1) scaled to a new range:
|
||||
// 0 <= x < exclusiveMaximum.
|
||||
float PreviousFloat(this IRandom random, float exclusiveMaximum);
|
||||
|
||||
// Gets the previous unscaled float (between 0 and 1) scaled to a new range:
|
||||
// inclusiveMinimum <= n < exclusiveMaximum.
|
||||
float PreviousFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum);
|
||||
|
||||
// Gets the previous unscaled float (between 0 and 1) scaled to an int in a new range:
|
||||
// 0 <= n < exclusiveMaximum.
|
||||
int Previous(this IRandom random, int exclusiveMaximum);
|
||||
|
||||
// Gets the previous unscaled float (between 0 and 1) scaled to an int in a new range:
|
||||
// inclusiveMinimum <= n < exclusiveMaximum.
|
||||
int Previous(this IRandom random, int inclusiveMinimum, int exclusiveMaximum);
|
||||
```
|
||||
|
||||
## C\# Usage
|
||||
|
||||
### Add Project Reference
|
||||
|
||||
Add the `Games.Common` project as a reference to the game project. For example, here's the reference from the C\# port
|
||||
of `86_Tower`:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\00_Common\dotnet\Games.Common\Games.Common.csproj" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
### C# Game Input/Output usage
|
||||
|
||||
A game can be encapsulated in a class which takes a `TextIO` instance in it's constructor:
|
||||
|
||||
```csharp
|
||||
public class Game
|
||||
{
|
||||
private readonly TextIO _io;
|
||||
|
||||
public Game(TextIO io) => _io = io;
|
||||
|
||||
public void Play()
|
||||
{
|
||||
var name = _io.ReadString("What is your name");
|
||||
var (cats, dogs) = _io.Read2Number($"Hello, {name}, how many pets do you have (cats, dogs)");
|
||||
_io.WriteLine($"So, {cats + dogs} pets in total, huh?");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then the entry point of the game program would look something like:
|
||||
|
||||
```csharp
|
||||
var game = new Game(new ConsoleIO());
|
||||
game.Play();
|
||||
```
|
||||
|
||||
### C# Random Number Generator usage
|
||||
|
||||
```csharp
|
||||
var io = new ConsoleIO();
|
||||
var rng = new RandomNumberGenerator();
|
||||
io.WriteLine(rng.NextFloat()); // 0.1234, for example
|
||||
io.WriteLine(rng.NextFloat()); // 0.6, for example
|
||||
io.WriteLine(rng.PreviousFloat()); // 0.6, repeats previous
|
||||
io.WriteLine(rng.PreviousFloat(0, 10)); // 6, repeats previous value, but scaled to new range
|
||||
```
|
||||
|
||||
### C# Unit Test usage
|
||||
|
||||
`TextIO` can be initialised with a `StringReader` and `StringWriter` to enable testing. For example, given the `Game`
|
||||
class above:
|
||||
|
||||
```csharp
|
||||
var reader = new StringReader("Joe Bloggs\r\n4\n\r5");
|
||||
var writer = new StringWriter();
|
||||
var game = new Game(new TextIO(reader, writer))
|
||||
|
||||
game.Play();
|
||||
|
||||
writer.ToString().Should().BeEquivalentTo(
|
||||
"What is your name? Hello, Joe Bloggs, how many pets do you have (cats, dogs)? ?? So, 9 pets in total, huh?");
|
||||
```
|
||||
|
||||
Note the lack of line breaks in the expected output, because during game play the line breaks come from the text input.
|
||||
|
||||
Of course, `IReadWrite` can also be mocked for simple test scenarios.
|
||||
|
||||
## VB.Net Usage
|
||||
|
||||
*To be provided*
|
||||
Reference in New Issue
Block a user