diff --git a/.github/workflows/Reversi Build.yml b/.github/workflows/Reversi Build.yml
new file mode 100644
index 00000000..02be7fa6
--- /dev/null
+++ b/.github/workflows/Reversi Build.yml
@@ -0,0 +1,20 @@
+name: Reversi Build
+on:
+ push:
+ paths:
+ - 'Projects/Reversi/**'
+ - '!**.md'
+ pull_request:
+ paths:
+ - 'Projects/Reversi/**'
+ - '!**.md'
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 8.0.x
+ - run: dotnet build "Projects\Reversi\Reversi.csproj" --configuration Release
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 50c70e36..3df29cc0 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -312,11 +312,21 @@
"console": "externalTerminal",
"stopAtEntry": false,
},
+ {
+ "name": "Reversi",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "Build Reversi",
+ "program": "${workspaceFolder}/Projects/Reversi/bin/Debug/Reversi.dll",
+ "cwd": "${workspaceFolder}/Projects/Reversi/bin/Debug",
+ "console": "externalTerminal",
+ "stopAtEntry": false,
+ },
{
"name": "Darts",
"type": "coreclr",
"request": "launch",
- "preLaunchTask": "Build Oligopoly",
+ "preLaunchTask": "Build Darts",
"program": "${workspaceFolder}/Projects/Darts/bin/Debug/Darts.dll",
"cwd": "${workspaceFolder}/Projects/Darts/bin/Debug",
"console": "externalTerminal",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index eba8b91b..22726416 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -678,6 +678,19 @@
],
"problemMatcher": "$msCompile",
},
+ {
+ "label": "Build Reversi",
+ "command": "dotnet",
+ "type": "process",
+ "args":
+ [
+ "build",
+ "${workspaceFolder}/Projects/Reversi/Reversi.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary",
+ ],
+ "problemMatcher": "$msCompile",
+ },
{
"label": "Build Solution",
"command": "dotnet",
diff --git a/Projects/Reversi/Program.cs b/Projects/Reversi/Program.cs
new file mode 100644
index 00000000..e46ff8b6
--- /dev/null
+++ b/Projects/Reversi/Program.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+(int Left, int Top)[] directions =
+[
+ ( 1, 0), // right
+ (-1, 0), // left
+ ( 0, 1), // down
+ ( 0, -1), // up
+ ( 1, 1), // down-right
+ (-1, -1), // up-left
+ ( 1, -1), // up-right
+ (-1, 1), // down-left
+];
+
+Console.OutputEncoding = Encoding.UTF8;
+PlayAgain:
+(int Left, int Top) cursor = default;
+bool?[,] board;
+HashSet<(int Left, int Top)> validMoves = [];
+bool turn = true;
+bool? playerColor = null;
+Console.Clear();
+InitializeBoard();
+RenderBoard();
+Console.Write($"""
+
+ When you place a piece on the board all
+ your oponent pieces you jump will be converted
+ into your pieces. Have the most pieces at the
+ end of the game and you win. You and your
+ opponent will be randomly assigned a color of
+ black or white. The white player always moves first.
+
+ Controls:
+ - enter: start match
+ - escape: close game
+ """);
+MainMenuInput:
+Console.CursorVisible = false;
+switch (Console.ReadKey(true).Key)
+{
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto MainMenuInput;
+}
+playerColor = Random.Shared.Next(2) is 0;
+Console.Clear();
+RenderBoard();
+Console.Write($"""
+
+ You are {(playerColor.Value ? "● white" : "○ black")} and your opponent
+ is {(playerColor.Value ? "○ black" : "● white")}.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ColorConfirmInput:
+Console.CursorVisible = false;
+switch (Console.ReadKey(true).Key)
+{
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto ColorConfirmInput;
+}
+while (true)
+{
+ UpdateValidMoves(turn);
+ if (validMoves.Count is 0)
+ {
+ turn = !turn;
+ UpdateValidMoves(turn);
+ if (validMoves.Count is 0)
+ {
+ Console.Clear();
+ RenderBoard();
+ int playerScore = GetScore(playerColor.Value);
+ int opponentScore = GetScore(!playerColor.Value);
+ string endGameState =
+ playerScore > opponentScore ? "Win" :
+ playerScore < opponentScore ? "Lose" :
+ "Tie";
+ Console.Write($"""
+
+ No more valid moves. Game Over.
+
+ You {endGameState}!
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ GameOverInput:
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: goto PlayAgain;
+ default: goto GameOverInput;
+ }
+ }
+ Console.Clear();
+ RenderBoard();
+ Console.Write($"""
+
+ {(turn == playerColor ? "Your Opponent" : "You")} has no valid moves.
+ Turn skipped.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ ConfirmTurnSkip:
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto ConfirmTurnSkip;
+ }
+ goto SkipTurn;
+ }
+SkipTurn:
+ if (turn == playerColor)
+ {
+ Console.Clear();
+ RenderBoard();
+ Console.Write($"""
+
+ Controls:
+ - arrow keys: move cursor
+ - enter: place piece at '+' valid move
+ - escape: close game
+ """);
+ Console.SetCursorPosition(2 * cursor.Left, cursor.Top);
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.LeftArrow: cursor.Left = cursor.Left <= 0 ? board.GetLength(0) - 1 : cursor.Left - 1; break;
+ case ConsoleKey.RightArrow: cursor.Left = cursor.Left >= board.GetLength(0) - 1 ? 0 : cursor.Left + 1; break;
+ case ConsoleKey.UpArrow: cursor.Top = cursor.Top <= 0 ? board.GetLength(1) - 1 : cursor.Top - 1; break;
+ case ConsoleKey.DownArrow: cursor.Top = cursor.Top >= board.GetLength(1) - 1 ? 0 : cursor.Top + 1; break;
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter:
+ if (validMoves.Contains(cursor))
+ {
+ PlaceMove(cursor, playerColor.Value);
+ Console.Clear();
+ RenderBoard();
+ Console.Write($"""
+
+ You played a piece.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ MoveConfirmInput:
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto MoveConfirmInput;
+ }
+ turn = !turn;
+ }
+ break;
+ }
+ }
+ else
+ {
+ ComputerMove();
+ Console.Clear();
+ RenderBoard();
+ Console.Write($"""
+
+ Your opponent played a piece.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ OpponentMoveConfirmInput:
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: turn = !turn; break;
+ default: goto OpponentMoveConfirmInput;
+ }
+ }
+}
+Close:
+Console.Clear();
+Console.WriteLine("Reversi was closed.");
+Console.CursorVisible = true;
+
+void InitializeBoard()
+{
+ bool? _ = null, w = true, b = false;
+ board = new bool?[,]
+ {
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, w, b, _, _, _ },
+ { _, _, _, b, w, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ };
+}
+
+void RenderBoard()
+{
+ StringBuilder render = new();
+ render.AppendLine(" Reversi");
+ render.AppendLine();
+ render.AppendLine(" ┌─────────────────┐");
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ render.Append(' ');
+ render.Append('│');
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ render.Append(
+ cursor == (j, i) ? '[' :
+ cursor == (j - 1, i) ? ']' :
+ ' ');
+ render.Append(
+ validMoves.Contains((j, i)) ? '+' :
+ board[j, i] is null ? ' ' :
+ board[j, i]!.Value ? '●' : '○');
+ }
+ render.Append(cursor == (board.GetLength(0) - 1, i) ? ']' : ' ');
+ render.Append('│');
+ render.AppendLine();
+ }
+ render.AppendLine(" └─────────────────┘");
+ if (playerColor is not null)
+ {
+ render.AppendLine($" ●: {GetScore(true)} ○: {GetScore(false)}");
+ }
+ Console.SetCursorPosition(0, 0);
+ Console.Write(render);
+}
+
+int GetScore(bool color)
+{
+ int score = 0;
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ if (board[j, i] == color)
+ {
+ score++;
+ }
+ }
+ }
+ return score;
+}
+
+void UpdateValidMoves(bool color)
+{
+ validMoves.Clear();
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ if (board[j, i] is null)
+ {
+ foreach (var direction in directions)
+ {
+ bool jump = false;
+ (int Left, int Top) location = (j + direction.Left, i + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ jump = true;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ if (location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == color &&
+ jump)
+ {
+ validMoves.Add((j, i));
+ }
+ }
+ }
+ }
+ }
+}
+
+void PlaceMove((int Left, int Top) move, bool color)
+{
+ board[move.Left, move.Top] = color;
+ foreach (var direction in directions)
+ {
+ bool jump = false;
+ (int Left, int Top) location = (move.Left + direction.Left, move.Top + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ jump = true;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ if (location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == color &&
+ jump)
+ {
+ location = (move.Left + direction.Left, move.Top + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ board[location.Left, location.Top] = color;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ }
+ }
+ validMoves.Clear();
+}
+
+void ComputerMove()
+{
+ (int Left, int Top)[] validMovesArray = [.. validMoves];
+ (int Left, int Top) move = validMovesArray[Random.Shared.Next(validMovesArray.Length)];
+ cursor = move;
+ PlaceMove(move, !playerColor.Value);
+}
\ No newline at end of file
diff --git a/Projects/Reversi/README.md b/Projects/Reversi/README.md
new file mode 100644
index 00000000..ad7d81c7
--- /dev/null
+++ b/Projects/Reversi/README.md
@@ -0,0 +1,54 @@
+
+ Reversi
+
+
+
+
+
+
+
+
+
+
+
+
+ You can play this game in your browser:
+
+
+
+
+
+ Hosted On GitHub Pages
+
+
+Reversi is a 1 v 1 abstract game where you place pieces that jump over your opponents pieces and convert all the jumped pieces into your own. Whoever has the most pieces at the end of the game wins.
+
+```
+ Reversi
+
+ ┌─────────────────┐
+ │ ○ │
+ │ + ● ● ● ● │
+ │ + ○ ● ● │
+ │ +[+]● ○ + │
+ │ ○ ○ ○ ○ ○ │
+ │ + ● + + + │
+ │ ● │
+ │ ● │
+ └─────────────────┘
+ ●: 10 ○: 8
+```
+
+## Input
+
+- `↑`, `↓`, `←`, `→`: move cursor
+- `enter`: place move & confirm
+- `escape`: exit game
+
+## Downloads
+
+[win-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/win-x64/Reversi.exe)
+
+[linux-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/linux-x64/Reversi)
+
+[osx-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/osx-x64/Reversi)
diff --git a/Projects/Reversi/Reversi.csproj b/Projects/Reversi/Reversi.csproj
new file mode 100644
index 00000000..26137b7e
--- /dev/null
+++ b/Projects/Reversi/Reversi.csproj
@@ -0,0 +1,8 @@
+
+
+ Exe
+ net8.0
+ disable
+ enable
+
+
diff --git a/Projects/Website/Games/Reversi/Reversi.cs b/Projects/Website/Games/Reversi/Reversi.cs
new file mode 100644
index 00000000..a7de957d
--- /dev/null
+++ b/Projects/Website/Games/Reversi/Reversi.cs
@@ -0,0 +1,352 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Website.Games.Reversi;
+
+public class Reversi
+{
+ public readonly BlazorConsole Console = new();
+
+ public async Task Run()
+ {
+ (int Left, int Top)[] directions =
+ [
+ ( 1, 0), // right
+ (-1, 0), // left
+ ( 0, 1), // down
+ ( 0, -1), // up
+ ( 1, 1), // down-right
+ (-1, -1), // up-left
+ ( 1, -1), // up-right
+ (-1, 1), // down-left
+ ];
+
+ Console.OutputEncoding = Encoding.UTF8;
+ PlayAgain:
+ (int Left, int Top) cursor = default;
+ bool?[,] board;
+ HashSet<(int Left, int Top)> validMoves = [];
+ bool turn = true;
+ bool? playerColor = null;
+ await Console.Clear();
+ InitializeBoard();
+ await RenderBoard();
+ await Console.Write($"""
+
+ When you place a piece on the board all
+ your oponent pieces you jump will be converted
+ into your pieces. Have the most pieces at the
+ end of the game and you win. You and your
+ opponent will be randomly assigned a color of
+ black or white. The white player always moves first.
+
+ Controls:
+ - enter: start match
+ - escape: close game
+ """);
+ MainMenuInput:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto MainMenuInput;
+ }
+ playerColor = Random.Shared.Next(2) is 0;
+ await Console.Clear();
+ await RenderBoard();
+ await Console.Write($"""
+
+ You are {(playerColor.Value ? "● white" : "○ black")} and your opponent
+ is {(playerColor.Value ? "○ black" : "● white")}.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ ColorConfirmInput:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto ColorConfirmInput;
+ }
+ while (true)
+ {
+ UpdateValidMoves(turn);
+ if (validMoves.Count is 0)
+ {
+ turn = !turn;
+ UpdateValidMoves(turn);
+ if (validMoves.Count is 0)
+ {
+ await Console.Clear();
+ await RenderBoard();
+ int playerScore = GetScore(playerColor.Value);
+ int opponentScore = GetScore(!playerColor.Value);
+ string endGameState =
+ playerScore > opponentScore ? "Win" :
+ playerScore < opponentScore ? "Lose" :
+ "Tie";
+ await Console.Write($"""
+
+ No more valid moves. Game Over.
+
+ You {endGameState}!
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ GameOverInput:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: goto PlayAgain;
+ default: goto GameOverInput;
+ }
+ }
+ await Console.Clear();
+ await RenderBoard();
+ await Console.Write($"""
+
+ {(turn == playerColor ? "Your Opponent" : "You")} has no valid moves.
+ Turn skipped.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ ConfirmTurnSkip:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto ConfirmTurnSkip;
+ }
+ goto SkipTurn;
+ }
+ SkipTurn:
+ if (turn == playerColor)
+ {
+ await Console.Clear();
+ await RenderBoard();
+ await Console.Write($"""
+
+ Controls:
+ - arrow keys: move cursor
+ - enter: place piece at '+' valid move
+ - escape: close game
+ """);
+ await Console.SetCursorPosition(2 * cursor.Left, cursor.Top);
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.LeftArrow: cursor.Left = cursor.Left <= 0 ? board.GetLength(0) - 1 : cursor.Left - 1; break;
+ case ConsoleKey.RightArrow: cursor.Left = cursor.Left >= board.GetLength(0) - 1 ? 0 : cursor.Left + 1; break;
+ case ConsoleKey.UpArrow: cursor.Top = cursor.Top <= 0 ? board.GetLength(1) - 1 : cursor.Top - 1; break;
+ case ConsoleKey.DownArrow: cursor.Top = cursor.Top >= board.GetLength(1) - 1 ? 0 : cursor.Top + 1; break;
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter:
+ if (validMoves.Contains(cursor))
+ {
+ PlaceMove(cursor, playerColor.Value);
+ await Console.Clear();
+ await RenderBoard();
+ await Console.Write($"""
+
+ You played a piece.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ MoveConfirmInput:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: break;
+ default: goto MoveConfirmInput;
+ }
+ turn = !turn;
+ }
+ break;
+ }
+ }
+ else
+ {
+ ComputerMove();
+ await Console.Clear();
+ await RenderBoard();
+ await Console.Write($"""
+
+ Your opponent played a piece.
+
+ Controls:
+ - enter: continue
+ - escape: close game
+ """);
+ OpponentMoveConfirmInput:
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Escape: goto Close;
+ case ConsoleKey.Enter: turn = !turn; break;
+ default: goto OpponentMoveConfirmInput;
+ }
+ }
+ }
+ Close:
+ await Console.Clear();
+ await Console.WriteLine("Reversi was closed.");
+ Console.CursorVisible = true;
+
+ void InitializeBoard()
+ {
+ bool? _ = null, w = true, b = false;
+ board = new bool?[,]
+ {
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, w, b, _, _, _ },
+ { _, _, _, b, w, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ { _, _, _, _, _, _, _, _ },
+ };
+ }
+
+ async Task RenderBoard()
+ {
+ StringBuilder render = new();
+ render.AppendLine(" Reversi");
+ render.AppendLine();
+ render.AppendLine(" ┌─────────────────┐");
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ render.Append(' ');
+ render.Append('│');
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ render.Append(
+ cursor == (j, i) ? '[' :
+ cursor == (j - 1, i) ? ']' :
+ ' ');
+ render.Append(
+ validMoves.Contains((j, i)) ? '+' :
+ board[j, i] is null ? ' ' :
+ board[j, i]!.Value ? '●' : '○');
+ }
+ render.Append(cursor == (board.GetLength(0) - 1, i) ? ']' : ' ');
+ render.Append('│');
+ render.AppendLine();
+ }
+ render.AppendLine(" └─────────────────┘");
+ if (playerColor is not null)
+ {
+ render.AppendLine($" ●: {GetScore(true)} ○: {GetScore(false)}");
+ }
+ await Console.SetCursorPosition(0, 0);
+ await Console.Write(render);
+ }
+
+ int GetScore(bool color)
+ {
+ int score = 0;
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ if (board[j, i] == color)
+ {
+ score++;
+ }
+ }
+ }
+ return score;
+ }
+
+ void UpdateValidMoves(bool color)
+ {
+ validMoves.Clear();
+ for (int i = 0; i < board.GetLength(1); i++)
+ {
+ for (int j = 0; j < board.GetLength(0); j++)
+ {
+ if (board[j, i] is null)
+ {
+ foreach (var direction in directions)
+ {
+ bool jump = false;
+ (int Left, int Top) location = (j + direction.Left, i + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ jump = true;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ if (location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == color &&
+ jump)
+ {
+ validMoves.Add((j, i));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void PlaceMove((int Left, int Top) move, bool color)
+ {
+ board[move.Left, move.Top] = color;
+ foreach (var direction in directions)
+ {
+ bool jump = false;
+ (int Left, int Top) location = (move.Left + direction.Left, move.Top + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ jump = true;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ if (location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == color &&
+ jump)
+ {
+ location = (move.Left + direction.Left, move.Top + direction.Top);
+ while (
+ location.Left >= 0 && location.Left < board.GetLength(0) &&
+ location.Top >= 0 && location.Top < board.GetLength(1) &&
+ board[location.Left, location.Top] == !color)
+ {
+ board[location.Left, location.Top] = color;
+ location = (location.Left + direction.Left, location.Top + direction.Top);
+ }
+ }
+ }
+ validMoves.Clear();
+ }
+
+ void ComputerMove()
+ {
+ (int Left, int Top)[] validMovesArray = [.. validMoves];
+ (int Left, int Top) move = validMovesArray[Random.Shared.Next(validMovesArray.Length)];
+ cursor = move;
+ PlaceMove(move, !playerColor.Value);
+ }
+ }
+}
diff --git a/Projects/Website/Pages/Reversi.razor b/Projects/Website/Pages/Reversi.razor
new file mode 100644
index 00000000..38f09b5f
--- /dev/null
+++ b/Projects/Website/Pages/Reversi.razor
@@ -0,0 +1,52 @@
+@using System
+
+@page "/Reversi"
+
+Reversi
+
+Reversi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⌨ Keyboard input is supported if you click on the game.
+
+
+
+ ↻ You can restart the game by refreshing the page.
+
+
+@code
+{
+ Games.Reversi.Reversi Game;
+ BlazorConsole Console;
+
+ public Reversi()
+ {
+ Game = new();
+ Console = Game.Console;
+ Console.WindowWidth = 55;
+ Console.WindowHeight = 25;
+ Console.TriggerRefresh = StateHasChanged;
+ }
+
+ protected override void OnInitialized() => InvokeAsync(Game.Run);
+}
diff --git a/Projects/Website/Shared/NavMenu.razor b/Projects/Website/Shared/NavMenu.razor
index 3583f87f..357c01ad 100644
--- a/Projects/Website/Shared/NavMenu.razor
+++ b/Projects/Website/Shared/NavMenu.razor
@@ -158,6 +158,11 @@
Oligopoly
+
+
+ Reversi
+
+
Darts
diff --git a/README.md b/README.md
index 8b21181e..da096fbe 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@
|[Pong](Projects/Pong)|3|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Pong) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Pong%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
|[Flappy Bird](Projects/Flappy%20Bird)|3|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Flappy%20Bird) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Flappy%20Bird%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
|[Oligopoly](Projects/Oligopoly)|3|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Oligopoly) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Oligopoly%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)
*_[Community Contribution](https://github.com/dotnet/dotnet-console-games/pull/72)_|
+|[Reversi](Projects/Reversi)|3|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Reversi) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Reversi%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
|[Darts](Projects/Darts)|3|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Darts) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Darts%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
|[Yahtzee](Projects/Yahtzee)|4|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Yahtzee) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Yahtzee%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
|[Tanks](Projects/Tanks)|4|[![Play Now](.github/resources/play-badge.svg)](https://dotnet.github.io/dotnet-console-games/Tanks) [![Status](https://github.com/dotnet/dotnet-console-games/workflows/Tanks%20Build/badge.svg)](https://github.com/dotnet/dotnet-console-games/actions)|
diff --git a/dotnet-console-games.sln b/dotnet-console-games.sln
index e0cfdce3..2d33927d 100644
--- a/dotnet-console-games.sln
+++ b/dotnet-console-games.sln
@@ -107,7 +107,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tetris", "Projects\Tetris\T
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Word Search", "Projects\Word Search\Word Search.csproj", "{A1536214-8984-4528-90DF-F465EB491685}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lights Out", "Projects\Lights Out\Lights Out.csproj", "{31AE3F64-98FC-40E8-9A10-7276B0F8E726}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lights Out", "Projects\Lights Out\Lights Out.csproj", "{31AE3F64-98FC-40E8-9A10-7276B0F8E726}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reversi", "Projects\Reversi\Reversi.csproj", "{8D5244E1-C54E-4909-A9DE-0DE7E683D911}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -327,6 +329,10 @@ Global
{31AE3F64-98FC-40E8-9A10-7276B0F8E726}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31AE3F64-98FC-40E8-9A10-7276B0F8E726}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31AE3F64-98FC-40E8-9A10-7276B0F8E726}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D5244E1-C54E-4909-A9DE-0DE7E683D911}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D5244E1-C54E-4909-A9DE-0DE7E683D911}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D5244E1-C54E-4909-A9DE-0DE7E683D911}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D5244E1-C54E-4909-A9DE-0DE7E683D911}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/dotnet-console-games.slnf b/dotnet-console-games.slnf
index dd21dfb9..725d1db1 100644
--- a/dotnet-console-games.slnf
+++ b/dotnet-console-games.slnf
@@ -33,6 +33,7 @@
"Projects\\PacMan\\PacMan.csproj",
"Projects\\Pong\\Pong.csproj",
"Projects\\Quick Draw\\Quick Draw.csproj",
+ "Projects\\Reversi\\Reversi.csproj",
"Projects\\Rock Paper Scissors\\Rock Paper Scissors.csproj",
"Projects\\Role Playing Game\\Role Playing Game.csproj",
"Projects\\Roll And Move\\Roll And Move.csproj",