mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-07 02:24:33 -08:00
Move folder for consistency
This commit is contained in:
34
90_Tower/csharp/Tower.sln
Normal file
34
90_Tower/csharp/Tower.sln
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tower", "tower\Tower.csproj", "{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2E14FCD5-A52C-4292-A7F4-0C7E5780C962}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
78
90_Tower/csharp/Tower/Game.cs
Normal file
78
90_Tower/csharp/Tower/Game.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using Tower.Models;
|
||||
using Tower.Resources;
|
||||
using Tower.UI;
|
||||
|
||||
namespace Tower
|
||||
{
|
||||
internal class Game
|
||||
{
|
||||
private readonly Towers _towers;
|
||||
private readonly TowerDisplay _display;
|
||||
private readonly int _optimalMoveCount;
|
||||
private int _moveCount;
|
||||
|
||||
public Game(int diskCount)
|
||||
{
|
||||
_towers = new Towers(diskCount);
|
||||
_display = new TowerDisplay(_towers);
|
||||
_optimalMoveCount = (1 << diskCount) - 1;
|
||||
}
|
||||
|
||||
public bool Play()
|
||||
{
|
||||
Console.Write(Strings.Instructions);
|
||||
|
||||
Console.Write(_display);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!Input.TryReadNumber(Prompt.Disk, out int disk)) { return false; }
|
||||
|
||||
if (!_towers.TryFindDisk(disk, out var from, out var message))
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Input.TryReadNumber(Prompt.Needle, out var to)) { return false; }
|
||||
|
||||
if (!_towers.TryMoveDisk(from, to))
|
||||
{
|
||||
Console.Write(Strings.IllegalMove);
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.Write(_display);
|
||||
|
||||
var result = CheckProgress();
|
||||
if (result.HasValue) { return result.Value; }
|
||||
}
|
||||
}
|
||||
|
||||
private bool? CheckProgress()
|
||||
{
|
||||
_moveCount++;
|
||||
|
||||
if (_moveCount == 128)
|
||||
{
|
||||
Console.Write(Strings.TooManyMoves);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_towers.Finished)
|
||||
{
|
||||
if (_moveCount == _optimalMoveCount)
|
||||
{
|
||||
Console.Write(Strings.Congratulations);
|
||||
}
|
||||
|
||||
Console.WriteLine(Strings.TaskFinished, _moveCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
90_Tower/csharp/Tower/Models/Needle.cs
Normal file
33
90_Tower/csharp/Tower/Models/Needle.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Tower.Models
|
||||
{
|
||||
internal class Needle : IEnumerable<int>
|
||||
{
|
||||
private readonly Stack<int> _disks = new Stack<int>();
|
||||
|
||||
public bool IsEmpty => _disks.Count == 0;
|
||||
|
||||
public int Top => _disks.TryPeek(out var disk) ? disk : default;
|
||||
|
||||
public bool TryPut(int disk)
|
||||
{
|
||||
if (_disks.Count == 0 || disk < _disks.Peek())
|
||||
{
|
||||
_disks.Push(disk);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetTopDisk(out int disk) => _disks.TryPop(out disk);
|
||||
|
||||
public IEnumerator<int> GetEnumerator() =>
|
||||
Enumerable.Repeat(0, 7 - _disks.Count).Concat(_disks).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
87
90_Tower/csharp/Tower/Models/Towers.cs
Normal file
87
90_Tower/csharp/Tower/Models/Towers.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Tower.Resources;
|
||||
|
||||
namespace Tower.Models
|
||||
{
|
||||
internal class Towers : IEnumerable<(int, int, int)>
|
||||
{
|
||||
private static int[] _availableDisks = new[] { 15, 13, 11, 9, 7, 5, 3 };
|
||||
|
||||
private readonly Needle[] _needles = new[] { new Needle(), new Needle(), new Needle() };
|
||||
private readonly int _smallestDisk;
|
||||
|
||||
public Towers(int diskCount)
|
||||
{
|
||||
foreach (int disk in _availableDisks.Take(diskCount))
|
||||
{
|
||||
this[1].TryPut(disk);
|
||||
_smallestDisk = disk;
|
||||
}
|
||||
}
|
||||
|
||||
private Needle this[int i] => _needles[i-1];
|
||||
|
||||
public bool Finished => this[1].IsEmpty && this[2].IsEmpty;
|
||||
|
||||
public bool TryFindDisk(int disk, out int needle, out string message)
|
||||
{
|
||||
needle = default;
|
||||
message = default;
|
||||
|
||||
if (disk < _smallestDisk)
|
||||
{
|
||||
message = Strings.DiskNotInPlay;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (needle = 1; needle <= 3; needle++)
|
||||
{
|
||||
if (this[needle].Top == disk) { return true; }
|
||||
}
|
||||
|
||||
message = Strings.DiskUnavailable;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryMoveDisk(int from, int to)
|
||||
{
|
||||
if (!this[from].TryGetTopDisk(out var disk))
|
||||
{
|
||||
throw new InvalidOperationException($"Needle {from} is empty");
|
||||
}
|
||||
|
||||
if (this[to].TryPut(disk)) { return true; }
|
||||
|
||||
this[from].TryPut(disk);
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<(int, int, int)> GetEnumerator() => new TowersEnumerator(_needles);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private class TowersEnumerator : IEnumerator<(int, int, int)>
|
||||
{
|
||||
private readonly List<IEnumerator<int>> _enumerators;
|
||||
|
||||
public TowersEnumerator(Needle[] needles)
|
||||
{
|
||||
_enumerators = needles.Select(n => n.GetEnumerator()).ToList();
|
||||
}
|
||||
|
||||
public (int, int, int) Current =>
|
||||
(_enumerators[0].Current, _enumerators[1].Current, _enumerators[2].Current);
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose() => _enumerators.ForEach(e => e.Dispose());
|
||||
|
||||
public bool MoveNext() => _enumerators.All(e => e.MoveNext());
|
||||
|
||||
public void Reset() => _enumerators.ForEach(e => e.Reset());
|
||||
}
|
||||
}
|
||||
}
|
||||
27
90_Tower/csharp/Tower/Program.cs
Normal file
27
90_Tower/csharp/Tower/Program.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Tower.Resources;
|
||||
using Tower.UI;
|
||||
|
||||
namespace Tower
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.Write(Strings.Title);
|
||||
|
||||
do
|
||||
{
|
||||
Console.Write(Strings.Intro);
|
||||
|
||||
if (!Input.TryReadNumber(Prompt.DiskCount, out var diskCount)) { return; }
|
||||
|
||||
var game = new Game(diskCount);
|
||||
|
||||
if (!game.Play()) { return; }
|
||||
} while (Input.ReadYesNo(Strings.PlayAgainPrompt, Strings.YesNoPrompt));
|
||||
|
||||
Console.Write(Strings.Thanks);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
90_Tower/csharp/Tower/Resources/Congratulations.txt
Normal file
2
90_Tower/csharp/Tower/Resources/Congratulations.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Congratulations!!
|
||||
1
90_Tower/csharp/Tower/Resources/DiskCountPrompt.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskCountPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
How many disks do you want to move (7 is max)
|
||||
2
90_Tower/csharp/Tower/Resources/DiskCountQuit.txt
Normal file
2
90_Tower/csharp/Tower/Resources/DiskCountQuit.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
All right, wise guy, if you can't play the game right, I'll
|
||||
just take my puzzle and go home. So long.
|
||||
1
90_Tower/csharp/Tower/Resources/DiskCountRetry.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskCountRetry.txt
Normal file
@@ -0,0 +1 @@
|
||||
Sorry, but i can't do that job for you.
|
||||
1
90_Tower/csharp/Tower/Resources/DiskNotInPlay.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskNotInPlay.txt
Normal file
@@ -0,0 +1 @@
|
||||
That disk is not in play. Make another choice.
|
||||
1
90_Tower/csharp/Tower/Resources/DiskPrompt.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
Which disk would you like to move
|
||||
1
90_Tower/csharp/Tower/Resources/DiskQuit.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskQuit.txt
Normal file
@@ -0,0 +1 @@
|
||||
Stop wasting my time. Go bother someone else.
|
||||
1
90_Tower/csharp/Tower/Resources/DiskRetry.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskRetry.txt
Normal file
@@ -0,0 +1 @@
|
||||
Illegal entry... You may only type 3, 5, 7, 9, 11, 13, or 15.
|
||||
1
90_Tower/csharp/Tower/Resources/DiskUnavailable.txt
Normal file
1
90_Tower/csharp/Tower/Resources/DiskUnavailable.txt
Normal file
@@ -0,0 +1 @@
|
||||
That disk is below another one. Make another choice.
|
||||
3
90_Tower/csharp/Tower/Resources/IllegalMove.txt
Normal file
3
90_Tower/csharp/Tower/Resources/IllegalMove.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
You can't place a larger disk on top of a smaller one,
|
||||
it might crush it!
|
||||
Now then,
|
||||
11
90_Tower/csharp/Tower/Resources/Instructions.txt
Normal file
11
90_Tower/csharp/Tower/Resources/Instructions.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
In this program, we shall refer to disks by numerical code.
|
||||
3 will represent the smallest disk, 5 the next size,
|
||||
7 the next, and so on, up to 15. If you do the puzzle with
|
||||
2 disks, their code names would be 13 and 15. With 3 disks
|
||||
the code names would be 11, 13 and 15, etc. The needles
|
||||
are numbered from left to right, 1 to 3. We will
|
||||
startup with the disks on needle 1, and attempt to move them
|
||||
to needle 3.
|
||||
|
||||
Good luck!
|
||||
|
||||
7
90_Tower/csharp/Tower/Resources/Intro.txt
Normal file
7
90_Tower/csharp/Tower/Resources/Intro.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
Towers of Hanoi puzzle.
|
||||
|
||||
You must transfer the disks from the left to the right
|
||||
tower, one at a time, never putting a larger dish on a
|
||||
smaller disk.
|
||||
|
||||
1
90_Tower/csharp/Tower/Resources/NeedlePrompt.txt
Normal file
1
90_Tower/csharp/Tower/Resources/NeedlePrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
Place disk on which needle
|
||||
2
90_Tower/csharp/Tower/Resources/NeedleQuit.txt
Normal file
2
90_Tower/csharp/Tower/Resources/NeedleQuit.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
I tried to warn you, but you wouldn't listen,
|
||||
Bye bye, big shot.
|
||||
2
90_Tower/csharp/Tower/Resources/NeedleRetry.txt
Normal file
2
90_Tower/csharp/Tower/Resources/NeedleRetry.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
I'll assume you hit the wrong key this time. But watch it,
|
||||
I only allow one mistake
|
||||
2
90_Tower/csharp/Tower/Resources/PlayAgainPrompt.txt
Normal file
2
90_Tower/csharp/Tower/Resources/PlayAgainPrompt.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Try again (Yes or No)
|
||||
40
90_Tower/csharp/Tower/Resources/Strings.cs
Normal file
40
90_Tower/csharp/Tower/Resources/Strings.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Tower.Resources
|
||||
{
|
||||
internal static class Strings
|
||||
{
|
||||
internal static string Congratulations => GetResource();
|
||||
internal static string DiskCountPrompt => GetResource();
|
||||
internal static string DiskCountQuit => GetResource();
|
||||
internal static string DiskCountRetry => GetResource();
|
||||
internal static string DiskNotInPlay => GetResource();
|
||||
internal static string DiskPrompt => GetResource();
|
||||
internal static string DiskQuit => GetResource();
|
||||
internal static string DiskRetry => GetResource();
|
||||
internal static string DiskUnavailable => GetResource();
|
||||
internal static string IllegalMove => GetResource();
|
||||
internal static string Instructions => GetResource();
|
||||
internal static string Intro => GetResource();
|
||||
internal static string NeedlePrompt => GetResource();
|
||||
internal static string NeedleQuit => GetResource();
|
||||
internal static string NeedleRetry => GetResource();
|
||||
internal static string PlayAgainPrompt => GetResource();
|
||||
internal static string TaskFinished => GetResource();
|
||||
internal static string Thanks => GetResource();
|
||||
internal static string Title => GetResource();
|
||||
internal static string TooManyMoves => GetResource();
|
||||
internal static string YesNoPrompt => GetResource();
|
||||
|
||||
private static string GetResource([CallerMemberName] string name = "")
|
||||
{
|
||||
var streamName = $"Tower.Resources.{name}.txt";
|
||||
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(streamName);
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
90_Tower/csharp/Tower/Resources/TaskFinished.txt
Normal file
2
90_Tower/csharp/Tower/Resources/TaskFinished.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
You have performed the task in {0} moves.
|
||||
2
90_Tower/csharp/Tower/Resources/Thanks.txt
Normal file
2
90_Tower/csharp/Tower/Resources/Thanks.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Thanks for the game!
|
||||
5
90_Tower/csharp/Tower/Resources/Title.txt
Normal file
5
90_Tower/csharp/Tower/Resources/Title.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Towers
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
2
90_Tower/csharp/Tower/Resources/TooManyMoves.txt
Normal file
2
90_Tower/csharp/Tower/Resources/TooManyMoves.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Sorry, but I have orders to stop if you make more than
|
||||
128 moves.
|
||||
2
90_Tower/csharp/Tower/Resources/YesNoPrompt.txt
Normal file
2
90_Tower/csharp/Tower/Resources/YesNoPrompt.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
'Yes' or 'No' please
|
||||
12
90_Tower/csharp/Tower/Tower.csproj
Normal file
12
90_Tower/csharp/Tower/Tower.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\*.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
85
90_Tower/csharp/Tower/UI/Input.cs
Normal file
85
90_Tower/csharp/Tower/UI/Input.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Tower.UI
|
||||
{
|
||||
// Provides input methods which emulate the BASIC interpreter's keyboard input routines
|
||||
internal static class Input
|
||||
{
|
||||
private static void Prompt(string text = "") => Console.Write($"{text}? ");
|
||||
|
||||
internal static bool ReadYesNo(string prompt, string retryPrompt)
|
||||
{
|
||||
var response = ReadString(prompt);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (response.Equals("No", StringComparison.InvariantCultureIgnoreCase)) { return false; }
|
||||
if (response.Equals("Yes", StringComparison.InvariantCultureIgnoreCase)) { return true; }
|
||||
response = ReadString(retryPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool TryReadNumber(Prompt prompt, out int number)
|
||||
{
|
||||
var message = prompt.Message;
|
||||
|
||||
for (int retryCount = 0; retryCount <= prompt.RetriesAllowed; retryCount++)
|
||||
{
|
||||
if (retryCount > 0) { Console.WriteLine(prompt.RetryMessage); }
|
||||
|
||||
if (prompt.TryValidateResponse(ReadNumber(message), out number)) { return true; }
|
||||
|
||||
if (!prompt.RepeatPrompt) { message = ""; }
|
||||
}
|
||||
|
||||
Console.WriteLine(prompt.QuitMessage);
|
||||
|
||||
number = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static float ReadNumber(string prompt)
|
||||
{
|
||||
Prompt(prompt);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var inputValues = ReadStrings();
|
||||
|
||||
if (TryParseNumber(inputValues[0], out var number))
|
||||
{
|
||||
if (inputValues.Length > 1)
|
||||
{
|
||||
Console.WriteLine("!Extra input ingored");
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadString(string prompt)
|
||||
{
|
||||
Prompt(prompt);
|
||||
|
||||
var inputValues = ReadStrings();
|
||||
if (inputValues.Length > 1)
|
||||
{
|
||||
Console.WriteLine("!Extra input ingored");
|
||||
}
|
||||
return inputValues[0];
|
||||
}
|
||||
|
||||
private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);
|
||||
|
||||
private static bool TryParseNumber(string text, out float number)
|
||||
{
|
||||
if (float.TryParse(text, out number)) { return true; }
|
||||
|
||||
Console.WriteLine("!Number expected - retry input line");
|
||||
number = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
90_Tower/csharp/Tower/UI/Prompt.cs
Normal file
41
90_Tower/csharp/Tower/UI/Prompt.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static Tower.Resources.Strings;
|
||||
|
||||
namespace Tower.UI
|
||||
{
|
||||
internal class Prompt
|
||||
{
|
||||
public static Prompt DiskCount =
|
||||
new(DiskCountPrompt, DiskCountRetry, DiskCountQuit, 1, 2, 3, 4, 5, 6, 7) { RetriesAllowed = 2 };
|
||||
|
||||
public static Prompt Disk =
|
||||
new(DiskPrompt, DiskRetry, DiskQuit, 3, 5, 7, 9, 11, 13, 15) { RepeatPrompt = false };
|
||||
|
||||
public static Prompt Needle = new(NeedlePrompt, NeedleRetry, NeedleQuit, 1, 2, 3);
|
||||
|
||||
private readonly HashSet<int> _validValues;
|
||||
|
||||
private Prompt(string prompt, string retryMessage, string quitMessage, params int[] validValues)
|
||||
{
|
||||
Message = prompt;
|
||||
RetryMessage = retryMessage;
|
||||
QuitMessage = quitMessage;
|
||||
_validValues = validValues.ToHashSet();
|
||||
RetriesAllowed = 1;
|
||||
RepeatPrompt = true;
|
||||
}
|
||||
|
||||
public string Message { get; }
|
||||
public string RetryMessage { get; }
|
||||
public string QuitMessage { get; }
|
||||
public int RetriesAllowed { get; private set; }
|
||||
public bool RepeatPrompt { get; private set; }
|
||||
|
||||
public bool TryValidateResponse(float number, out int integer)
|
||||
{
|
||||
integer = (int)number;
|
||||
return integer == number && _validValues.Contains(integer);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
90_Tower/csharp/Tower/UI/TowerDisplay.cs
Normal file
37
90_Tower/csharp/Tower/UI/TowerDisplay.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Tower.Models;
|
||||
|
||||
namespace Tower.UI
|
||||
{
|
||||
internal class TowerDisplay
|
||||
{
|
||||
private readonly Towers _towers;
|
||||
|
||||
public TowerDisplay(Towers towers)
|
||||
{
|
||||
_towers = towers;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var row in _towers)
|
||||
{
|
||||
AppendTower(row.Item1);
|
||||
AppendTower(row.Item2);
|
||||
AppendTower(row.Item3);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
|
||||
void AppendTower(int size)
|
||||
{
|
||||
var padding = 10 - size / 2;
|
||||
builder.Append(' ', padding).Append('*', Math.Max(1, size)).Append(' ', padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user