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]++;
+}
\ No newline at end of file
diff --git a/34_Digits/csharp/Memory.cs b/34_Digits/csharp/Memory.cs
new file mode 100644
index 00000000..a3023351
--- /dev/null
+++ b/34_Digits/csharp/Memory.cs
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/34_Digits/csharp/Program.cs b/34_Digits/csharp/Program.cs
new file mode 100644
index 00000000..1b5dd2e0
--- /dev/null
+++ b/34_Digits/csharp/Program.cs
@@ -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();
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/ForInstructions.txt b/34_Digits/csharp/Resources/ForInstructions.txt
new file mode 100644
index 00000000..1c16d5f4
--- /dev/null
+++ b/34_Digits/csharp/Resources/ForInstructions.txt
@@ -0,0 +1 @@
+For instructions, type '1', else type '0'
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/GuessResult.txt b/34_Digits/csharp/Resources/GuessResult.txt
new file mode 100644
index 00000000..4e233e03
--- /dev/null
+++ b/34_Digits/csharp/Resources/GuessResult.txt
@@ -0,0 +1 @@
+ {0} {1} {2} {3}
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/Headings.txt b/34_Digits/csharp/Resources/Headings.txt
new file mode 100644
index 00000000..8289cdf6
--- /dev/null
+++ b/34_Digits/csharp/Resources/Headings.txt
@@ -0,0 +1,3 @@
+
+My guess Your no. Result No. right
+
diff --git a/34_Digits/csharp/Resources/IWin.txt b/34_Digits/csharp/Resources/IWin.txt
new file mode 100644
index 00000000..491f69cf
--- /dev/null
+++ b/34_Digits/csharp/Resources/IWin.txt
@@ -0,0 +1,4 @@
+
+I guessed more than 1/3 of your numbers.
+I win.
+
diff --git a/34_Digits/csharp/Resources/Instructions.txt b/34_Digits/csharp/Resources/Instructions.txt
new file mode 100644
index 00000000..f9ff2a16
--- /dev/null
+++ b/34_Digits/csharp/Resources/Instructions.txt
@@ -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 *****
+
+
diff --git a/34_Digits/csharp/Resources/Introduction.txt b/34_Digits/csharp/Resources/Introduction.txt
new file mode 100644
index 00000000..e4d2d93e
--- /dev/null
+++ b/34_Digits/csharp/Resources/Introduction.txt
@@ -0,0 +1,6 @@
+ Digits
+ Creative Computing Morristown, New Jersey
+
+
+
+This is a game of guessing.
diff --git a/34_Digits/csharp/Resources/ItsATie.txt b/34_Digits/csharp/Resources/ItsATie.txt
new file mode 100644
index 00000000..0e92fbf6
--- /dev/null
+++ b/34_Digits/csharp/Resources/ItsATie.txt
@@ -0,0 +1,4 @@
+
+I guessed exactly 1/3 of your numbers.
+It's a tie game.
+
diff --git a/34_Digits/csharp/Resources/Resource.cs b/34_Digits/csharp/Resources/Resource.cs
new file mode 100644
index 00000000..2e935955
--- /dev/null
+++ b/34_Digits/csharp/Resources/Resource.cs
@@ -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}'.");
+}
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/TenNumbers.txt b/34_Digits/csharp/Resources/TenNumbers.txt
new file mode 100644
index 00000000..ad03893a
--- /dev/null
+++ b/34_Digits/csharp/Resources/TenNumbers.txt
@@ -0,0 +1,2 @@
+
+Ten numbers, please
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/Thanks.txt b/34_Digits/csharp/Resources/Thanks.txt
new file mode 100644
index 00000000..15d42e1b
--- /dev/null
+++ b/34_Digits/csharp/Resources/Thanks.txt
@@ -0,0 +1,2 @@
+
+Thanks for the game
diff --git a/34_Digits/csharp/Resources/TryAgain.txt b/34_Digits/csharp/Resources/TryAgain.txt
new file mode 100644
index 00000000..74bdca68
--- /dev/null
+++ b/34_Digits/csharp/Resources/TryAgain.txt
@@ -0,0 +1,2 @@
+Only use the digits '0', '1', or '2'.
+Let's try again.
diff --git a/34_Digits/csharp/Resources/WantToTryAgain.txt b/34_Digits/csharp/Resources/WantToTryAgain.txt
new file mode 100644
index 00000000..38f4509d
--- /dev/null
+++ b/34_Digits/csharp/Resources/WantToTryAgain.txt
@@ -0,0 +1 @@
+Do you want to try again (1 for yes, 0 for no)
\ No newline at end of file
diff --git a/34_Digits/csharp/Resources/YouWin.txt b/34_Digits/csharp/Resources/YouWin.txt
new file mode 100644
index 00000000..87b26b38
--- /dev/null
+++ b/34_Digits/csharp/Resources/YouWin.txt
@@ -0,0 +1,4 @@
+
+I guessed less than 1/3 of your numbers.
+You beat me. Congratulations *****
+
diff --git a/41_Guess/csharp/Game.cs b/41_Guess/csharp/Game.cs
new file mode 100644
index 00000000..57ae071a
--- /dev/null
+++ b/41_Guess/csharp/Game.cs
@@ -0,0 +1,78 @@
+namespace Guess;
+
+internal class Game
+{
+ private readonly IReadWrite _io;
+ private readonly IRandom _random;
+
+ public Game(IReadWrite io, IRandom random)
+ {
+ _io = io;
+ _random = random;
+ }
+
+ public void Play()
+ {
+ while (true)
+ {
+ _io.Write(Streams.Introduction);
+
+ var limit = _io.ReadNumber(Prompts.Limit);
+ _io.WriteLine();
+
+ // There's a bug here that exists in the original code.
+ // If the limit entered is <= 0 then the program will crash.
+ var targetGuessCount = checked((int)Math.Log2(limit) + 1);
+
+ PlayGuessingRounds(limit, targetGuessCount);
+
+ _io.Write(Streams.BlankLines);
+ }
+ }
+
+ private void PlayGuessingRounds(float limit, int targetGuessCount)
+ {
+ while (true)
+ {
+ _io.WriteLine(Formats.Thinking, limit);
+
+ // There's a bug here that exists in the original code. If a non-integer is entered as the limit
+ // then it's possible for the secret number to be the next integer greater than the limit.
+ var secretNumber = (int)_random.NextFloat(limit) + 1;
+
+ var guessCount = 0;
+
+ while (true)
+ {
+ var guess = _io.ReadNumber("");
+ if (guess <= 0) { return; }
+ guessCount++;
+ if (IsGuessCorrect(guess, secretNumber)) { break; }
+ }
+
+ ReportResult(guessCount, targetGuessCount);
+
+ _io.Write(Streams.BlankLines);
+ }
+ }
+
+ private bool IsGuessCorrect(float guess, int secretNumber)
+ {
+ if (guess < secretNumber) { _io.Write(Streams.TooLow); }
+ if (guess > secretNumber) { _io.Write(Streams.TooHigh); }
+
+ return guess == secretNumber;
+ }
+
+ private void ReportResult(int guessCount, int targetGuessCount)
+ {
+ _io.WriteLine(Formats.ThatsIt, guessCount);
+ _io.WriteLine(
+ (guessCount - targetGuessCount) switch
+ {
+ < 0 => Strings.VeryGood,
+ 0 => Strings.Good,
+ > 0 => string.Format(Formats.ShouldHave, targetGuessCount)
+ });
+ }
+}
\ No newline at end of file
diff --git a/41_Guess/csharp/Guess.csproj b/41_Guess/csharp/Guess.csproj
index d3fe4757..3870320c 100644
--- a/41_Guess/csharp/Guess.csproj
+++ b/41_Guess/csharp/Guess.csproj
@@ -6,4 +6,12 @@
enable
enable
+
+
+
+
+
+
+
+
diff --git a/41_Guess/csharp/Program.cs b/41_Guess/csharp/Program.cs
new file mode 100644
index 00000000..73ab09dd
--- /dev/null
+++ b/41_Guess/csharp/Program.cs
@@ -0,0 +1,7 @@
+global using Games.Common.IO;
+global using Games.Common.Randomness;
+global using static Guess.Resources.Resource;
+
+using Guess;
+
+new Game(new ConsoleIO(), new RandomNumberGenerator()).Play();
diff --git a/41_Guess/csharp/Resources/BlankLines.txt b/41_Guess/csharp/Resources/BlankLines.txt
new file mode 100644
index 00000000..3f2ff2d6
--- /dev/null
+++ b/41_Guess/csharp/Resources/BlankLines.txt
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/41_Guess/csharp/Resources/Good.txt b/41_Guess/csharp/Resources/Good.txt
new file mode 100644
index 00000000..989dfa38
--- /dev/null
+++ b/41_Guess/csharp/Resources/Good.txt
@@ -0,0 +1 @@
+Good.
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/Introduction.txt b/41_Guess/csharp/Resources/Introduction.txt
new file mode 100644
index 00000000..ed679492
--- /dev/null
+++ b/41_Guess/csharp/Resources/Introduction.txt
@@ -0,0 +1,9 @@
+ Guess
+ Creative Computing Morristown, New Jersey
+
+
+
+This is a number guessing game. I'll think
+of a number between 1 and any limit you want.
+The you have to guess what it is.
+
diff --git a/41_Guess/csharp/Resources/Limit.txt b/41_Guess/csharp/Resources/Limit.txt
new file mode 100644
index 00000000..62e698a6
--- /dev/null
+++ b/41_Guess/csharp/Resources/Limit.txt
@@ -0,0 +1 @@
+What limit do you want
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/Resource.cs b/41_Guess/csharp/Resources/Resource.cs
new file mode 100644
index 00000000..d42477e2
--- /dev/null
+++ b/41_Guess/csharp/Resources/Resource.cs
@@ -0,0 +1,44 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Guess.Resources;
+
+internal static class Resource
+{
+ internal static class Streams
+ {
+ public static Stream Introduction => GetStream();
+ public static Stream TooLow => GetStream();
+ public static Stream TooHigh => GetStream();
+ public static Stream BlankLines => GetStream();
+ }
+
+ internal static class Formats
+ {
+ public static string Thinking => GetString();
+ public static string ThatsIt => GetString();
+ public static string ShouldHave => GetString();
+ }
+
+ internal static class Prompts
+ {
+ public static string Limit => GetString();
+ }
+
+ internal static class Strings
+ {
+ public static string Good => GetString();
+ public static string VeryGood => 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}'.");
+}
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/ShouldHave.txt b/41_Guess/csharp/Resources/ShouldHave.txt
new file mode 100644
index 00000000..84803588
--- /dev/null
+++ b/41_Guess/csharp/Resources/ShouldHave.txt
@@ -0,0 +1 @@
+You should have been able to get it in only {0}
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/ThatsIt.txt b/41_Guess/csharp/Resources/ThatsIt.txt
new file mode 100644
index 00000000..61f78c43
--- /dev/null
+++ b/41_Guess/csharp/Resources/ThatsIt.txt
@@ -0,0 +1 @@
+That's it! You got it in {0} tries.
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/Thinking.txt b/41_Guess/csharp/Resources/Thinking.txt
new file mode 100644
index 00000000..8f1bbac7
--- /dev/null
+++ b/41_Guess/csharp/Resources/Thinking.txt
@@ -0,0 +1,2 @@
+I'm thinking of a number between 1 and {0}
+Now you try to guess what it is.
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/TooHigh.txt b/41_Guess/csharp/Resources/TooHigh.txt
new file mode 100644
index 00000000..bb4ee4ed
--- /dev/null
+++ b/41_Guess/csharp/Resources/TooHigh.txt
@@ -0,0 +1 @@
+Too high. Try a smaller answer.
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/TooLow.txt b/41_Guess/csharp/Resources/TooLow.txt
new file mode 100644
index 00000000..4bc1776f
--- /dev/null
+++ b/41_Guess/csharp/Resources/TooLow.txt
@@ -0,0 +1 @@
+Too low. Try a bigger answer.
\ No newline at end of file
diff --git a/41_Guess/csharp/Resources/VeryGood.txt b/41_Guess/csharp/Resources/VeryGood.txt
new file mode 100644
index 00000000..606150c7
--- /dev/null
+++ b/41_Guess/csharp/Resources/VeryGood.txt
@@ -0,0 +1 @@
+Very good.
\ No newline at end of file
diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md
index 3cc22c9e..3d906342 100644
--- a/56_Life_for_Two/README.md
+++ b/56_Life_for_Two/README.md
@@ -6,6 +6,7 @@ There are two players; the game is played on a 5x5 board and each player has a s
The # and * are regarded as the same except when deciding whether to generate a live cell. An empty cell having two `#` and one `*` for neighbors will generate a `#`, i.e. the live cell generated belongs to the player who has the majority of the 3 live cells surrounding the empty cell where life is to be generated, for example:
+```
| | 1 | 2 | 3 | 4 | 5 |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 | | | | | |
@@ -13,9 +14,10 @@ The # and * are regarded as the same except when deciding whether to generate a
| 3 | | | | # | |
| 4 | | | # | | |
| 5 | | | | | |
+```
A new cell will be generated at (3,3) which will be a `#` since there are two `#` and one `*` surrounding. The board will then become:
-
+```
| | 1 | 2 | 3 | 4 | 5 |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 | | | | | |
@@ -23,7 +25,7 @@ A new cell will be generated at (3,3) which will be a `#` since there are two `#
| 3 | | | # | # | |
| 4 | | | | | |
| 5 | | | | | |
-
+```
On the first most each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.)
The board is then adjusted to the next generation and printed out.
diff --git a/56_Life_for_Two/java/LifeForTwo.java b/56_Life_for_Two/java/LifeForTwo.java
new file mode 100644
index 00000000..1f68e794
--- /dev/null
+++ b/56_Life_for_Two/java/LifeForTwo.java
@@ -0,0 +1,305 @@
+import java.util.*;
+import java.util.stream.IntStream;
+
+/**
+ * Life for Two
+ *
+ * The original BASIC program uses a grid with an extras border of cells all around,
+ * probably to simplify calculations and manipulations. This java program has the exact
+ * grid size and instead uses boundary check conditions in the logic.
+ *
+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
+ */
+public class LifeForTwo {
+
+ final static int GRID_SIZE = 5;
+
+ //Pair of offset which when added to the current cell's coordinates,
+ // give the coordinates of the neighbours
+ final static int[] neighbourCellOffsets = {
+ -1, 0,
+ 1, 0,
+ 0, -1,
+ 0, 1,
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+ };
+
+ //The best term that I could come with to describe these numbers was 'masks'
+ //They act like indicators to decide which player won the cell. The value is the score of the cell after all the
+ // generation calculations.
+ final static List maskPlayer1 = List.of(3, 102, 103, 120, 130, 121, 112, 111, 12);
+ final static List maskPlayer2 = List.of(21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012);
+
+ public static void main(String[] args) {
+ printIntro();
+ Scanner scan = new Scanner(System.in);
+ scan.useDelimiter("\\D");
+
+ int[][] grid = new int[GRID_SIZE][GRID_SIZE];
+
+ initializeGrid(grid);
+
+ //Read the initial 3 moves for each player
+ for (int b = 1; b <= 2; b++) {
+ System.out.printf("\nPLAYER %d - 3 LIVE PIECES.%n", b);
+ for (int k1 = 1; k1 <= 3; k1++) {
+ var player1Coordinates = readUntilValidCoordinates(scan, grid);
+ grid[player1Coordinates.x - 1][player1Coordinates.y - 1] = (b == 1 ? 3 : 30);
+ }
+ }
+
+ printGrid(grid);
+
+ calculatePlayersScore(grid); //Convert 3, 30 to 100, 1000
+
+ resetGridForNextGen(grid);
+ computeCellScoresForOneGen(grid);
+
+ var playerScores = calculatePlayersScore(grid);
+ resetGridForNextGen(grid);
+
+ boolean gameOver = false;
+ while (!gameOver) {
+ printGrid(grid);
+ if (playerScores.getPlayer1Score() == 0 && playerScores.getPlayer2Score() == 0) {
+ System.out.println("\nA DRAW");
+ gameOver = true;
+ } else if (playerScores.getPlayer2Score() == 0) {
+ System.out.println("\nPLAYER 1 IS THE WINNER");
+ gameOver = true;
+ } else if (playerScores.getPlayer1Score() == 0) {
+ System.out.println("\nPLAYER 2 IS THE WINNER");
+ gameOver = true;
+ } else {
+ System.out.print("PLAYER 1 ");
+ Coordinate player1Move = readCoordinate(scan);
+ System.out.print("PLAYER 2 ");
+ Coordinate player2Move = readCoordinate(scan);
+ if (!player1Move.equals(player2Move)) {
+ grid[player1Move.x - 1][player1Move.y - 1] = 100;
+ grid[player2Move.x - 1][player2Move.y - 1] = 1000;
+ }
+ //In the original, B is assigned 99 when both players choose the same cell
+ //and that is used to control the flow
+ computeCellScoresForOneGen(grid);
+ playerScores = calculatePlayersScore(grid);
+ resetGridForNextGen(grid);
+ }
+ }
+
+ }
+
+ private static void initializeGrid(int[][] grid) {
+ for (int[] row : grid) {
+ Arrays.fill(row, 0);
+ }
+ }
+
+ private static void computeCellScoresForOneGen(int[][] grid) {
+ for (int i = 0; i < GRID_SIZE; i++) {
+ for (int j = 0; j < GRID_SIZE; j++) {
+ if (grid[i][j] >= 100) {
+ calculateScoreForOccupiedCell(grid, i, j);
+ }
+ }
+ }
+ }
+
+ private static Scores calculatePlayersScore(int[][] grid) {
+ int m2 = 0;
+ int m3 = 0;
+ for (int i = 0; i < GRID_SIZE; i++) {
+ for (int j = 0; j < GRID_SIZE; j++) {
+ if (grid[i][j] < 3) {
+ grid[i][j] = 0;
+ } else {
+ if (maskPlayer1.contains(grid[i][j])) {
+ m2++;
+ } else if (maskPlayer2.contains(grid[i][j])) {
+ m3++;
+ }
+ }
+ }
+ }
+ return new Scores(m2, m3);
+ }
+
+ private static void resetGridForNextGen(int[][] grid) {
+ for (int i = 0; i < GRID_SIZE; i++) {
+ for (int j = 0; j < GRID_SIZE; j++) {
+ if (grid[i][j] < 3) {
+ grid[i][j] = 0;
+ } else {
+ if (maskPlayer1.contains(grid[i][j])) {
+ grid[i][j] = 100;
+ } else if (maskPlayer2.contains(grid[i][j])) {
+ grid[i][j] = 1000;
+ } else {
+ grid[i][j] = 0;
+ }
+ }
+ }
+ }
+ }
+
+ private static void calculateScoreForOccupiedCell(int[][] grid, int i, int j) {
+ var b = 1;
+ if (grid[i][j] > 999) {
+ b = 10;
+ }
+ for (int k = 0; k < 15; k += 2) {
+ //check bounds
+ var neighbourX = i + neighbourCellOffsets[k];
+ var neighbourY = j + neighbourCellOffsets[k + 1];
+ if (neighbourX >= 0 && neighbourX < GRID_SIZE &&
+ neighbourY >= 0 && neighbourY < GRID_SIZE) {
+ grid[neighbourX][neighbourY] = grid[neighbourX][neighbourY] + b;
+ }
+
+ }
+ }
+
+ private static void printGrid(int[][] grid) {
+ System.out.println();
+ printRowEdge();
+ System.out.println();
+ for (int i = 0; i < grid.length; i++) {
+ System.out.printf("%d ", i + 1);
+ for (int j = 0; j < grid[i].length; j++) {
+ System.out.printf(" %c ", mapChar(grid[i][j]));
+ }
+ System.out.printf(" %d", i + 1);
+ System.out.println();
+ }
+ printRowEdge();
+ System.out.println();
+ }
+
+ private static void printRowEdge() {
+ System.out.print("0 ");
+ IntStream.range(1, GRID_SIZE + 1).forEach(i -> System.out.printf(" %s ", i));
+ System.out.print(" 0");
+ }
+
+ private static char mapChar(int i) {
+ if (i == 3 || i == 100) {
+ return '*';
+ }
+ if (i == 30 || i == 1000) {
+ return '#';
+ }
+ return ' ';
+ }
+
+ private static Coordinate readUntilValidCoordinates(Scanner scanner, int[][] grid) {
+ boolean coordinateInRange = false;
+ Coordinate coordinate = null;
+ while (!coordinateInRange) {
+ coordinate = readCoordinate(scanner);
+ if (coordinate.x <= 0 || coordinate.x > GRID_SIZE
+ || coordinate.y <= 0 || coordinate.y > GRID_SIZE
+ || grid[coordinate.x - 1][coordinate.y - 1] != 0) {
+ System.out.println("ILLEGAL COORDS. RETYPE");
+ } else {
+ coordinateInRange = true;
+ }
+ }
+ return coordinate;
+ }
+
+ private static Coordinate readCoordinate(Scanner scanner) {
+ Coordinate coordinate = null;
+ int x, y;
+ boolean valid = false;
+
+ System.out.println("X,Y");
+ System.out.print("XXXXXX\r");
+ System.out.print("$$$$$$\r");
+ System.out.print("&&&&&&\r");
+
+ while (!valid) {
+ try {
+ System.out.print("? ");
+ y = scanner.nextInt();
+ x = scanner.nextInt();
+ valid = true;
+ coordinate = new Coordinate(x, y);
+ } catch (InputMismatchException e) {
+ System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE");
+ valid = false;
+ } finally {
+ scanner.nextLine();
+ }
+ }
+ return coordinate;
+ }
+
+ private static void printIntro() {
+ System.out.println(" LIFE2");
+ System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+ System.out.println("\n\n");
+
+ System.out.println("\tU.B. LIFE GAME");
+ }
+
+ private static class Coordinate {
+ private final int x, y;
+
+ public Coordinate(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ @Override
+ public String toString() {
+ return "Coordinate{" +
+ "x=" + x +
+ ", y=" + y +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Coordinate that = (Coordinate) o;
+ return x == that.x && y == that.y;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(x, y);
+ }
+ }
+
+ private static class Scores {
+ private final int player1Score;
+ private final int player2Score;
+
+ public Scores(int player1Score, int player2Score) {
+ this.player1Score = player1Score;
+ this.player2Score = player2Score;
+ }
+
+ public int getPlayer1Score() {
+ return player1Score;
+ }
+
+ public int getPlayer2Score() {
+ return player2Score;
+ }
+ }
+
+
+}
diff --git a/56_Life_for_Two/python/life_for_two.py b/56_Life_for_Two/python/life_for_two.py
new file mode 100644
index 00000000..a79be546
--- /dev/null
+++ b/56_Life_for_Two/python/life_for_two.py
@@ -0,0 +1,155 @@
+'''
+LIFE FOR TWO
+
+Competitive Game of Life (two or more players).
+
+Ported by Sajid Sarker (2022).
+'''
+# Global Variable Initialisation
+gn = []
+gx = []
+gy = []
+gk = [0, 3, 102, 103, 120, 130, 121, 112, 111, 12, 21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012]
+ga = [0, -1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, -1, -1, 1, 1, 1]
+m2 = 0
+m3 = 0
+
+# Initialise the board
+for j in range(6):
+ gn.append([])
+ for k in range(6):
+ gn[j].append(0)
+
+for i in range(3):
+ gx.append(0)
+ gy.append(0)
+
+# Helper Functions
+def tab(number) -> str:
+ t = ""
+ while len(t) < number:
+ t += " "
+ return t
+
+def display_header() -> None:
+ print("{}LIFE2".format(tab(33)))
+ print("{}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n".format(tab(15)))
+ print("{}U.B. LIFE GAME".format(tab(10)))
+
+# Board Functions
+def setup_board() -> None:
+ # Players add symbols to initially setup the board
+ for b in range(1, 3):
+ p1 = 3 if b != 2 else 30
+ print("\nPLAYER {} - 3 LIVE PIECES.".format(b))
+ for k1 in range(1, 4):
+ query_player(b)
+ gn[gx[b]][gy[b]] = p1
+
+def modify_board() -> None:
+ # Players take turns to add symbols and modify the board
+ for b in range(1, 3):
+ print("PLAYER {} ".format(b))
+ query_player(b)
+ if b == 99:
+ break
+ if b <= 2:
+ gn[gx[1]][gy[1]] = 100
+ gn[gx[2]][gy[2]] = 1000
+
+def simulate_board() -> None:
+ # Simulate the board for one step
+ for j in range(1, 6):
+ for k in range(1, 6):
+ if gn[j][k] > 99:
+ b = 1 if gn[j][k] <= 999 else 10
+ for o1 in range(1, 16, 2):
+ gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] = gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] + b
+ #gn[j + ga[o1]][k + ga[o1 + 1]] = gn[j + ga[o1]][k + ga[o1 + 1]] + b
+
+def display_board() -> None:
+ # Draws the board with all symbols
+ m2, m3 = 0, 0
+ for j in range(7):
+ print("")
+ for k in range(7):
+ if j == 0 or j == 6:
+ if k != 6:
+ print(" " + str(k) + " ", end="")
+ else:
+ print(" 0 ", end="")
+ elif k == 0 or k == 6:
+ if j != 6:
+ print(" " + str(j) + " ", end="")
+ else:
+ print(" 0\n")
+ else:
+ if gn[j][k] < 3:
+ gn[j][k] = 0
+ print(" ", end="")
+ else:
+ for o1 in range(1, 19):
+ if gn[j][k] == gk[o1]:
+ break
+ if o1 <= 18:
+ if o1 > 9:
+ gn[j][k] = 1000
+ m3 += 1
+ print(" # ", end="")
+ else:
+ gn[j][k] = 100
+ m2 += 1
+ print(" * ", end="")
+ else:
+ gn[j][k] = 0
+ print(" ", end="")
+
+# Player Functions
+def query_player(b) -> None:
+ # Query player for symbol placement coordinates
+ while True:
+ print("X,Y\nXXXXXX\n$$$$$$\n&&&&&&")
+ a_ = input("??")
+ b_ = input("???")
+ x_ = [int(num) for num in a_.split() if num.isdigit()]
+ y_ = [int(num) for num in b_.split() if num.isdigit()]
+ x_ = [0] if len(x_) == 0 else x_
+ y_ = [0] if len(y_) == 0 else y_
+ gx[b] = y_[0]
+ gy[b] = x_[0]
+ if gx[b] in range(1, 6) and gy[b] in range(1, 6) and gn[gx[b]][gy[b]] == 0:
+ break
+ print("ILLEGAL COORDS. RETYPE")
+ if b != 1:
+ if gx[1] == gx[2] and gy[1] == gy[2]:
+ print("SAME COORD. SET TO 0")
+ gn[gx[b] + 1][gy[b] + 1] = 0
+ b = 99
+
+# Game Functions
+def check_winner(m2, m3) -> None:
+ # Check if the game has been won
+ if m2 == 0 and m3 == 0:
+ print("\nA DRAW\n")
+ return
+ if m3 == 0:
+ print("\nPLAYER 1 IS THE WINNER\n")
+ return
+ if m2 == 0:
+ print("\nPLAYER 2 IS THE WINNER\n")
+ return
+
+# Program Flow
+def main() -> None:
+ display_header()
+ setup_board()
+ display_board()
+ while True:
+ print("\n")
+ simulate_board()
+ display_board()
+ check_winner(m2, m3)
+ modify_board()
+
+if __name__ == "__main__":
+ main()
diff --git a/67_One_Check/csharp/Board.cs b/67_One_Check/csharp/Board.cs
new file mode 100644
index 00000000..2e68072d
--- /dev/null
+++ b/67_One_Check/csharp/Board.cs
@@ -0,0 +1,64 @@
+namespace OneCheck;
+
+internal class Board
+{
+ private readonly bool[][] _checkers;
+ private int _pieceCount;
+ private int _moveCount;
+
+ public Board()
+ {
+ _checkers =
+ Enumerable.Range(0, 8)
+ .Select(r => Enumerable.Range(0, 8)
+ .Select(c => r <= 1 || r >= 6 || c <= 1 || c >= 6).ToArray())
+ .ToArray();
+ _pieceCount = 48;
+ }
+
+ private bool this[int index]
+ {
+ get => _checkers[index / 8][index % 8];
+ set => _checkers[index / 8][index % 8] = value;
+ }
+
+ public bool PlayMove(IReadWrite io)
+ {
+ while (true)
+ {
+ var from = (int)io.ReadNumber(Prompts.From);
+ if (from == 0) { return false; }
+
+ var move = new Move { From = from - 1, To = (int)io.ReadNumber(Prompts.To) - 1 };
+
+ if (TryMove(move))
+ {
+ _moveCount++;
+ return true;
+ }
+
+ io.Write(Streams.IllegalMove);
+ }
+ }
+
+ public bool TryMove(Move move)
+ {
+ if (move.IsInRange && move.IsTwoSpacesDiagonally && IsPieceJumpingPieceToEmptySpace(move))
+ {
+ this[move.From] = false;
+ this[move.Jumped] = false;
+ this[move.To] = true;
+ _pieceCount--;
+ return true;
+ }
+
+ return false;
+ }
+
+ private bool IsPieceJumpingPieceToEmptySpace(Move move) => this[move.From] && this[move.Jumped] && !this[move.To];
+
+ public string GetReport() => string.Format(Formats.Results, _moveCount, _pieceCount);
+
+ public override string ToString() =>
+ string.Join(Environment.NewLine, _checkers.Select(r => string.Join(" ", r.Select(c => c ? " 1" : " 0"))));
+}
diff --git a/67_One_Check/csharp/Game.cs b/67_One_Check/csharp/Game.cs
new file mode 100644
index 00000000..d9e64e26
--- /dev/null
+++ b/67_One_Check/csharp/Game.cs
@@ -0,0 +1,45 @@
+namespace OneCheck;
+
+internal class Game
+{
+ private readonly IReadWrite _io;
+
+ public Game(IReadWrite io)
+ {
+ _io = io;
+ }
+
+ public void Play()
+ {
+ _io.Write(Streams.Introduction);
+
+ do
+ {
+ var board = new Board();
+ do
+ {
+ _io.WriteLine(board);
+ _io.WriteLine();
+ } while (board.PlayMove(_io));
+
+ _io.WriteLine(board.GetReport());
+ } while (_io.ReadYesNo(Prompts.TryAgain) == "yes");
+
+ _io.Write(Streams.Bye);
+ }
+}
+
+internal static class IOExtensions
+{
+ internal static string ReadYesNo(this IReadWrite io, string prompt)
+ {
+ while (true)
+ {
+ var response = io.ReadString(prompt).ToLower();
+
+ if (response == "yes" || response == "no") { return response; }
+
+ io.Write(Streams.YesOrNo);
+ }
+ }
+}
diff --git a/67_One_Check/csharp/Move.cs b/67_One_Check/csharp/Move.cs
new file mode 100644
index 00000000..0b48659e
--- /dev/null
+++ b/67_One_Check/csharp/Move.cs
@@ -0,0 +1,13 @@
+namespace OneCheck;
+
+internal class Move
+{
+ public int From { get; init; }
+ public int To { get; init; }
+ public int Jumped => (From + To) / 2;
+
+ public bool IsInRange => From >= 0 && From <= 63 && To >= 0 && To <= 63;
+ public bool IsTwoSpacesDiagonally => RowDelta == 2 && ColumnDelta == 2;
+ private int RowDelta => Math.Abs(From / 8 - To / 8);
+ private int ColumnDelta => Math.Abs(From % 8 - To % 8);
+}
\ No newline at end of file
diff --git a/67_One_Check/csharp/OneCheck.csproj b/67_One_Check/csharp/OneCheck.csproj
index d3fe4757..3870320c 100644
--- a/67_One_Check/csharp/OneCheck.csproj
+++ b/67_One_Check/csharp/OneCheck.csproj
@@ -6,4 +6,12 @@
enable
enable
+
+
+
+
+
+
+
+
diff --git a/67_One_Check/csharp/Program.cs b/67_One_Check/csharp/Program.cs
new file mode 100644
index 00000000..4a3ab83b
--- /dev/null
+++ b/67_One_Check/csharp/Program.cs
@@ -0,0 +1,5 @@
+global using Games.Common.IO;
+global using static OneCheck.Resources.Resource;
+using OneCheck;
+
+new Game(new ConsoleIO()).Play();
diff --git a/67_One_Check/csharp/Resources/Bye.txt b/67_One_Check/csharp/Resources/Bye.txt
new file mode 100644
index 00000000..ee4ddab1
--- /dev/null
+++ b/67_One_Check/csharp/Resources/Bye.txt
@@ -0,0 +1,2 @@
+
+O.K. Hope you had fun!!
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/From.txt b/67_One_Check/csharp/Resources/From.txt
new file mode 100644
index 00000000..bb4c7a2d
--- /dev/null
+++ b/67_One_Check/csharp/Resources/From.txt
@@ -0,0 +1 @@
+Jump from
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/IllegalMove.txt b/67_One_Check/csharp/Resources/IllegalMove.txt
new file mode 100644
index 00000000..a96b6e81
--- /dev/null
+++ b/67_One_Check/csharp/Resources/IllegalMove.txt
@@ -0,0 +1 @@
+Illegal move. Try again...
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/Introduction.txt b/67_One_Check/csharp/Resources/Introduction.txt
new file mode 100644
index 00000000..409f6b37
--- /dev/null
+++ b/67_One_Check/csharp/Resources/Introduction.txt
@@ -0,0 +1,30 @@
+ One Check
+ Creative Computing Morristown, New Jersey
+
+
+
+Solitaire checker puzzle by David Ahl
+
+48 checkers and placed on the 2 outside spaces of a
+standard 64-square checkerboard. The object is to
+remove as many checkers as possible by diagonal jumps
+(as in standard checkers). Use the numbered board to
+indicate the square you wish to jump from and to. On
+the board printed out on each turn '1' indicates a
+checker and '0' an empty square. When you have no
+possible jumps remaining, input a '0' in response to
+question 'Jump from ?'
+
+Here is the numerical board:
+
+ 1 2 3 4 5 6 7 8
+ 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24
+ 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40
+ 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56
+ 57 58 59 60 61 62 63 64
+
+And here is the opening position of the checkers.
+
diff --git a/67_One_Check/csharp/Resources/Resource.cs b/67_One_Check/csharp/Resources/Resource.cs
new file mode 100644
index 00000000..7095d7ec
--- /dev/null
+++ b/67_One_Check/csharp/Resources/Resource.cs
@@ -0,0 +1,45 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace OneCheck.Resources;
+
+internal static class Resource
+{
+ internal static class Streams
+ {
+ public static Stream Introduction => GetStream();
+ public static Stream IllegalMove => GetStream();
+ public static Stream YesOrNo => GetStream();
+ public static Stream Bye => GetStream();
+ }
+
+ internal static class Formats
+ {
+ public static string Results => GetString();
+ }
+
+ internal static class Prompts
+ {
+ public static string From => GetString();
+ public static string To => GetString();
+ public static string TryAgain => GetString();
+ }
+
+ internal static class Strings
+ {
+ public static string TooManyColumns => GetString();
+ public static string TooManyRows => 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}'.");
+}
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/Results.txt b/67_One_Check/csharp/Resources/Results.txt
new file mode 100644
index 00000000..a8771b6b
--- /dev/null
+++ b/67_One_Check/csharp/Resources/Results.txt
@@ -0,0 +1,3 @@
+
+You made {0} jumps and had {1} pieces
+remaining on the board.
diff --git a/67_One_Check/csharp/Resources/To.txt b/67_One_Check/csharp/Resources/To.txt
new file mode 100644
index 00000000..788636ff
--- /dev/null
+++ b/67_One_Check/csharp/Resources/To.txt
@@ -0,0 +1 @@
+to
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/TryAgain.txt b/67_One_Check/csharp/Resources/TryAgain.txt
new file mode 100644
index 00000000..c65e51fc
--- /dev/null
+++ b/67_One_Check/csharp/Resources/TryAgain.txt
@@ -0,0 +1 @@
+Try again
\ No newline at end of file
diff --git a/67_One_Check/csharp/Resources/YesOrNo.txt b/67_One_Check/csharp/Resources/YesOrNo.txt
new file mode 100644
index 00000000..703d4ad6
--- /dev/null
+++ b/67_One_Check/csharp/Resources/YesOrNo.txt
@@ -0,0 +1 @@
+Please answer 'Yes' or 'No'.
\ No newline at end of file
diff --git a/76_Russian_Roulette/lua/russianroulette.lua b/76_Russian_Roulette/lua/russianroulette.lua
new file mode 100644
index 00000000..546ec6c4
--- /dev/null
+++ b/76_Russian_Roulette/lua/russianroulette.lua
@@ -0,0 +1,58 @@
+print [[
+ RUSSIAN ROULETTE
+ CREATIVE COMPUTING MORRISTOWN, NEW JERSY
+This is a game of >>>>>>>>>>Russian Roulette
+Here is a Revolver
+
+]]
+
+local function parse_input()
+ local incorrect_input = true
+ local input = nil
+ while incorrect_input do
+ input = io.read(1)
+ if input == "1" or input == "2" then incorrect_input = false end
+ end
+ return input
+end
+
+local function russian_roulette()
+ local NUMBER_OF_ROUNDS = 9
+
+ while true do
+ local dead = false
+ local n = 0
+ print("Type '1' to Spin chamber and pull trigger")
+ print("Type '2' to Give up")
+ print("Go")
+
+ while not dead do
+ local choice = parse_input()
+ if choice == "2" then break end
+
+ if math.random() > 0.833333333333334 then
+ dead = true
+ else
+ print("CLICK")
+ n = n + 1
+ end
+
+ if n > NUMBER_OF_ROUNDS then break end
+ end
+
+ if dead then
+ print("BANG!!!!! You're Dead!")
+ print("Condolences will be sent to your relatives.\n\n\n")
+ print("...Next victim...")
+ elseif n > NUMBER_OF_ROUNDS then
+ print("You win!!!!!")
+ print("Let someone else blow his brain out.\n")
+ else
+ print(" Chicken!!!!!\n\n\n")
+ print("...Next victim....")
+ end
+ end
+end
+
+russian_roulette()
+