From 1775929ced31587c5b21ba4ce7e8fa23eeb6238c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 31 May 2023 09:24:32 +0200 Subject: [PATCH] Implement strategy pattern --- Nodes/BfsNode.cs | 6 ----- Nodes/DfsNode.cs | 4 --- Nodes/{BaseMazeNode.cs => MazeNode.cs} | 5 ++-- Program.cs | 33 ++++++++++++++++++++++--- Solvers/BreadthFirstSearchMazeSolver.cs | 16 ++++++------ Solvers/DepthFirstSearchMazeSolver.cs | 16 ++++++------ Solvers/IMazeSolver.cs | 4 +-- Utlis/MazeParser.cs | 12 ++++----- Utlis/MazePrinter.cs | 8 +++--- Utlis/PathFinder.cs | 19 ++++++++++++++ 10 files changed, 80 insertions(+), 43 deletions(-) delete mode 100644 Nodes/BfsNode.cs delete mode 100644 Nodes/DfsNode.cs rename Nodes/{BaseMazeNode.cs => MazeNode.cs} (61%) create mode 100644 Utlis/PathFinder.cs diff --git a/Nodes/BfsNode.cs b/Nodes/BfsNode.cs deleted file mode 100644 index 99b25be..0000000 --- a/Nodes/BfsNode.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Maze.Nodes; - -internal class BfsNode : BaseMazeNode -{ - public BfsNode? Parent { get; set; } -} \ No newline at end of file diff --git a/Nodes/DfsNode.cs b/Nodes/DfsNode.cs deleted file mode 100644 index 8017b15..0000000 --- a/Nodes/DfsNode.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Maze.Nodes; -internal class DfsNode : BaseMazeNode -{ -} \ No newline at end of file diff --git a/Nodes/BaseMazeNode.cs b/Nodes/MazeNode.cs similarity index 61% rename from Nodes/BaseMazeNode.cs rename to Nodes/MazeNode.cs index 7960e09..247ab82 100644 --- a/Nodes/BaseMazeNode.cs +++ b/Nodes/MazeNode.cs @@ -1,11 +1,12 @@ namespace Maze.Nodes; -internal abstract class BaseMazeNode where T : BaseMazeNode +internal class MazeNode { public bool Visited { get; set; } public bool Wall { get; set; } public bool Start { get; set; } public bool Goal { get; set; } public bool Updated { get; set; } = true; - public List Neighbors { get; set; } = new List(); + public MazeNode? Parent { get; set; } + public List Neighbors { get; set; } = new List(); } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 64930b9..1036526 100644 --- a/Program.cs +++ b/Program.cs @@ -7,11 +7,11 @@ using Stone_Red_Utilities.ConsoleExtentions; MazeParser parser = new MazeParser(); MazePrinter printer = new MazePrinter(); -IMazeSolver solver = new DepthFirstSearchMazeSolver(); +PathFinder pathFinder = new PathFinder(new DepthFirstSearchMazeSolver()); try { - DfsNode[,] maze = parser.FromFile("input.txt", out DfsNode startNode); + MazeNode[,] maze = parser.FromFile("input.txt", out MazeNode startNode); if (Console.WindowHeight < maze.GetLength(0) || Console.WindowWidth < maze.GetLength(1)) { @@ -20,7 +20,34 @@ try Console.Clear(); } - List solution = solver.Solve(startNode, maze, GraphicsMode.Colored); + Console.WriteLine("Choose an algorithm:"); + Type type = typeof(IMazeSolver); + IEnumerable types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract); + + int index = 0; + + foreach (Type t in types) + { + Console.WriteLine($"[{index++}] {t.Name}"); + } + + int algorithmIndex = -1; + + do + { + if (!int.TryParse(Console.ReadLine(), out algorithmIndex)) + { + ConsoleExt.WriteLine("Invalid input. Please try again.", ConsoleColor.Red); + algorithmIndex = -1; + } + } + while (algorithmIndex < 0 || algorithmIndex >= types.Count()); + + pathFinder.MazeSolver = (IMazeSolver)Activator.CreateInstance(types.ElementAt(algorithmIndex))!; + + List solution = pathFinder.FindPath(startNode, maze, GraphicsMode.Colored); printer.PrintColored(maze, solution, redrawAll: true); diff --git a/Solvers/BreadthFirstSearchMazeSolver.cs b/Solvers/BreadthFirstSearchMazeSolver.cs index c337be9..137ff83 100644 --- a/Solvers/BreadthFirstSearchMazeSolver.cs +++ b/Solvers/BreadthFirstSearchMazeSolver.cs @@ -3,17 +3,17 @@ using Maze.Utlis; namespace Maze.Solvers; -internal class BreadthFirstSearchMazeSolver : IMazeSolver +internal class BreadthFirstSearchMazeSolver : IMazeSolver { - public List Solve(BfsNode node, BfsNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) + public List Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) { if (!node.Start) { throw new MazeException("Node is not a start node."); } - BfsNode currentNode; - Queue queue = new Queue(); + MazeNode currentNode; + Queue queue = new Queue(); queue.Enqueue(node); @@ -28,8 +28,8 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver if (currentNode.Goal) { - List path = new List(); - BfsNode? pathNode = currentNode; + List path = new List(); + MazeNode? pathNode = currentNode; while (pathNode is not null && !pathNode.Start) { @@ -41,7 +41,7 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver return path; } - foreach (BfsNode child in currentNode.Neighbors.Where(n => !n.Visited && !n.Wall)) + foreach (MazeNode child in currentNode.Neighbors.Where(n => !n.Visited && !n.Wall)) { child.Parent = currentNode; child.Visited = true; @@ -65,6 +65,6 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver } } - return new List(); + return new List(); } } \ No newline at end of file diff --git a/Solvers/DepthFirstSearchMazeSolver.cs b/Solvers/DepthFirstSearchMazeSolver.cs index b655580..77c8631 100644 --- a/Solvers/DepthFirstSearchMazeSolver.cs +++ b/Solvers/DepthFirstSearchMazeSolver.cs @@ -3,18 +3,18 @@ using Maze.Utlis; namespace Maze.Solvers; -internal class DepthFirstSearchMazeSolver : IMazeSolver +internal class DepthFirstSearchMazeSolver : IMazeSolver { - public List Solve(DfsNode node, DfsNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) + public List Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) { if (!node.Start) { throw new MazeException("Node is not a start node."); } - DfsNode? currentNode = node; - DfsNode? tempNode = null; - Stack path = new Stack(); + MazeNode? currentNode = node; + MazeNode? tempNode = null; + Stack path = new Stack(); while (!currentNode.Goal) { @@ -25,7 +25,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver throw new MazeException("Node has no neighbors."); } - if (path.TryPeek(out DfsNode? prevNode)) + if (path.TryPeek(out MazeNode? prevNode)) { prevNode.Updated = true; } @@ -39,7 +39,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver throw new MazeException("No path found."); } - if (path.TryPeek(out DfsNode? prevNode2)) + if (path.TryPeek(out MazeNode? prevNode2)) { prevNode2.Updated = true; } @@ -76,7 +76,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver } } - List solution = path.ToList(); + List solution = path.ToList(); solution.ForEach(n => n.Updated = true); return solution; } diff --git a/Solvers/IMazeSolver.cs b/Solvers/IMazeSolver.cs index 0fe298f..cc0379f 100644 --- a/Solvers/IMazeSolver.cs +++ b/Solvers/IMazeSolver.cs @@ -2,7 +2,7 @@ namespace Maze.Solvers; -internal interface IMazeSolver where T : BaseMazeNode, new() +internal interface IMazeSolver { - public List Solve(T node, T[,] maze, GraphicsMode graphicsMode = GraphicsMode.None); + public List Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None); } \ No newline at end of file diff --git a/Utlis/MazeParser.cs b/Utlis/MazeParser.cs index 37daa86..03b4d8b 100644 --- a/Utlis/MazeParser.cs +++ b/Utlis/MazeParser.cs @@ -4,18 +4,18 @@ namespace Maze.Utlis; internal class MazeParser { - public T[,] FromFile(string filePath, out T startNode) where T : BaseMazeNode, new() + public MazeNode[,] FromFile(string filePath, out MazeNode startNode) { return FromString(File.ReadAllText(filePath), out startNode); } - public T[,] FromString(string input, out T startNode) where T : BaseMazeNode, new() + public MazeNode[,] FromString(string input, out MazeNode startNode) { string[] lines = input.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); startNode = null!; - T? goalNode = null; - T[,] nodes = new T[lines.Length, lines[0].Length]; + MazeNode? goalNode = null; + MazeNode[,] nodes = new MazeNode[lines.Length, lines[0].Length]; // Create nodes from input for (int y = 0; y < lines.Length; y++) @@ -24,7 +24,7 @@ internal class MazeParser { char c = lines[y][x]; - T node = new T + MazeNode node = new MazeNode { Wall = c == '+', Start = c == 'S', @@ -69,7 +69,7 @@ internal class MazeParser { for (int x = 0; x < lines[0].Length; x++) { - T node = nodes[y, x]; + MazeNode node = nodes[y, x]; if (x < lines[0].Length - 1) { diff --git a/Utlis/MazePrinter.cs b/Utlis/MazePrinter.cs index 42a5334..30e94d7 100644 --- a/Utlis/MazePrinter.cs +++ b/Utlis/MazePrinter.cs @@ -6,13 +6,13 @@ namespace Maze.Utlis; internal class MazePrinter { - public void Print(T[,] nodes, List? solution = null, bool redrawAll = false) where T : BaseMazeNode + public void Print(MazeNode[,] nodes, List? solution = null, bool redrawAll = false) { for (int y = 0; y < nodes.GetLength(0); y++) { for (int x = 0; x < nodes.GetLength(1); x++) { - T node = nodes[y, x]; + MazeNode node = nodes[y, x]; if (!node.Updated && !redrawAll) { @@ -51,7 +51,7 @@ internal class MazePrinter } } - public void PrintColored(T[,] nodes, List? solution = null, bool redrawAll = false) where T : BaseMazeNode + public void PrintColored(MazeNode[,] nodes, List? solution = null, bool redrawAll = false) { Console.BackgroundColor = ConsoleColor.Black; Console.CursorVisible = false; @@ -60,7 +60,7 @@ internal class MazePrinter { for (int x = 0; x < nodes.GetLength(1); x++) { - T node = nodes[y, x]; + MazeNode node = nodes[y, x]; if (!node.Updated && !redrawAll) { diff --git a/Utlis/PathFinder.cs b/Utlis/PathFinder.cs new file mode 100644 index 0000000..89ba693 --- /dev/null +++ b/Utlis/PathFinder.cs @@ -0,0 +1,19 @@ +using Maze.Nodes; +using Maze.Solvers; + +namespace Maze.Utlis; + +internal class PathFinder +{ + public IMazeSolver MazeSolver { get; set; } + + public PathFinder(IMazeSolver mazeSolver) + { + MazeSolver = mazeSolver; + } + + public List FindPath(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) + { + return MazeSolver.Solve(node, maze, graphicsMode); + } +} \ No newline at end of file