Skip to content

Commit

Permalink
Merge pull request #36 from ZacharyPatten/Tower-Of-Hanoi
Browse files Browse the repository at this point in the history
Tower Of Hanoi
  • Loading branch information
ZacharyPatten authored May 25, 2022
2 parents 85dca57 + 9d34fe5 commit 3202bcd
Show file tree
Hide file tree
Showing 12 changed files with 638 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/Tower Of Hanoi Build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Tower Of Hanoi Build
on:
push:
paths:
- 'Projects/Tower Of Hanoi/**'
pull_request:
paths:
- 'Projects/Tower Of Hanoi/**'
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\Tower Of Hanoi\Tower Of Hanoi.csproj" --configuration Release
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@
"console": "externalTerminal",
"stopAtEntry": false,
},
{
"name": "Tower Of Hanoi",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build Tower Of Hanoi",
"program": "${workspaceFolder}/Projects/Tower Of Hanoi/bin/Debug/Tower Of Hanoi.dll",
"cwd": "${workspaceFolder}/Projects/Tower Of Hanoi/bin/Debug",
"console": "externalTerminal",
"stopAtEntry": false,
},
{
"name": "Hangman",
"type": "coreclr",
Expand Down
13 changes: 13 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
"version": "2.0.0",
"tasks":
[
{
"label": "Build Tower Of Hanoi",
"command": "dotnet",
"type": "process",
"args":
[
"build",
"${workspaceFolder}/Projects/Tower Of Hanoi/Tower Of Hanoi.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
],
"problemMatcher": "$msCompile",
},
{
"label": "Build Battleship",
"command": "dotnet",
Expand Down
228 changes: 228 additions & 0 deletions Projects/Tower Of Hanoi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using System.Globalization;

int disks;
int minimumNumberOfMoves;
List<int>[] stacks;
int moves;
int? source;
State state;

try
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Menu:
Console.CursorVisible = false;
Console.Clear();
Console.WriteLine();
Console.WriteLine(" Tower Of Hanoi");
Console.WriteLine();
Console.WriteLine(" This is a puzzle game where you need to");
Console.WriteLine(" move all the disks in the left stack to");
Console.WriteLine(" the right stack. You can only move one");
Console.WriteLine(" disk at a time from one stack to another");
Console.WriteLine(" stack, and you may never place a disk on");
Console.WriteLine(" top of a smaller disk on the same stack.");
Console.WriteLine();
Console.WriteLine(" [enter] to continue");
Console.Write(" [escape] exit game");
GetEnter:
Console.CursorVisible = false;
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Enter: break;
case ConsoleKey.Escape: return;
default: goto GetEnter;
}
Console.Clear();
Console.WriteLine();
Console.WriteLine(" Tower Of Hanoi");
Console.WriteLine();
Console.WriteLine(" The more disks, the harder the puzzle.");
Console.WriteLine();
Console.WriteLine(" Select the number of disks:");
Console.WriteLine(" [3] 3 disks");
Console.WriteLine(" [4] 4 disks");
Console.WriteLine(" [5] 5 disks");
Console.WriteLine(" [6] 6 disks");
Console.WriteLine(" [7] 7 disks");
Console.WriteLine(" [8] 8 disks");
Console.WriteLine(" [escape] exit game");
GetDiskCount:
Console.CursorVisible = false;
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.D3 or ConsoleKey.NumPad3: disks = 3; break;
case ConsoleKey.D4 or ConsoleKey.NumPad4: disks = 4; break;
case ConsoleKey.D5 or ConsoleKey.NumPad5: disks = 5; break;
case ConsoleKey.D6 or ConsoleKey.NumPad6: disks = 6; break;
case ConsoleKey.D7 or ConsoleKey.NumPad3: disks = 7; break;
case ConsoleKey.D8 or ConsoleKey.NumPad8: disks = 8; break;
case ConsoleKey.Escape: return;
default: goto GetDiskCount;
}
Restart:
state = State.ChooseSource;
minimumNumberOfMoves = (int)Math.Pow(2, disks) - 1;
stacks = new List<int>[] { new(), new(), new() };
for (int i = disks; i > 0; i--)
{
stacks[0].Add(i);
}
moves = 0;
source = null;
Console.Clear();
while (stacks[2].Count != disks)
{
Render();
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Escape: return;
case ConsoleKey.D1 or ConsoleKey.NumPad1: HandleStackButtonPress(0); break;
case ConsoleKey.D2 or ConsoleKey.NumPad2: HandleStackButtonPress(1); break;
case ConsoleKey.D3 or ConsoleKey.NumPad3: HandleStackButtonPress(2); break;
case ConsoleKey.End: goto Menu;
case ConsoleKey.Home: goto Restart;
}
}
state = State.Win;
Render();
GetEnterOrEscape:
Console.CursorVisible = false;
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Enter: goto Menu;
case ConsoleKey.Escape: return;
default: goto GetEnterOrEscape;
}
}
finally
{
Console.CursorVisible = true;
Console.ResetColor();
Console.Clear();
Console.Write("Tower Of Hanoi was closed.");
}

