183 lines
6.5 KiB
C#
183 lines
6.5 KiB
C#
using System;
|
||
using su.divan2000.UtilsTUI;
|
||
|
||
namespace su.divan2000.PLandDS_HanoiTowers
|
||
{
|
||
class HanoiTowers
|
||
{
|
||
private int[][] towers;
|
||
private int size;
|
||
|
||
public enum TowerName { A, B, C }
|
||
public int Size { get { return size; } }
|
||
|
||
public HanoiTowers(int size)
|
||
{
|
||
this.size = size;
|
||
towers = new int[3][];
|
||
towers[0] = new int[size];
|
||
towers[1] = new int[size];
|
||
towers[2] = new int[size];
|
||
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
towers[0][i] = size - i;
|
||
}
|
||
}
|
||
|
||
public override string ToString()
|
||
{
|
||
int charsPerTower = size.ToString().Length;
|
||
string result = "";
|
||
for (int i = size - 1; i >= 0; i--)
|
||
{
|
||
result += towers[0][i].ToString().PadLeft(charsPerTower).Replace("0", "|") + " ";
|
||
result += towers[1][i].ToString().PadLeft(charsPerTower).Replace("0", "|") + " ";
|
||
result += towers[2][i].ToString().PadLeft(charsPerTower).Replace("0", "|") + "\n";
|
||
}
|
||
return result;
|
||
}
|
||
|
||
public void move(TowerName from, TowerName to)
|
||
{
|
||
if (from == to) return;
|
||
|
||
int[] sourceTower = towers[(int)from];
|
||
int[] targetTower = towers[(int)to];
|
||
int sourceTopIndex = getTopIndex(sourceTower);
|
||
int targetTopIndex = getTopIndex(targetTower);
|
||
|
||
if (sourceTopIndex < 0)
|
||
throw new InvalidOperationException("Source tower is empty");
|
||
if (targetTopIndex >= size)
|
||
throw new InvalidOperationException("Target tower is full");
|
||
if (targetTopIndex >= 0 && sourceTower[sourceTopIndex] > targetTower[targetTopIndex])
|
||
throw new InvalidOperationException("Cannot place larger disk on smaller one");
|
||
|
||
targetTower[targetTopIndex + 1] = sourceTower[sourceTopIndex];
|
||
sourceTower[sourceTopIndex] = 0;
|
||
}
|
||
|
||
public int getTopIndex(int[] tower)
|
||
{
|
||
for (int i = size-1; i >= 0; i--)
|
||
{
|
||
if (tower[i] != 0)
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
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
|
||
{
|
||
public struct Move
|
||
{
|
||
public HanoiTowers.TowerName From;
|
||
public HanoiTowers.TowerName To;
|
||
|
||
public Move(HanoiTowers.TowerName from, HanoiTowers.TowerName to)
|
||
{
|
||
From = from;
|
||
To = to;
|
||
}
|
||
}
|
||
|
||
public static List<Move> MoveN(HanoiTowers towers, int n, HanoiTowers.TowerName from, HanoiTowers.TowerName to, HanoiTowers.TowerName aux)
|
||
{
|
||
List<Move> moves = new List<Move>();
|
||
if (n == 1)
|
||
{
|
||
moves.Add(new Move(from, to));
|
||
}
|
||
else
|
||
{
|
||
moves.AddRange(MoveN(towers, n - 1, from, aux, to));
|
||
moves.Add(new Move(from, to));
|
||
moves.AddRange(MoveN(towers, n - 1, aux, to, from));
|
||
}
|
||
return moves;
|
||
}
|
||
|
||
public static void ExecuteMove(HanoiTowers towers, Move move)
|
||
{
|
||
towers.move(move.From, move.To);
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
} |