# 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_Target`: ```xml ``` ### 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*