Skip to content

Commit

Permalink
domain content only Algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
newtomsoft committed Dec 16, 2021
1 parent ce632f4 commit 43ae5ef
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 106 deletions.
61 changes: 18 additions & 43 deletions TowerOfHanoi.Domain/TowerOfHanoi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,45 @@ namespace TowerOfHanoi.Domain;

public class TowerOfHanoi : IObservable<Stack<int>[]>
{
private const string LevelSeparator = " - ";
private const string PlaceSeparator = " / ";
private static readonly Dictionary<int, char> Places = new() { { 0, 'A' }, { 1, 'B' }, { 2, 'C' } };

private readonly Stack<int>[] _levels = new Stack<int>[3];
private static readonly int[] PlaceIndexes = { 0, 1, 2 };

public Stack<int>[] Levels { get; } = new Stack<int>[3];

private int _moveNumber;

private readonly List<IObserver<Stack<int>[]>> _observers = new();

public TowerOfHanoi(int levelNumber)
{
_levels[0] = new Stack<int>();
for (var currentLevel = levelNumber - 1; currentLevel >= 0; currentLevel--) _levels[0].Push(currentLevel);
_levels[1] = new Stack<int>();
_levels[2] = new Stack<int>();
Levels[0] = new Stack<int>();
for (var currentLevel = 0; currentLevel < levelNumber; currentLevel++) Levels[0].Push(currentLevel);
Levels[1] = new Stack<int>();
Levels[2] = new Stack<int>();
}

public TowerOfHanoi(Stack<int> levelsInA, Stack<int> levelsInB, Stack<int> levelsInC)
public TowerOfHanoi(IEnumerable<int> levelsInA, IEnumerable<int> levelsInB, IEnumerable<int> levelsInC)
{
_moveNumber = 0;
_levels[0] = levelsInA;
_levels[1] = levelsInB;
_levels[2] = levelsInC;
Levels[0] = new Stack<int>(levelsInA);
Levels[1] = new Stack<int>(levelsInB);
Levels[2] = new Stack<int>(levelsInC);
}


public void MoveLevels() => Move(_levels[0].Count, 0, 2);

public void MoveLevels() => Move(Levels[0].Count, 0, 2);


public void Move(int startPlaceIndex, int endPlaceIndex)
{
Console.WriteLine(this);
Move(_levels[0].Count, startPlaceIndex, endPlaceIndex);
Move(Levels[0].Count, startPlaceIndex, endPlaceIndex);
}

public void Move(int levelNumber, int startPlaceIndex, int endPlaceIndex)
{
if (levelNumber == 1)
{
_moveNumber++;
var levelToMove = _levels[startPlaceIndex].Pop();
_levels[endPlaceIndex].Push(levelToMove);
foreach (var observer in _observers) observer.OnNext(_levels);
Levels[endPlaceIndex].Push(Levels[startPlaceIndex].Pop());
foreach (var observer in _observers) observer.OnNext(Levels);
return;
}

Expand All @@ -65,31 +59,12 @@ public void Move(int levelNumber, int startPlaceIndex, int endPlaceIndex)
Move(1, startPlaceIndex, endPlaceIndex);
Move(levelNumber - 1, sidingPlaceIndex, endPlaceIndex);
}

public override string ToString()
{
var levelBuilder = new StringBuilder();
levelBuilder.Append($"Move {_moveNumber} ");
for (var i = 0; i < _levels.Length; i++) levelBuilder.Append(PlaceToString(_levels[i], Places[i]));
var levelString = levelBuilder.ToString();
levelString = PlaceSeparator.Aggregate(levelString, (current, separator) => current.TrimEnd(separator));
return levelString;
}

private static string PlaceToString(Stack<int> levelStack, char placeName)
{
if (levelStack.Count == 0) return string.Empty;
var levelBuilder = new StringBuilder();
levelBuilder.Append($"place {placeName}: ");
foreach (var level in levelStack) levelBuilder.Append(level + LevelSeparator);
levelBuilder.Remove(levelBuilder.Length - LevelSeparator.Length, LevelSeparator.Length);
levelBuilder.Append(PlaceSeparator);
return levelBuilder.ToString();
}

public IDisposable Subscribe(IObserver<Stack<int>[]> observer)
{
if (!_observers.Contains(observer)) _observers.Add(observer);
if (_observers.Contains(observer)) return new Unsubscriber(_observers, observer);
_observers.Add(observer);
observer.OnNext(Levels);
return new Unsubscriber(_observers, observer);
}

Expand Down
144 changes: 84 additions & 60 deletions TowerOfHanoi.Test/TowerOfHanoiMoveShould.cs
Original file line number Diff line number Diff line change
@@ -1,100 +1,124 @@
using Shouldly;
using System.Collections.Generic;
using Xunit;
// ReSharper disable CollectionNeverUpdated.Local

namespace TowerOfHanoi.Test;
public class TowerOfHanoiMoveShould
{
private Stack<int> _stackA = new();
private Stack<int> _stackB = new();
private Stack<int> _stackC = new();

private void FillStacks(IEnumerable<int> levelsA, IEnumerable<int> levelsB, IEnumerable<int> levelsC)
{
_stackA = new Stack<int>(levelsA);
_stackB = new Stack<int>(levelsB);
_stackC = new Stack<int>(levelsC);
}

[Fact]
public void Return1PlaceCWhenMoveOnly1LevelFrom0to2()
public void Return0Place2WhenMoveOnly0LevelFrom0to2()
{
var stackA = new Stack<int>();
stackA.Push(1);
var stackB = new Stack<int>();
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
towerOfHanoi.Move(1,0,2);
towerOfHanoi.ToString().ShouldBe("Move 1 place C: 1");
var levelsA = new List<int> { 0 };
var levelsB = new List<int>();
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] {_stackC, _stackB, _stackA};
var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(1, 0, 2);
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}



[Fact]
public void Return1PlaceBWhenMoveOnly1LevelFrom0to1()
public void Return0Place1WhenMoveOnly0LevelFrom0to1()
{
var stackA = new Stack<int>();
stackA.Push(1);
var stackB = new Stack<int>();
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
var levelsA = new List<int> { 0 };
var levelsB = new List<int>();
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackB, _stackA, _stackC };
var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(1, 0, 1);
towerOfHanoi.ToString().ShouldBe("Move 1 place B: 1");
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}

