Добавленно TUI

This commit is contained in:
2026-03-05 23:00:24 +04:00
parent 3d57b2a574
commit 479014a03b
4 changed files with 233 additions and 13 deletions

View File

@@ -1,3 +1,6 @@
using System;
using su.divan2000.UtilsTUI;
namespace su.divan2000.PLandDS_HanoiTowers namespace su.divan2000.PLandDS_HanoiTowers
{ {
class HanoiTowers class HanoiTowers
@@ -48,7 +51,7 @@ namespace su.divan2000.PLandDS_HanoiTowers
throw new InvalidOperationException("Source tower is empty"); throw new InvalidOperationException("Source tower is empty");
if (targetTopIndex >= size) if (targetTopIndex >= size)
throw new InvalidOperationException("Target tower is full"); throw new InvalidOperationException("Target tower is full");
if (targetTopIndex > 0 && sourceTower[sourceTopIndex] > targetTower[targetTopIndex]) if (targetTopIndex >= 0 && sourceTower[sourceTopIndex] > targetTower[targetTopIndex])
throw new InvalidOperationException("Cannot place larger disk on smaller one"); throw new InvalidOperationException("Cannot place larger disk on smaller one");
targetTower[targetTopIndex + 1] = sourceTower[sourceTopIndex]; targetTower[targetTopIndex + 1] = sourceTower[sourceTopIndex];
@@ -66,6 +69,21 @@ namespace su.divan2000.PLandDS_HanoiTowers
} }
return -1; // Tower is empty return -1; // Tower is empty
} }
public bool isSolved()
{
return towers[0].All(disk => disk == 0) && towers[1].All(disk => disk == 0) && towers[2].All(disk => disk != 0);
}
public void reset()
{
for (int i = 0; i < size; i++)
{
towers[0][i] = size - i;
towers[1][i] = 0;
towers[2][i] = 0;
}
}
} }
static class HanoiUtils static class HanoiUtils
@@ -98,16 +116,68 @@ namespace su.divan2000.PLandDS_HanoiTowers
return moves; return moves;
} }
public static void ExecuteMoves(HanoiTowers towers, List<Move> moves) public static void ExecuteMove(HanoiTowers towers, Move move)
{
foreach (Move move in moves)
{ {
towers.move(move.From, move.To); towers.move(move.From, move.To);
Console.Clear();
Console.WriteLine($"Move from {move.From} to {move.To}");
Console.WriteLine(towers);
System.Threading.Thread.Sleep(1000);
} }
public static int RunTUI()
{
bool running;
int n = InputHelper.AskInt("Введите количество дисков в ханойской башне: ");
HanoiTowers towers = new HanoiTowers(n);
HanoiTowers.TowerName selectedTower = HanoiTowers.TowerName.A;
Menu manualInput = new Menu("Выберите башню:\n"+towers);
manualInput.AddOption("Башня A", () => selectedTower = HanoiTowers.TowerName.A);
manualInput.AddOption("Башня B", () => selectedTower = HanoiTowers.TowerName.B);
manualInput.AddOption("Башня C", () => selectedTower = HanoiTowers.TowerName.C);
Menu menu = new Menu("Выберите действие:\n"+towers);
menu.AddOption("Сделать ход вручную", () =>
{
manualInput.SetTitle("Выберите башню, с которой хотите переместить диск:\n" + towers);
manualInput.RunMenu();
HanoiTowers.TowerName from = selectedTower;
manualInput.SetTitle("Перемещение с башни " + from + "\nВыберите башню, на которую хотите переместить диск:\n" + towers);
manualInput.RunMenu();
HanoiTowers.TowerName to = selectedTower;
try
{
towers.move(from, to);
} catch (InvalidOperationException ex)
{
Console.WriteLine("Невозможно переместить диск: " + ex.Message);
}
});
menu.AddOption("Сбросить башню", () =>
{
towers.reset();
});
menu.AddOption("Решить башню автоматически", () =>
{
List<Move> moves = MoveN(towers, towers.Size, HanoiTowers.TowerName.A, HanoiTowers.TowerName.C, HanoiTowers.TowerName.B);
towers.reset();
foreach (Move move in moves) {
ExecuteMove(towers, move);
Console.Clear();
Console.WriteLine("Решение башни:\n" + towers);
System.Threading.Thread.Sleep(500); // Пауза для визуализации
}
});
menu.AddOption("Выход", () =>
{
running = false;
});
for (running = true; running;)
{
menu.SetTitle("Выберите действие:\n" + towers);
menu.RunMenu();
running = !towers.isSolved();
}
return 0;
} }
} }
} }