void HandleStackButtonPress(int stack)
{
if (source is null && stacks[stack].Count > 0)
{
source = stack;
state = State.ChooseTarget;
}
else if (source is not null &&
(stacks[stack].Count is 0 || stacks[source.Value][^1] < stacks[stack][^1]))
{
stacks[stack].Add(stacks[source.Value][^1]);
stacks[source.Value].RemoveAt(stacks[source.Value].Count - 1);
source = null;
moves++;
state = State.ChooseSource;
}
else if (source == stack)
{
source = null;
state = State.ChooseSource;
}
else if (stacks[stack].Count is not 0)
{
state = State.InvalidTarget;
}
}

void Render()
{
Console.CursorVisible = false;
Console.Clear();
Console.WriteLine();
Console.WriteLine(" Tower Of Hanoi");
Console.WriteLine();
Console.WriteLine($" Minimum Moves: {minimumNumberOfMoves}");
Console.WriteLine();
Console.WriteLine($" Moves: {moves}");
Console.WriteLine();
for (int i = disks - 1; i >= 0; i--)
{
for (int j = 0; j < stacks.Length; j++)
{
Console.Write(" ");
RenderDisk(stacks[j].Count > i ? stacks[j][i] : null);
}
Console.WriteLine();
}
string towerBase = new string('─', disks) + '┴' + new string('─', disks);
Console.WriteLine($" {towerBase} {towerBase} {towerBase}");
Console.WriteLine($" {RenderBelowBase(0)} {RenderBelowBase(1)} {RenderBelowBase(2)}");
Console.WriteLine();
switch (state)
{
case State.ChooseSource:
Console.WriteLine(" [1], [2], or [3] select source stack");
Console.WriteLine(" [home] restart current puzzle");
Console.WriteLine(" [end] back to menu");
Console.Write(" [escape] exit game");
break;
case State.InvalidTarget:
Console.WriteLine(" You may not place a disk on top of a");
Console.WriteLine(" smaller disk on the same stack.");
Console.WriteLine();
goto ChooseTarget;
case State.ChooseTarget:
ChooseTarget:
Console.WriteLine(" [1], [2], or [3] select target stack");
Console.WriteLine(" [home] restart current puzzle");
Console.WriteLine(" [end] back to menu");
Console.Write(" [escape] exit game");
break;
case State.Win:
Console.WriteLine(" You solved the puzzle!");
Console.WriteLine(" [enter] return to menu");
Console.Write(" [escape] exit game");
break;
}
}

string RenderBelowBase(int stack) =>
stack == source
? new string('^', disks - 1) + $"[{(stack + 1).ToString(CultureInfo.InvariantCulture)}]" + new string('^', disks - 1)
: new string(' ', disks - 1) + $"[{(stack + 1).ToString(CultureInfo.InvariantCulture)}]" + new string(' ', disks - 1);

