mirror of
https://github.com/Stone-Red-Code/Maze.git
synced 2026-09-04 00:56:11 +02:00
Implement strategy pattern
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
namespace Maze.Nodes;
|
|
||||||
|
|
||||||
internal class BfsNode : BaseMazeNode<BfsNode>
|
|
||||||
{
|
|
||||||
public BfsNode? Parent { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Maze.Nodes;
|
|
||||||
internal class DfsNode : BaseMazeNode<DfsNode>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
namespace Maze.Nodes;
|
namespace Maze.Nodes;
|
||||||
|
|
||||||
internal abstract class BaseMazeNode<T> where T : BaseMazeNode<T>
|
internal class MazeNode
|
||||||
{
|
{
|
||||||
public bool Visited { get; set; }
|
public bool Visited { get; set; }
|
||||||
public bool Wall { get; set; }
|
public bool Wall { get; set; }
|
||||||
public bool Start { get; set; }
|
public bool Start { get; set; }
|
||||||
public bool Goal { get; set; }
|
public bool Goal { get; set; }
|
||||||
public bool Updated { get; set; } = true;
|
public bool Updated { get; set; } = true;
|
||||||
public List<T> Neighbors { get; set; } = new List<T>();
|
public MazeNode? Parent { get; set; }
|
||||||
|
public List<MazeNode> Neighbors { get; set; } = new List<MazeNode>();
|
||||||
}
|
}
|
||||||
+30
-3
@@ -7,11 +7,11 @@ using Stone_Red_Utilities.ConsoleExtentions;
|
|||||||
|
|
||||||
MazeParser parser = new MazeParser();
|
MazeParser parser = new MazeParser();
|
||||||
MazePrinter printer = new MazePrinter();
|
MazePrinter printer = new MazePrinter();
|
||||||
IMazeSolver<DfsNode> solver = new DepthFirstSearchMazeSolver();
|
PathFinder pathFinder = new PathFinder(new DepthFirstSearchMazeSolver());
|
||||||
|
|
||||||
try
|
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))
|
if (Console.WindowHeight < maze.GetLength(0) || Console.WindowWidth < maze.GetLength(1))
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,34 @@ try
|
|||||||
Console.Clear();
|
Console.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DfsNode> solution = solver.Solve(startNode, maze, GraphicsMode.Colored);
|
Console.WriteLine("Choose an algorithm:");
|
||||||
|
Type type = typeof(IMazeSolver);
|
||||||
|
IEnumerable<Type> 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<MazeNode> solution = pathFinder.FindPath(startNode, maze, GraphicsMode.Colored);
|
||||||
|
|
||||||
printer.PrintColored(maze, solution, redrawAll: true);
|
printer.PrintColored(maze, solution, redrawAll: true);
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ using Maze.Utlis;
|
|||||||
|
|
||||||
namespace Maze.Solvers;
|
namespace Maze.Solvers;
|
||||||
|
|
||||||
internal class BreadthFirstSearchMazeSolver : IMazeSolver<BfsNode>
|
internal class BreadthFirstSearchMazeSolver : IMazeSolver
|
||||||
{
|
{
|
||||||
public List<BfsNode> Solve(BfsNode node, BfsNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None)
|
public List<MazeNode> Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None)
|
||||||
{
|
{
|
||||||
if (!node.Start)
|
if (!node.Start)
|
||||||
{
|
{
|
||||||
throw new MazeException("Node is not a start node.");
|
throw new MazeException("Node is not a start node.");
|
||||||
}
|
}
|
||||||
|
|
||||||
BfsNode currentNode;
|
MazeNode currentNode;
|
||||||
Queue<BfsNode> queue = new Queue<BfsNode>();
|
Queue<MazeNode> queue = new Queue<MazeNode>();
|
||||||
|
|
||||||
queue.Enqueue(node);
|
queue.Enqueue(node);
|
||||||
|
|
||||||
@@ -28,8 +28,8 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver<BfsNode>
|
|||||||
|
|
||||||
if (currentNode.Goal)
|
if (currentNode.Goal)
|
||||||
{
|
{
|
||||||
List<BfsNode> path = new List<BfsNode>();
|
List<MazeNode> path = new List<MazeNode>();
|
||||||
BfsNode? pathNode = currentNode;
|
MazeNode? pathNode = currentNode;
|
||||||
|
|
||||||
while (pathNode is not null && !pathNode.Start)
|
while (pathNode is not null && !pathNode.Start)
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver<BfsNode>
|
|||||||
return path;
|
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.Parent = currentNode;
|
||||||
child.Visited = true;
|
child.Visited = true;
|
||||||
@@ -65,6 +65,6 @@ internal class BreadthFirstSearchMazeSolver : IMazeSolver<BfsNode>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<BfsNode>();
|
return new List<MazeNode>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,18 +3,18 @@ using Maze.Utlis;
|
|||||||
|
|
||||||
namespace Maze.Solvers;
|
namespace Maze.Solvers;
|
||||||
|
|
||||||
internal class DepthFirstSearchMazeSolver : IMazeSolver<DfsNode>
|
internal class DepthFirstSearchMazeSolver : IMazeSolver
|
||||||
{
|
{
|
||||||
public List<DfsNode> Solve(DfsNode node, DfsNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None)
|
public List<MazeNode> Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None)
|
||||||
{
|
{
|
||||||
if (!node.Start)
|
if (!node.Start)
|
||||||
{
|
{
|
||||||
throw new MazeException("Node is not a start node.");
|
throw new MazeException("Node is not a start node.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DfsNode? currentNode = node;
|
MazeNode? currentNode = node;
|
||||||
DfsNode? tempNode = null;
|
MazeNode? tempNode = null;
|
||||||
Stack<DfsNode> path = new Stack<DfsNode>();
|
Stack<MazeNode> path = new Stack<MazeNode>();
|
||||||
|
|
||||||
while (!currentNode.Goal)
|
while (!currentNode.Goal)
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver<DfsNode>
|
|||||||
throw new MazeException("Node has no neighbors.");
|
throw new MazeException("Node has no neighbors.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.TryPeek(out DfsNode? prevNode))
|
if (path.TryPeek(out MazeNode? prevNode))
|
||||||
{
|
{
|
||||||
prevNode.Updated = true;
|
prevNode.Updated = true;
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver<DfsNode>
|
|||||||
throw new MazeException("No path found.");
|
throw new MazeException("No path found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.TryPeek(out DfsNode? prevNode2))
|
if (path.TryPeek(out MazeNode? prevNode2))
|
||||||
{
|
{
|
||||||
prevNode2.Updated = true;
|
prevNode2.Updated = true;
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ internal class DepthFirstSearchMazeSolver : IMazeSolver<DfsNode>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DfsNode> solution = path.ToList();
|
List<MazeNode> solution = path.ToList();
|
||||||
solution.ForEach(n => n.Updated = true);
|
solution.ForEach(n => n.Updated = true);
|
||||||
return solution;
|
return solution;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Maze.Solvers;
|
namespace Maze.Solvers;
|
||||||
|
|
||||||
internal interface IMazeSolver<T> where T : BaseMazeNode<T>, new()
|
internal interface IMazeSolver
|
||||||
{
|
{
|
||||||
public List<T> Solve(T node, T[,] maze, GraphicsMode graphicsMode = GraphicsMode.None);
|
public List<MazeNode> Solve(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None);
|
||||||
}
|
}
|
||||||
+6
-6
@@ -4,18 +4,18 @@ namespace Maze.Utlis;
|
|||||||
|
|
||||||
internal class MazeParser
|
internal class MazeParser
|
||||||
{
|
{
|
||||||
public T[,] FromFile<T>(string filePath, out T startNode) where T : BaseMazeNode<T>, new()
|
public MazeNode[,] FromFile(string filePath, out MazeNode startNode)
|
||||||
{
|
{
|
||||||
return FromString(File.ReadAllText(filePath), out startNode);
|
return FromString(File.ReadAllText(filePath), out startNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T[,] FromString<T>(string input, out T startNode) where T : BaseMazeNode<T>, new()
|
public MazeNode[,] FromString(string input, out MazeNode startNode)
|
||||||
{
|
{
|
||||||
string[] lines = input.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
|
string[] lines = input.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
startNode = null!;
|
startNode = null!;
|
||||||
T? goalNode = null;
|
MazeNode? goalNode = null;
|
||||||
T[,] nodes = new T[lines.Length, lines[0].Length];
|
MazeNode[,] nodes = new MazeNode[lines.Length, lines[0].Length];
|
||||||
|
|
||||||
// Create nodes from input
|
// Create nodes from input
|
||||||
for (int y = 0; y < lines.Length; y++)
|
for (int y = 0; y < lines.Length; y++)
|
||||||
@@ -24,7 +24,7 @@ internal class MazeParser
|
|||||||
{
|
{
|
||||||
char c = lines[y][x];
|
char c = lines[y][x];
|
||||||
|
|
||||||
T node = new T
|
MazeNode node = new MazeNode
|
||||||
{
|
{
|
||||||
Wall = c == '+',
|
Wall = c == '+',
|
||||||
Start = c == 'S',
|
Start = c == 'S',
|
||||||
@@ -69,7 +69,7 @@ internal class MazeParser
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < lines[0].Length; x++)
|
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)
|
if (x < lines[0].Length - 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ namespace Maze.Utlis;
|
|||||||
|
|
||||||
internal class MazePrinter
|
internal class MazePrinter
|
||||||
{
|
{
|
||||||
public void Print<T>(T[,] nodes, List<T>? solution = null, bool redrawAll = false) where T : BaseMazeNode<T>
|
public void Print(MazeNode[,] nodes, List<MazeNode>? solution = null, bool redrawAll = false)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < nodes.GetLength(0); y++)
|
for (int y = 0; y < nodes.GetLength(0); y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < nodes.GetLength(1); x++)
|
for (int x = 0; x < nodes.GetLength(1); x++)
|
||||||
{
|
{
|
||||||
T node = nodes[y, x];
|
MazeNode node = nodes[y, x];
|
||||||
|
|
||||||
if (!node.Updated && !redrawAll)
|
if (!node.Updated && !redrawAll)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ internal class MazePrinter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrintColored<T>(T[,] nodes, List<T>? solution = null, bool redrawAll = false) where T : BaseMazeNode<T>
|
public void PrintColored(MazeNode[,] nodes, List<MazeNode>? solution = null, bool redrawAll = false)
|
||||||
{
|
{
|
||||||
Console.BackgroundColor = ConsoleColor.Black;
|
Console.BackgroundColor = ConsoleColor.Black;
|
||||||
Console.CursorVisible = false;
|
Console.CursorVisible = false;
|
||||||
@@ -60,7 +60,7 @@ internal class MazePrinter
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < nodes.GetLength(1); x++)
|
for (int x = 0; x < nodes.GetLength(1); x++)
|
||||||
{
|
{
|
||||||
T node = nodes[y, x];
|
MazeNode node = nodes[y, x];
|
||||||
|
|
||||||
if (!node.Updated && !redrawAll)
|
if (!node.Updated && !redrawAll)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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<MazeNode> FindPath(MazeNode node, MazeNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None)
|
||||||
|
{
|
||||||
|
return MazeSolver.Solve(node, maze, graphicsMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user