View File

@@ -6,11 +6,7 @@ namespace su.divan2000.PLandDS_HanoiTowers
{ {
static void Main() static void Main()
{ {
HanoiTowers towers = new HanoiTowers(8); HanoiUtils.RunTUI();
Console.WriteLine(towers);
List<HanoiUtils.Move> moves = HanoiUtils.MoveN(towers, towers.Size, HanoiTowers.TowerName.A, HanoiTowers.TowerName.C, HanoiTowers.TowerName.B);
HanoiUtils.ExecuteMoves(towers, moves);
Environment.Exit(0); Environment.Exit(0);
} }

45
TUI/InputHelper.cs Normal file
View File

@@ -0,0 +1,45 @@
using System;
namespace su.divan2000.UtilsTUI
{
public static class InputHelper
{
public static double AskDouble(string prompt)
{
double val;
while (true)
{
Console.Write(prompt);
if (double.TryParse(Console.ReadLine(), out val))
return val;
Console.WriteLine("Некорректный ввод. Введите число в формате 1.0, 2.5 и т.д.");
}
}
public static int AskInt(string prompt)
{
int val;
while (true)
{
Console.Write(prompt);
if (int.TryParse(Console.ReadLine(), out val))
return val;
Console.WriteLine("Некорректный ввод. Введите целое число.");
}
}
public static bool AskYesNo(string prompt)
{
while (true)
{
Console.Write(prompt);
string? s = Console.ReadLine()?.Trim().ToLower();
if (s == "да") return true;
if (s == "нет") return false;
Console.WriteLine("Введите 'да' или 'нет'.");
}
}
}
}

109
TUI/Menu.cs Normal file
View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace su.divan2000.UtilsTUI
{
/// <summary>
/// TUI menu;
/// </summary>
internal class Menu
{
private List<Option> options;
private int selected;
private string title;
/// <summary>
/// Constructor of menu;
/// </summary>
/// <param name="title">Title of menu</param>
public Menu(string title)
{
this.title = title;
this.options = new List<Option> { };
}
/// <summary>
/// Add option to menu;
/// </summary>
/// <param name="name">Name of option</param>
/// <param name="action">Action, runs if option selected</param>
public void AddOption(string name, Action action)
{
this.options.Add(new Option(name, action));
}
/// <summary>
/// Set title of menu;
/// </summary>
/// <param name="title">New title of menu</param>
public void SetTitle(string title)
{
this.title = title;
}
/// <summary>
/// Run menu;
/// Console will be clean!;
/// </summary>
public void RunMenu()
{
selected = 0;
this.PrintMenu();
ConsoleKeyInfo keyinfo;
do
{
keyinfo = Console.ReadKey();
if (keyinfo.Key == ConsoleKey.DownArrow)
{
if (selected + 1 < options.Count)
{
selected++;
this.PrintMenu();
}
}
if (keyinfo.Key == ConsoleKey.UpArrow)
{
if (selected > 0)
{
selected--;
this.PrintMenu();
}
}
if (keyinfo.Key == ConsoleKey.Enter)
{
Console.Clear();
options[selected].Action.Invoke();
}
} while (keyinfo.Key != ConsoleKey.Enter);
}
private void PrintMenu()
{
Console.Clear();
Console.WriteLine(title);
int optionIndex = 0;
foreach (Option option in options)
{
string pointer = optionIndex == selected ? " ->" : " ";
Console.WriteLine($"{pointer}{option.Name}");
optionIndex++;
}
}
private struct Option
{
public string Name { get; }
public Action Action { get; }
public Option(string name, Action action)
{
Name = name;
Action = action;
}
}
}
}