void RenderDisk(int? disk)
{
if (disk is null)
{
Console.Write(new string(' ', disks) + '│' + new string(' ', disks));
}
else
{
Console.Write(new string(' ', disks - disk.Value));
Console.BackgroundColor = disk switch
{
1 => ConsoleColor.Red,
2 => ConsoleColor.Green,
3 => ConsoleColor.Blue,
4 => ConsoleColor.Magenta,
5 => ConsoleColor.Cyan,
6 => ConsoleColor.DarkYellow,
7 => ConsoleColor.White,
8 => ConsoleColor.DarkGray,
_ => throw new NotImplementedException()
};
Console.Write(new string(' ', disk.Value));
Console.Write('│');
Console.Write(new string(' ', disk.Value));
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(new string(' ', disks - disk.Value));
}
}

enum State
{
ChooseSource,
ChooseTarget,
InvalidTarget,
Win,
}
48 changes: 48 additions & 0 deletions Projects/Tower Of Hanoi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<h1 align="center">
Tower Of Hanoi
</h1>

<p align="center">
<a href="https://github.com/ZacharyPatten/dotnet-console-games" alt="GitHub repo"><img alt="flat" src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/github-repo-black.svg"></a>
<a href="https://docs.microsoft.com/en-us/dotnet/csharp/" alt="GitHub repo"><img alt="Language C#" src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/language-csharp.svg"></a>
<a href="https://dotnet.microsoft.com/download"><img src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/dotnet-badge.svg" title="Target Framework" alt="Target Framework"></a>
<a href="https://github.com/ZacharyPatten/dotnet-console-games/actions"><img src="https://github.com/ZacharyPatten/dotnet-console-games/workflows/Tower%20Of%20Hanoi%20Build/badge.svg" title="Goto Build" alt="Build"></a>
<a href="https://discord.gg/4XbQbwF" alt="Discord"><img src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/discord-badge.svg" title="Go To Discord Server" alt="Discord"/></a>
<a href="https://github.com/ZacharyPatten/dotnet-console-games/blob/master/LICENSE" alt="license"><img src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/license-MIT-green.svg" /></a>
</p>

**[Source Code](Program.cs)**

Tower Of Hanoi is a puzzle game where you need to move all the disks in the left stack to the right stack. You can only move one disk at a time from one stack to another stack, and you may never place a disk on top of a smaller disk on the same stack.

```
Tower Of Hanoi
Minimum Moves: 15
Moves: 5
│ │ │
│ │ │
│ ███ │
█████████ █████ ███████
────┴──── ────┴──── ────┴────
^^^[1]^^^ [2] [3]
```

## Input

- `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8` choose number of disks
- `1`, `2`, `3` select source and target stacks
- `enter` confirm prompts
- `escape` exit game

<p align="center">
You can play this game in your browser:
<br />
<a href="https://zacharypatten.github.io/dotnet-console-games/Tower%20Of%20Hanoi" alt="Play Now">
<sub><img height="40"src="https://raw.githubusercontent.com/ZacharyPatten/dotnet-console-games/main/.github/resources/play-badge.svg" title="Play Now" alt="Play Now"/></sub>
</a>
<br />
<sup>Hosted On GitHub Pages</sup>
</p>
9 changes: 9 additions & 0 deletions Projects/Tower Of Hanoi/Tower Of Hanoi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Tower_Of_Hanoi</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions Projects/Website/BlazorConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public void OnKeyDown(KeyboardEventArgs e)
{
switch (e.Key)
{
case "Home": EnqueueInput(ConsoleKey.Home); break;
case "End": EnqueueInput(ConsoleKey.End); break;
case "Backspace": EnqueueInput(ConsoleKey.Backspace); break;
case " ": EnqueueInput(ConsoleKey.Spacebar); break;
Expand Down
Loading

0 comments on commit 3202bcd

Please sign in to comment.