diff --git a/.github/workflows/Tug Of War Build.yml b/.github/workflows/Tug Of War Build.yml
new file mode 100644
index 00000000..fe07408b
--- /dev/null
+++ b/.github/workflows/Tug Of War Build.yml
@@ -0,0 +1,20 @@
+name: Tug Of War Build
+on:
+ push:
+ paths:
+ - 'Projects/Tug Of War/**'
+ pull_request:
+ paths:
+ - 'Projects/Tug Of War/**'
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: setup dotnet
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 6.0.x
+ - name: dotnet build
+ run: dotnet build "Projects\Tug Of War\Tug Of War.csproj" --configuration Release
diff --git a/.vscode/launch.json b/.vscode/launch.json
index b85fd081..94148a11 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -42,6 +42,16 @@
"console": "externalTerminal",
"stopAtEntry": false,
},
+ {
+ "name": "Tug Of War",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "Build Tug Of War",
+ "program": "${workspaceFolder}/Projects/Tug Of War/bin/Debug/Tug Of War.dll",
+ "cwd": "${workspaceFolder}/Projects/Tug Of War/bin/Debug",
+ "console": "externalTerminal",
+ "stopAtEntry": false,
+ },
{
"name": "Whack A Mole",
"type": "coreclr",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 70032690..28ebbefb 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,6 +2,19 @@
"version": "2.0.0",
"tasks":
[
+ {
+ "label": "Build Tug Of War",
+ "command": "dotnet",
+ "type": "process",
+ "args":
+ [
+ "build",
+ "${workspaceFolder}/Projects/Tug Of War/Tug Of War.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary",
+ ],
+ "problemMatcher": "$msCompile",
+ },
{
"label": "Build Tower Of Hanoi",
"command": "dotnet",
diff --git a/Projects/Tug Of War/Program.cs b/Projects/Tug Of War/Program.cs
new file mode 100644
index 00000000..c0a1fbe0
--- /dev/null
+++ b/Projects/Tug Of War/Program.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Threading;
+
+try
+{
+ while (true)
+ {
+ int position = 0;
+ const int displacement = 10;
+ string L() => new(' ', displacement + position + 4);
+ string R() => new(' ', displacement - position + 4);
+ string Ground =
+ new string(' ', 2) +
+ new string('-', displacement + (15 - displacement) + 2) +
+ new string('=', displacement * 2 + 2) +
+ new string('-', displacement + (15 - displacement) + 2) +
+ new string(' ', 2);
+ bool frame_a = false;
+ Console.Clear();
+ Console.WriteLine(@"
+ Tug Of War
+
+ Out pull your opponent in a rope pulling
+ competition. Mash the [left]+[right] arrow
+ keys and/or the [A]+[D] keys to pull on the
+ rope. First player to pull the center of the
+ rope into their boundary wins.
+
+ Choose Your Opponent:
+ [1] Easy.......2 mashes per second
+ [2] Medium.....4 mashes per second
+ [3] Hard.......8 mashes per second
+ [4] Harder....16 mashes per second
+ [escape] give up");
+ int? requiredMash = null;
+ while (requiredMash is null)
+ {
+ Console.CursorVisible = false;
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.D1 or ConsoleKey.NumPad1: requiredMash = 02; break;
+ case ConsoleKey.D2 or ConsoleKey.NumPad2: requiredMash = 04; break;
+ case ConsoleKey.D3 or ConsoleKey.NumPad3: requiredMash = 08; break;
+ case ConsoleKey.D4 or ConsoleKey.NumPad4: requiredMash = 16; break;
+ case ConsoleKey.Escape: return;
+ }
+ }
+ Console.Clear();
+ int mash = 0;
+ int presses = 0;
+ int sleeps = 0;
+ ConsoleKey lastKey = default;
+ DateTime start = DateTime.Now;
+ while (true)
+ {
+ while (Console.KeyAvailable)
+ {
+ ConsoleKey key = Console.ReadKey(true).Key;
+ if (key is ConsoleKey.Escape)
+ {
+ return;
+ }
+ else if (lastKey is not default(ConsoleKey) &&
+ key is ConsoleKey.A or ConsoleKey.D or ConsoleKey.LeftArrow or ConsoleKey.RightArrow &&
+ key != lastKey)
+ {
+ presses++;
+ mash++;
+ lastKey = default;
+ }
+ else if (key is ConsoleKey.A or ConsoleKey.D or ConsoleKey.LeftArrow or ConsoleKey.RightArrow)
+ {
+ lastKey = key;
+ }
+ }
+ if (sleeps is 2)
+ {
+ position = mash < requiredMash.Value
+ ? position + 1
+ : position - 1;
+ sleeps = 0;
+ mash = 0;
+ if (Math.Abs(position) >= displacement)
+ {
+ break;
+ }
+ }
+ Console.CursorVisible = false;
+ Console.SetCursorPosition(0, 0);
+ Console.WriteLine();
+ Console.WriteLine(" Tug Of War");
+ Console.WriteLine();
+ Console.Write(frame_a
+ ?
+ $@"{L()}o o {R()}{"\n"}" +
+ $@"{L()}LL-------------+-------------JJ\{R()}{"\n"}" +
+ $@"{L()}\\ //{R()}{"\n"}" +
+ $@"{L()}| \ / |{R()}{"\n"}"
+ :
+ $@"{L()} o o{R()}{"\n"}" +
+ $@"{L()}/LL-------------+-------------JJ{R()}{"\n"}" +
+ $@"{L()}\\ //{R()}{"\n"}" +
+ $@"{L()}| \ / |{R()}{"\n"}");
+ Console.WriteLine(Ground);
+ Console.WriteLine();
+ Console.WriteLine(frame_a
+ ? " *** Mash [A]+[D] or [Left]+[Right] ***"
+ : " ''' Mash [A]+[D] or [Left]+[Right] '''");
+ Thread.Sleep(500);
+ sleeps++;
+ frame_a = !frame_a;
+ }
+ bool win = position < 0;
+ double seconds = (DateTime.Now - start).TotalSeconds;
+ double average = presses / seconds;
+ Console.Clear();
+ Console.WriteLine();
+ Console.WriteLine(" Tug Of War");
+ Console.WriteLine();
+ Console.Write(win
+ ?
+ $@"{L()}o {R()}{"\n"}" +
+ $@"{L()}LL------------+------. o___ {R()}{"\n"}" +
+ $@"{L()}\\ \// \\__{R()}{"\n"}" +
+ $@"{L()}| \ \_____\ {R()}{"\n"}"
+ :
+ $@"{L()} o{R()}{"\n"}" +
+ $@"{L()} ___o .------+------------JJ{R()}{"\n"}" +
+ $@"{L()}__// \\/ //{R()}{"\n"}" +
+ $@"{L()} /_____/ / |{R()}{"\n"}");
+ Console.WriteLine(Ground);
+ Console.WriteLine();
+ Console.WriteLine(" You " + (win ? "Win!" : "Lose!"));
+ Console.WriteLine($" Average: {average:0.##} mashes per second");
+ Console.WriteLine(" [enter] return to menu");
+ Console.WriteLine(" [escape] exit game");
+ bool enterPressed = false;
+ while (!enterPressed)
+ {
+ switch (Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.Enter: enterPressed = true; break;
+ case ConsoleKey.Escape: return;
+ }
+ }
+ }
+}
+finally
+{
+ Console.CursorVisible = true;
+ Console.Clear();
+ Console.Write("Tug Of War was closed.");
+}
\ No newline at end of file
diff --git a/Projects/Tug Of War/README.md b/Projects/Tug Of War/README.md
new file mode 100644
index 00000000..06ff3f4a
--- /dev/null
+++ b/Projects/Tug Of War/README.md
@@ -0,0 +1,45 @@
+
+ Tug Of War
+
+
+
+
+
+
+
+
+
+
+
+**[Source Code](Program.cs)**
+
+Tug Of War is a rope pulling competition. The first person to pull the center of the rope into their territory wins. To pull, mash the keys `A`+`D` or `←`+`→` as fast as you can.
+
+```
+ Tug Of War
+
+ o o
+ LL-------------+-------------JJ\
+ \\ //
+ | \ / |
+ -----------------======================-----------------
+
+ *** Mash [A]+[D] or [Left]+[Right] ***
+```
+
+## Input
+
+- `A`, `D`, `←`, `→`: pull rope (mash)
+- `1`, `2`, `3`, `4`: choose opponent
+- `enter` confirm
+- `escape` exit game
+
+
+ You can play this game in your browser:
+
+
+
+
+
+ Hosted On GitHub Pages
+
diff --git a/Projects/Tug Of War/Tug Of War.csproj b/Projects/Tug Of War/Tug Of War.csproj
new file mode 100644
index 00000000..49125494
--- /dev/null
+++ b/Projects/Tug Of War/Tug Of War.csproj
@@ -0,0 +1,9 @@
+
+
+ Exe
+ net6.0
+ Tug_Of_War
+ disable
+ enable
+
+
diff --git a/Projects/Website/Games/Tug Of War/Tug Of War.cs b/Projects/Website/Games/Tug Of War/Tug Of War.cs
new file mode 100644
index 00000000..d215b625
--- /dev/null
+++ b/Projects/Website/Games/Tug Of War/Tug Of War.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Website.Games.Tug_Of_War;
+
+public class Tug_Of_War
+{
+ public readonly BlazorConsole Console = new();
+
+ public async Task Run()
+ {
+ try
+ {
+ while (true)
+ {
+ int position = 0;
+ const int displacement = 10;
+ string L() => new(' ', displacement + position + 4);
+ string R() => new(' ', displacement - position + 4);
+ string Ground =
+ new string(' ', 2) +
+ new string('-', displacement + (15 - displacement) + 2) +
+ new string('=', displacement * 2 + 2) +
+ new string('-', displacement + (15 - displacement) + 2) +
+ new string(' ', 2);
+ bool frame_a = false;
+ await Console.Clear();
+ await Console.WriteLine(@"
+ Tug Of War
+
+ Out pull your opponent in a rope pulling
+ competition. Mash the [left]+[right] arrow
+ keys and/or the [A]+[D] keys to pull on the
+ rope. First player to pull the center of the
+ rope into their boundary wins.
+
+ Choose Your Opponent:
+ [1] Easy.......2 mashes per second
+ [2] Medium.....4 mashes per second
+ [3] Hard.......8 mashes per second
+ [4] Harder....16 mashes per second
+ [escape] give up");
+ int? requiredMash = null;
+ while (requiredMash is null)
+ {
+ Console.CursorVisible = false;
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.D1 or ConsoleKey.NumPad1: requiredMash = 02; break;
+ case ConsoleKey.D2 or ConsoleKey.NumPad2: requiredMash = 04; break;
+ case ConsoleKey.D3 or ConsoleKey.NumPad3: requiredMash = 08; break;
+ case ConsoleKey.D4 or ConsoleKey.NumPad4: requiredMash = 16; break;
+ case ConsoleKey.Escape: return;
+ }
+ }
+ await Console.Clear();
+ int mash = 0;
+ int presses = 0;
+ int sleeps = 0;
+ ConsoleKey lastKey = default;
+ DateTime start = DateTime.Now;
+ while (true)
+ {
+ while (await Console.KeyAvailable())
+ {
+ ConsoleKey key = (await Console.ReadKey(true)).Key;
+ if (key is ConsoleKey.Escape)
+ {
+ return;
+ }
+ else if (lastKey is not default(ConsoleKey) &&
+ key is ConsoleKey.A or ConsoleKey.D or ConsoleKey.LeftArrow or ConsoleKey.RightArrow &&
+ key != lastKey)
+ {
+ presses++;
+ mash++;
+ lastKey = default;
+ }
+ else if (key is ConsoleKey.A or ConsoleKey.D or ConsoleKey.LeftArrow or ConsoleKey.RightArrow)
+ {
+ lastKey = key;
+ }
+ }
+ if (sleeps is 2)
+ {
+ position = mash < requiredMash.Value
+ ? position + 1
+ : position - 1;
+ sleeps = 0;
+ mash = 0;
+ if (Math.Abs(position) >= displacement)
+ {
+ break;
+ }
+ }
+ Console.CursorVisible = false;
+ await Console.SetCursorPosition(0, 0);
+ await Console.WriteLine();
+ await Console.WriteLine(" Tug Of War");
+ await Console.WriteLine();
+ await Console.Write(frame_a
+ ?
+ $@"{L()}o o {R()}{"\n"}" +
+ $@"{L()}LL-------------+-------------JJ\{R()}{"\n"}" +
+ $@"{L()}\\ //{R()}{"\n"}" +
+ $@"{L()}| \ / |{R()}{"\n"}"
+ :
+ $@"{L()} o o{R()}{"\n"}" +
+ $@"{L()}/LL-------------+-------------JJ{R()}{"\n"}" +
+ $@"{L()}\\ //{R()}{"\n"}" +
+ $@"{L()}| \ / |{R()}{"\n"}");
+ await Console.WriteLine(Ground);
+ await Console.WriteLine();
+ await Console.WriteLine(frame_a
+ ? " *** Mash [A]+[D] or [Left]+[Right] ***"
+ : " ''' Mash [A]+[D] or [Left]+[Right] '''");
+ await Console.RefreshAndDelay(TimeSpan.FromMilliseconds(500));
+ sleeps++;
+ frame_a = !frame_a;
+ }
+ bool win = position < 0;
+ double seconds = (DateTime.Now - start).TotalSeconds;
+ double average = presses / seconds;
+ await Console.Clear();
+ await Console.WriteLine();
+ await Console.WriteLine(" Tug Of War");
+ await Console.WriteLine();
+ await Console.Write(win
+ ?
+ $@"{L()}o {R()}{"\n"}" +
+ $@"{L()}LL------------+------. o___ {R()}{"\n"}" +
+ $@"{L()}\\ \// \\__{R()}{"\n"}" +
+ $@"{L()}| \ \_____\ {R()}{"\n"}"
+ :
+ $@"{L()} o{R()}{"\n"}" +
+ $@"{L()} ___o .------+------------JJ{R()}{"\n"}" +
+ $@"{L()}__// \\/ //{R()}{"\n"}" +
+ $@"{L()} /_____/ / |{R()}{"\n"}");
+ await Console.WriteLine(Ground);
+ await Console.WriteLine();
+ await Console.WriteLine(" You " + (win ? "Win!" : "Lose!"));
+ await Console.WriteLine($" Average: {average:0.##} mashes per second");
+ await Console.WriteLine(" [enter] return to menu");
+ await Console.WriteLine(" [escape] exit game");
+ bool enterPressed = false;
+ while (!enterPressed)
+ {
+ switch ((await Console.ReadKey(true)).Key)
+ {
+ case ConsoleKey.Enter: enterPressed = true; break;
+ case ConsoleKey.Escape: return;
+ }
+ }
+ }
+ }
+ finally
+ {
+ Console.CursorVisible = true;
+ await Console.Clear();
+ await Console.Write("Tug Of War was closed.");
+ await Console.Refresh();
+ }
+ }
+}
diff --git a/Projects/Website/Pages/Tug Of War.razor b/Projects/Website/Pages/Tug Of War.razor
new file mode 100644
index 00000000..537f201d
--- /dev/null
+++ b/Projects/Website/Pages/Tug Of War.razor
@@ -0,0 +1,56 @@
+@using System
+
+@page "/Tug Of War"
+
+Tug Of War
+
+