[Fact]
public void Return1PlaceCWhenMoveOnly1LevelFrom1to2()
public void Return0Place2WhenMoveOnly0LevelFrom1to2()
{
var stackA = new Stack<int>();
var stackB = new Stack<int>();
stackB.Push(1);
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
var levelsA = new List<int>();
var levelsB = new List<int> { 0 };
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackA, _stackC, _stackB };

var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(1, 1, 2);
towerOfHanoi.ToString().ShouldBe("Move 1 place C: 1");
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}

[Fact]
public void Return1PlaceAWhenMoveOnly1LevelFrom1to0()
public void Return0Place0WhenMoveOnly0LevelFrom1to0()
{
var stackA = new Stack<int>();
var stackB = new Stack<int>();
stackB.Push(1);
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
var levelsA = new List<int>();
var levelsB= new List<int> { 0 };
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackB, _stackA, _stackC };

var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(1, 1, 0);
towerOfHanoi.ToString().ShouldBe("Move 1 place A: 1");
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}

[Fact]
public void Return1And2PlaceCWhenMove1And2From0To2()
public void Return0And1Place2WhenMove0And1From0To2()
{
var stackA = new Stack<int>();
stackA.Push(2);
stackA.Push(1);
var stackB = new Stack<int>();
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
towerOfHanoi.ToString().ShouldBe("Move 0 place A: 1 - 2");
towerOfHanoi.Move( 0, 2);
towerOfHanoi.ToString().ShouldBe("Move 3 place C: 1 - 2");
var levelsA = new List<int> { 0, 1 };
var levelsB = new List<int>();
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackC, _stackB, _stackA };

var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(0, 2);
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}

[Fact]
public void Return1And2And3PlaceCWhenMove1And2And3From0To2()
public void Return0And1And2Place2WhenMove0And1And2From0To2()
{
var stackA = new Stack<int>();
stackA.Push(3);
stackA.Push(2);
stackA.Push(1);
var stackB = new Stack<int>();
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
towerOfHanoi.ToString().ShouldBe("Move 0 place A: 1 - 2 - 3");
var levelsA = new List<int> { 0, 1, 2 };
var levelsB = new List<int>();
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackC, _stackB, _stackA };

var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(0, 2);
towerOfHanoi.ToString().ShouldBe("Move 7 place C: 1 - 2 - 3");
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}

[Fact]
public void Return1To4PlaceCWhenMove1To4From0To2()
public void Return0To3Place2WhenMove0To3From0To2()
{
var stackA = new Stack<int>();
stackA.Push(4);
stackA.Push(3);
stackA.Push(2);
stackA.Push(1);
var stackB = new Stack<int>();
var stackC = new Stack<int>();
var towerOfHanoi = new Domain.TowerOfHanoi(stackA, stackB, stackC);
towerOfHanoi.ToString().ShouldBe("Move 0 place A: 1 - 2 - 3 - 4");
var levelsA = new List<int> { 0, 1, 2, 3 };
var levelsB = new List<int>();
var levelsC = new List<int>();

FillStacks(levelsA, levelsB, levelsC);
var stacksExpected = new[] { _stackC, _stackB, _stackA };

var towerOfHanoi = new Domain.TowerOfHanoi(levelsA, levelsB, levelsC);
towerOfHanoi.Move(0, 2);
towerOfHanoi.ToString().ShouldBe("Move 15 place C: 1 - 2 - 3 - 4");
towerOfHanoi.Levels.ShouldBe(stacksExpected);
}
}
1 change: 0 additions & 1 deletion TowerOfHanoi.UI.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
var towerOfHanoi = new TowerOfHanoi.Domain.TowerOfHanoi(6);
var towerOfHanoiLevelsObserver = new TowerOfHanoiObserver();


towerOfHanoiLevelsObserver.Subscribe(towerOfHanoi);
towerOfHanoi.MoveLevels();
towerOfHanoiLevelsObserver.OnCompleted();
3 changes: 1 addition & 2 deletions TowerOfHanoi.UI.Console/TowerOfHanoiObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ public void OnError(Exception error)

public void OnNext(Stack<int>[] value)
{
_moveNumber++;
var levelBuilder = new StringBuilder();
levelBuilder.Append($"Move {_moveNumber} ");
levelBuilder.Append($"Move {_moveNumber++} ");
for (var i = 0; i < value.Length; i++) levelBuilder.Append(PlaceToString(value[i], Places[i]));
var levelString = levelBuilder.ToString();
levelString = PlaceSeparator.Aggregate(levelString, (current, separator) => current.TrimEnd(separator));
Expand Down

0 comments on commit 43ae5ef

Please sign in to comment.