diff --git a/.github/workflows/Lights Out Build.yml b/.github/workflows/Lights Out Build.yml new file mode 100644 index 00000000..19633bb3 --- /dev/null +++ b/.github/workflows/Lights Out Build.yml @@ -0,0 +1,20 @@ +name: Lights Out Build +on: + push: + paths: + - 'Projects/Lights Out/**' + - '!**.md' + pull_request: + paths: + - 'Projects/Lights Out/**' + - '!**.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\Lights Out\Lights Out.csproj" --configuration Release diff --git a/.vscode/launch.json b/.vscode/launch.json index 5112fcc3..50c70e36 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -152,6 +152,16 @@ "console": "externalTerminal", "stopAtEntry": false, }, + { + "name": "Lights Out", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "Build Lights Out", + "program": "${workspaceFolder}/Projects/Lights Out/bin/Debug/Lights Out.dll", + "cwd": "${workspaceFolder}/Projects/Lights Out/bin/Debug", + "console": "externalTerminal", + "stopAtEntry": false, + }, { "name": "Wordle", "type": "coreclr", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index deddea10..eba8b91b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -665,6 +665,19 @@ ], "problemMatcher": "$msCompile", }, + { + "label": "Build Lights Out", + "command": "dotnet", + "type": "process", + "args": + [ + "build", + "${workspaceFolder}/Projects/Lights Out/Lights Out.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary", + ], + "problemMatcher": "$msCompile", + }, { "label": "Build Solution", "command": "dotnet", diff --git a/Projects/Lights Out/Lights Out.csproj b/Projects/Lights Out/Lights Out.csproj new file mode 100644 index 00000000..17618311 --- /dev/null +++ b/Projects/Lights Out/Lights Out.csproj @@ -0,0 +1,9 @@ + + + Exe + net8.0 + Lights_Out + disable + enable + + diff --git a/Projects/Lights Out/Program.cs b/Projects/Lights Out/Program.cs new file mode 100644 index 00000000..b9e875d1 --- /dev/null +++ b/Projects/Lights Out/Program.cs @@ -0,0 +1,310 @@ +using System; +using System.Text; + +const int Length = 5; +const bool O = true; +const bool X = false; + +bool[][][] levels = +[ + [ // 1 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, O, X, O], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 2 + [O, X, O, X, O], + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + [O, X, O, X, O], + ], + [ // 3 + [X, O, X, O, X], + [O, O, X, O, O], + [O, O, X, O, O], + [O, O, X, O, O], + [X, O, X, O, X], + ], + [ // 4 + [X, X, X, X, X], + [O, O, X, O, O], + [X, X, X, X, X], + [O, X, X, X, O], + [O, O, X, O, O], + ], + [ // 5 + [O, O, O, O, X], + [O, O, O, X, O], + [O, O, O, X, O], + [X, X, X, O, O], + [O, O, X, O, O], + ], + [ // 6 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, O, X, O], + [O, X, O, X, O], + [X, O, O, O, X], + ], + [ // 7 + [O, O, O, O, X], + [O, X, X, X, O], + [O, X, X, X, O], + [O, X, X, X, O], + [O, O, O, O, X], + ], + [ // 8 + [X, X, X, X, X], + [X, X, O, X, X], + [X, O, X, O, X], + [O, X, O, X, O], + [X, O, X, O, X], + ], + [ // 9 + [X, O, X, O, X], + [O, O, O, O, O], + [X, O, O, O, X], + [X, O, X, O, O], + [O, O, O, X, X], + ], + [ // 10 + [X, O, O, O, X], + [X, O, O, O, X], + [X, O, O, O, X], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 11 + [O, X, O, X, O], + [O, X, O, X, O], + [O, X, O, X, O], + [O, X, O, X, O], + [X, O, O, O, X], + ], + [ // 12 + [O, O, O, O, O], + [X, O, X, O, X], + [O, O, X, O, O], + [X, O, O, O, X], + [X, O, X, O, X], + ], + [ // 13 + [X, X, X, O, X], + [X, X, O, X, O], + [X, O, X, O, X], + [O, X, O, X, X], + [X, O, X, X, X], + ], + [ // 14 + [X, X, X, X, X], + [X, X, X, X, X], + [X, O, X, X, X], + [X, O, X, X, X], + [X, O, X, X, X], + ], + [ // 15 + [X, X, X, X, X], + [X, O, X, X, X], + [X, X, X, X, X], + [X, O, X, X, X], + [X, X, X, X, X], + ], + [ // 16 + [O, X, X, X, X], + [O, X, X, X, X], + [O, X, X, X, X], + [O, X, X, X, X], + [O, O, O, O, O], + ], + [ // 17 + [X, X, X, X, X], + [X, X, X, X, X], + [X, X, O, X, X], + [X, O, O, O, X], + [O, O, O, O, O], + ], + [ // 18 + [X, X, O, X, X], + [X, O, X, O, X], + [O, X, O, X, O], + [X, O, X, O, X], + [X, X, O, X, X], + ], + [ // 19 + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + ], + [ // 20 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, X, X, O], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 21 + [X, O, O, O, O], + [X, O, X, X, X], + [X, O, O, O, X], + [X, O, X, X, X], + [X, O, X, X, X], + ], + [ // 22 + [X, O, O, O, X], + [O, X, X, X, O], + [O, X, X, X, O], + [O, X, X, X, O], + [X, O, O, O, X], + ], + [ // 23 + [X, X, X, X, X], + [X, X, X, X, X], + [X, X, O, O, O], + [X, X, O, O, X], + [X, X, O, X, X], + ], + [ // 24 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, X, X, O], + [O, O, O, O, O], + [X, O, X, X, O], + ], + [ // 25 + [O, X, X, X, X], + [O, O, X, X, X], + [O, O, O, X, X], + [O, O, O, O, X], + [X, O, O, O, O], + ], +]; + +Console.OutputEncoding = Encoding.UTF8; +int level = 0; +bool[][] board = +[ + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], +]; +SetBoard(); +(int Left, int Top) cursor = (0, 0); +while (true) +{ + RenderBoard(); + Console.Write($""" + + Turn off all the lights. Level {level + 1}. + + Controls: + - arrow keys: move cursor + - enter: flip lights + - backspace: reset level + - 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 ? Length - 1 : cursor.Left - 1; break; + case ConsoleKey.RightArrow: cursor.Left = cursor.Left >= Length - 1 ? 0 : cursor.Left + 1; break; + case ConsoleKey.UpArrow: cursor.Top = cursor.Top <= 0 ? Length - 1 : cursor.Top - 1; break; + case ConsoleKey.DownArrow: cursor.Top = cursor.Top >= Length - 1 ? 0 : cursor.Top + 1; break; + case ConsoleKey.Backspace: SetBoard(); break; + case ConsoleKey.Escape: goto Close; + case ConsoleKey.Enter: + board[cursor.Top][cursor.Left] = !board[cursor.Top][cursor.Left]; + if (cursor.Top > 0) board[cursor.Top - 1][cursor.Left] = !board[cursor.Top - 1][cursor.Left]; + if (cursor.Top < Length - 1) board[cursor.Top + 1][cursor.Left] = !board[cursor.Top + 1][cursor.Left]; + if (cursor.Left > 0) board[cursor.Top][cursor.Left - 1] = !board[cursor.Top][cursor.Left - 1]; + if (cursor.Left < Length - 1) board[cursor.Top][cursor.Left + 1] = !board[cursor.Top][cursor.Left + 1]; + if (LightsOut()) + { + Console.Clear(); + RenderBoard(); + Console.Write($""" + + You turned off all the lights! + Level {level + 1} complete. + + Controls: + - enter: next level + - escape: close game + """); + switch (Console.ReadKey(true).Key) + { + case ConsoleKey.Escape: goto Close; + case ConsoleKey.Enter: + level++; + SetBoard(); + Console.Clear(); + break; + } + } + break; + } +} +Close: +Console.Clear(); +Console.WriteLine("Lights Out was closed."); +Console.CursorVisible = true; + +void SetBoard() +{ + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < Length; j++) + { + board[i][j] = levels[level][i][j]; + } + } +} + +bool LightsOut() +{ + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < Length; j++) + { + if (board[i][j]) + { + return false; + } + } + } + return true; +} + +void RenderBoard() +{ + StringBuilder render = new(); + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < 3; j++) + { + for (int k = 0; k < Length; k++) + { + switch (j) + { + case 0: render.Append((k, i) == cursor ? "╔═╤═╗" : "╭───╮"); break; + case 1: + render.Append((k, i) == cursor ? '╟' : '│'); + render.Append(board[i][k] ? "███" : " "); + render.Append((k, i) == cursor ? '╢' : '│'); + break; + case 2: render.Append((k, i) == cursor ? "╚═╧═╝" : "╰───╯"); break; + } + } + render.AppendLine(); + } + } + Console.SetCursorPosition(0, 0); + Console.Write(render); +} diff --git a/Projects/Lights Out/README.md b/Projects/Lights Out/README.md new file mode 100644 index 00000000..0b31c3ac --- /dev/null +++ b/Projects/Lights Out/README.md @@ -0,0 +1,59 @@ +

+ Lights Out +

+ +

+ GitHub repo + Language C# + Target Framework + Build + Discord + License +

+ +

+ You can play this game in your browser: +
+ + Play Now + +
+ Hosted On GitHub Pages +

+ +Lights Out is a puzzle game in which you try to turn off all the lights. However, when you toggle a light on/off you will also toggle the lights adjacent to it. + +```cs +╭───╮╭───╮╭───╮╭───╮╭───╮ +│ ││ ││ ││ ││ │ +╰───╯╰───╯╰───╯╰───╯╰───╯ +╭───╮╭───╮╭───╮╭───╮╭───╮ +│ ││ ││ ││ ││ │ +╰───╯╰───╯╰───╯╰───╯╰───╯ +╭───╮╭───╮╭───╮╭───╮╭───╮ +│███││ ││███││ ││███│ +╰───╯╰───╯╰───╯╰───╯╰───╯ +╭───╮╔═╤═╗╭───╮╭───╮╭───╮ +│ │╟ ╢│ ││ ││ │ +╰───╯╚═╧═╝╰───╯╰───╯╰───╯ +╭───╮╭───╮╭───╮╭───╮╭───╮ +│ ││ ││ ││ ││ │ +╰───╯╰───╯╰───╯╰───╯╰───╯ + +Turn off all the lights. Level 1. +``` + +## Input + +- `↑`, `↓`, `←`, `→`: move cursor +- `enter`: flip lights & move to next level +- `backspace`: restart level +- `escape`: exit game + +## Downloads + +[win-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/win-x64/Lights%20Out.exe) + +[linux-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/linux-x64/Lights%20Out) + +[osx-x64](https://github.com/dotnet/dotnet-console-games/raw/binaries/osx-x64/Lights%20Out) diff --git a/Projects/Website/Games/Lights Out/Lights Out.cs b/Projects/Website/Games/Lights Out/Lights Out.cs new file mode 100644 index 00000000..55d091fa --- /dev/null +++ b/Projects/Website/Games/Lights Out/Lights Out.cs @@ -0,0 +1,321 @@ +using System; +using System.Text; +using System.Threading.Tasks; + +namespace Website.Games.Lights_Out; + +public class Lights_Out +{ + public readonly BlazorConsole Console = new(); + + public async Task Run() + { + const int Length = 5; + const bool O = true; + const bool X = false; + + bool[][][] levels = + [ + [ // 1 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, O, X, O], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 2 + [O, X, O, X, O], + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + [O, X, O, X, O], + ], + [ // 3 + [X, O, X, O, X], + [O, O, X, O, O], + [O, O, X, O, O], + [O, O, X, O, O], + [X, O, X, O, X], + ], + [ // 4 + [X, X, X, X, X], + [O, O, X, O, O], + [X, X, X, X, X], + [O, X, X, X, O], + [O, O, X, O, O], + ], + [ // 5 + [O, O, O, O, X], + [O, O, O, X, O], + [O, O, O, X, O], + [X, X, X, O, O], + [O, O, X, O, O], + ], + [ // 6 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, O, X, O], + [O, X, O, X, O], + [X, O, O, O, X], + ], + [ // 7 + [O, O, O, O, X], + [O, X, X, X, O], + [O, X, X, X, O], + [O, X, X, X, O], + [O, O, O, O, X], + ], + [ // 8 + [X, X, X, X, X], + [X, X, O, X, X], + [X, O, X, O, X], + [O, X, O, X, O], + [X, O, X, O, X], + ], + [ // 9 + [X, O, X, O, X], + [O, O, O, O, O], + [X, O, O, O, X], + [X, O, X, O, O], + [O, O, O, X, X], + ], + [ // 10 + [X, O, O, O, X], + [X, O, O, O, X], + [X, O, O, O, X], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 11 + [O, X, O, X, O], + [O, X, O, X, O], + [O, X, O, X, O], + [O, X, O, X, O], + [X, O, O, O, X], + ], + [ // 12 + [O, O, O, O, O], + [X, O, X, O, X], + [O, O, X, O, O], + [X, O, O, O, X], + [X, O, X, O, X], + ], + [ // 13 + [X, X, X, O, X], + [X, X, O, X, O], + [X, O, X, O, X], + [O, X, O, X, X], + [X, O, X, X, X], + ], + [ // 14 + [X, X, X, X, X], + [X, X, X, X, X], + [X, O, X, X, X], + [X, O, X, X, X], + [X, O, X, X, X], + ], + [ // 15 + [X, X, X, X, X], + [X, O, X, X, X], + [X, X, X, X, X], + [X, O, X, X, X], + [X, X, X, X, X], + ], + [ // 16 + [O, X, X, X, X], + [O, X, X, X, X], + [O, X, X, X, X], + [O, X, X, X, X], + [O, O, O, O, O], + ], + [ // 17 + [X, X, X, X, X], + [X, X, X, X, X], + [X, X, O, X, X], + [X, O, O, O, X], + [O, O, O, O, O], + ], + [ // 18 + [X, X, O, X, X], + [X, O, X, O, X], + [O, X, O, X, O], + [X, O, X, O, X], + [X, X, O, X, X], + ], + [ // 19 + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + [X, X, X, X, X], + [O, X, O, X, O], + ], + [ // 20 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, X, X, O], + [X, X, X, X, X], + [X, X, X, X, X], + ], + [ // 21 + [X, O, O, O, O], + [X, O, X, X, X], + [X, O, O, O, X], + [X, O, X, X, X], + [X, O, X, X, X], + ], + [ // 22 + [X, O, O, O, X], + [O, X, X, X, O], + [O, X, X, X, O], + [O, X, X, X, O], + [X, O, O, O, X], + ], + [ // 23 + [X, X, X, X, X], + [X, X, X, X, X], + [X, X, O, O, O], + [X, X, O, O, X], + [X, X, O, X, X], + ], + [ // 24 + [X, X, X, X, X], + [X, X, X, X, X], + [O, X, X, X, O], + [O, O, O, O, O], + [X, O, X, X, O], + ], + [ // 25 + [O, X, X, X, X], + [O, O, X, X, X], + [O, O, O, X, X], + [O, O, O, O, X], + [X, O, O, O, O], + ], + ]; + + Console.OutputEncoding = Encoding.UTF8; + int level = 0; + bool[][] board = + [ + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], + [O, O, O, O, O], + ]; + SetBoard(); + (int Left, int Top) cursor = (0, 0); + while (true) + { + await RenderBoard(); + await Console.Write($""" + + Turn off all the lights. Level {level + 1}. + + Controls: + - arrow keys: move cursor + - enter: flip lights + - backspace: reset level + - 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 ? Length - 1 : cursor.Left - 1; break; + case ConsoleKey.RightArrow: cursor.Left = cursor.Left >= Length - 1 ? 0 : cursor.Left + 1; break; + case ConsoleKey.UpArrow: cursor.Top = cursor.Top <= 0 ? Length - 1 : cursor.Top - 1; break; + case ConsoleKey.DownArrow: cursor.Top = cursor.Top >= Length - 1 ? 0 : cursor.Top + 1; break; + case ConsoleKey.Backspace: SetBoard(); break; + case ConsoleKey.Escape: goto Close; + case ConsoleKey.Enter: + board[cursor.Top][cursor.Left] = !board[cursor.Top][cursor.Left]; + if (cursor.Top > 0) board[cursor.Top - 1][cursor.Left] = !board[cursor.Top - 1][cursor.Left]; + if (cursor.Top < Length - 1) board[cursor.Top + 1][cursor.Left] = !board[cursor.Top + 1][cursor.Left]; + if (cursor.Left > 0) board[cursor.Top][cursor.Left - 1] = !board[cursor.Top][cursor.Left - 1]; + if (cursor.Left < Length - 1) board[cursor.Top][cursor.Left + 1] = !board[cursor.Top][cursor.Left + 1]; + if (LightsOut()) + { + await Console.Clear(); + await RenderBoard(); + await Console.Write($""" + + You turned off all the lights! + Level {level + 1} complete. + + Controls: + - enter: next level + - escape: close game + """); + switch ((await Console.ReadKey(true)).Key) + { + case ConsoleKey.Escape: goto Close; + case ConsoleKey.Enter: + level++; + SetBoard(); + await Console.Clear(); + break; + } + } + break; + } + } + Close: + await Console.Clear(); + await Console.WriteLine("Lights Out was closed."); + Console.CursorVisible = true; + + void SetBoard() + { + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < Length; j++) + { + board[i][j] = levels[level][i][j]; + } + } + } + + bool LightsOut() + { + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < Length; j++) + { + if (board[i][j]) + { + return false; + } + } + } + return true; + } + + async Task RenderBoard() + { + StringBuilder render = new(); + for (int i = 0; i < Length; i++) + { + for (int j = 0; j < 3; j++) + { + for (int k = 0; k < Length; k++) + { + switch (j) + { + case 0: render.Append((k, i) == cursor ? "╔═╤═╗" : "╭───╮"); break; + case 1: + render.Append((k, i) == cursor ? '╟' : '│'); + render.Append(board[i][k] ? "███" : " "); + render.Append((k, i) == cursor ? '╢' : '│'); + break; + case 2: render.Append((k, i) == cursor ? "╚═╧═╝" : "╰───╯"); break; + } + } + render.AppendLine(); + } + } + await Console.SetCursorPosition(0, 0); + await Console.Write(render); + } + } +} diff --git a/Projects/Website/Pages/Lights Out.razor b/Projects/Website/Pages/Lights Out.razor new file mode 100644 index 00000000..ed59641e --- /dev/null +++ b/Projects/Website/Pages/Lights Out.razor @@ -0,0 +1,53 @@ +@using System + +@page "/Lights Out" + +Lights Out + +

Lights Out

+ + + Go To Readme + + +
+
+
+		@Console.State
+		
+
+
+ + + + + + + +
+
+ + + + + +@code +{ + Games.Lights_Out.Lights_Out Game; + BlazorConsole Console; + + public Lights_Out() + { + Game = new(); + Console = Game.Console; + Console.WindowWidth = 35; + Console.WindowHeight = 24; + 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 f6fa5c5f..3583f87f 100644 --- a/Projects/Website/Shared/NavMenu.razor +++ b/Projects/Website/Shared/NavMenu.razor @@ -78,6 +78,11 @@ Hangman +