commit eb79a8d616dac28dc32356b129ae62ed084b14c4 Author: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Fri May 5 19:47:25 2023 +0200 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..426d76d --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/GraphicsMode.cs b/GraphicsMode.cs new file mode 100644 index 0000000..78a2ccf --- /dev/null +++ b/GraphicsMode.cs @@ -0,0 +1,8 @@ +namespace Maze; + +internal enum GraphicsMode +{ + None, + BlackWhite, + Colored +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..070371a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Stone_Red + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Maze.csproj b/Maze.csproj new file mode 100644 index 0000000..651638a --- /dev/null +++ b/Maze.csproj @@ -0,0 +1,23 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + Always + + + Always + + + + diff --git a/Maze.sln b/Maze.sln new file mode 100644 index 0000000..cf2d01f --- /dev/null +++ b/Maze.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maze", "Maze.csproj", "{C297ADED-9AFB-4F7B-9EA5-B37AE5375FD7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C297ADED-9AFB-4F7B-9EA5-B37AE5375FD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C297ADED-9AFB-4F7B-9EA5-B37AE5375FD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C297ADED-9AFB-4F7B-9EA5-B37AE5375FD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C297ADED-9AFB-4F7B-9EA5-B37AE5375FD7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A34A2ED1-5C7E-430D-84D4-2112560BD3F5} + EndGlobalSection +EndGlobal diff --git a/MazeException.cs b/MazeException.cs new file mode 100644 index 0000000..bac7272 --- /dev/null +++ b/MazeException.cs @@ -0,0 +1,23 @@ +using System.Runtime.Serialization; + +namespace Maze; + +[Serializable] +public class MazeException : Exception +{ + public MazeException() + { + } + + public MazeException(string message) : base(message) + { + } + + public MazeException(string message, Exception innerException) : base(message, innerException) + { + } + + protected MazeException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/Nodes/BaseMazeNode.cs b/Nodes/BaseMazeNode.cs new file mode 100644 index 0000000..7960e09 --- /dev/null +++ b/Nodes/BaseMazeNode.cs @@ -0,0 +1,11 @@ +namespace Maze.Nodes; + +internal abstract class BaseMazeNode where T : BaseMazeNode +{ + 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(); +} \ No newline at end of file diff --git a/Nodes/BfsNode.cs b/Nodes/BfsNode.cs new file mode 100644 index 0000000..99b25be --- /dev/null +++ b/Nodes/BfsNode.cs @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..8017b15 --- /dev/null +++ b/Nodes/DfsNode.cs @@ -0,0 +1,4 @@ +namespace Maze.Nodes; +internal class DfsNode : BaseMazeNode +{ +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..4e0f8cc --- /dev/null +++ b/Program.cs @@ -0,0 +1,31 @@ +using Maze; +using Maze.Nodes; +using Maze.Solvers; +using Maze.Utlis; + +using Stone_Red_Utilities.ConsoleExtentions; + +MazeParser parser = new MazeParser(); +MazePrinter printer = new MazePrinter(); +IMazeSolver solver = new DepthFirstSearchMazeSolver(); + +try +{ + DfsNode[,] maze = parser.FromFile("input.txt", out DfsNode startNode); + + if (Console.WindowHeight < maze.GetLength(0) || Console.WindowWidth < maze.GetLength(1)) + { + ConsoleExt.WriteLine("Console window size too small. Visualizing the maze may cause errors!", ConsoleColor.Red); + ConsoleExt.Pause(true, "Press ENTER to continue or CTRL+C to exit the program."); + } + + List solution = solver.Solve(startNode, maze, GraphicsMode.Colored); + + printer.PrintColored(maze, solution, redrawAll: true); + + ConsoleExt.WriteLine("Done", ConsoleColor.Green); +} +catch (MazeException e) +{ + ConsoleExt.WriteLine(e.Message, ConsoleColor.Red); +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f4f9f47 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Maze + A small maze solving program diff --git a/Solvers/BreadthFirstSearchMazeSolver.cs b/Solvers/BreadthFirstSearchMazeSolver.cs new file mode 100644 index 0000000..c337be9 --- /dev/null +++ b/Solvers/BreadthFirstSearchMazeSolver.cs @@ -0,0 +1,70 @@ +using Maze.Nodes; +using Maze.Utlis; + +namespace Maze.Solvers; + +internal class BreadthFirstSearchMazeSolver : IMazeSolver +{ + public List Solve(BfsNode node, BfsNode[,] maze, GraphicsMode graphicsMode = GraphicsMode.None) + { + if (!node.Start) + { + throw new MazeException("Node is not a start node."); + } + + BfsNode currentNode; + Queue queue = new Queue(); + + queue.Enqueue(node); + + while (queue.Count > 0) + { + currentNode = queue.Dequeue(); + currentNode.Updated = true; + if (currentNode.Parent is not null) + { + currentNode.Parent.Updated = true; + } + + if (currentNode.Goal) + { + List path = new List(); + BfsNode? pathNode = currentNode; + + while (pathNode is not null && !pathNode.Start) + { + pathNode.Updated = true; + path.Add(pathNode); + pathNode = pathNode.Parent; + } + + return path; + } + + foreach (BfsNode child in currentNode.Neighbors.Where(n => !n.Visited && !n.Wall)) + { + child.Parent = currentNode; + child.Visited = true; + child.Updated = true; + queue.Enqueue(child); + } + + if (graphicsMode != GraphicsMode.None) + { + Thread.Sleep(50); + Console.SetCursorPosition(0, 0); + } + + if (graphicsMode == GraphicsMode.BlackWhite) + { + new MazePrinter().Print(maze, queue.ToList()); + } + else if (graphicsMode == GraphicsMode.Colored) + { + new MazePrinter().PrintColored(maze, queue.ToList()); + } + } + + return new List(); + } +} \ No newline at end of file diff --git a/Solvers/DepthFirstSearchMazeSolver.cs b/Solvers/DepthFirstSearchMazeSolver.cs new file mode 100644 index 0000000..b655580 --- /dev/null +++ b/Solvers/DepthFirstSearchMazeSolver.cs @@ -0,0 +1,83 @@ +using Maze.Nodes; +using Maze.Utlis; + +namespace Maze.Solvers; + +internal class DepthFirstSearchMazeSolver : IMazeSolver +{ + public List Solve(DfsNode node, DfsNode[,] 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(); + + while (!currentNode.Goal) + { + currentNode.Visited = true; + + if (currentNode.Neighbors.Count == 0) + { + throw new MazeException("Node has no neighbors."); + } + + if (path.TryPeek(out DfsNode? prevNode)) + { + prevNode.Updated = true; + } + + currentNode = currentNode.Neighbors.FirstOrDefault(n => !n.Visited && !n.Wall); + + if (currentNode is null) + { + if (!path.TryPop(out currentNode)) + { + throw new MazeException("No path found."); + } + + if (path.TryPeek(out DfsNode? prevNode2)) + { + prevNode2.Updated = true; + } + + tempNode = currentNode; + } + else + { + // Add the previous node to the path + if (tempNode is not null) + { + tempNode.Updated = true; + path.Push(tempNode); + tempNode = null; + } + path.Push(currentNode); + } + + currentNode.Updated = true; + + if (graphicsMode != GraphicsMode.None) + { + Thread.Sleep(30); + Console.SetCursorPosition(0, 0); + } + + if (graphicsMode == GraphicsMode.BlackWhite) + { + new MazePrinter().Print(maze, path.ToList()); + } + else if (graphicsMode == GraphicsMode.Colored) + { + new MazePrinter().PrintColored(maze, path.ToList()); + } + } + + List solution = path.ToList(); + solution.ForEach(n => n.Updated = true); + return solution; + } +} \ No newline at end of file diff --git a/Solvers/IMazeSolver.cs b/Solvers/IMazeSolver.cs new file mode 100644 index 0000000..0fe298f --- /dev/null +++ b/Solvers/IMazeSolver.cs @@ -0,0 +1,8 @@ +using Maze.Nodes; + +namespace Maze.Solvers; + +internal interface IMazeSolver where T : BaseMazeNode, new() +{ + public List Solve(T node, T[,] maze, GraphicsMode graphicsMode = GraphicsMode.None); +} \ No newline at end of file diff --git a/Utlis/MazeParser.cs b/Utlis/MazeParser.cs new file mode 100644 index 0000000..37daa86 --- /dev/null +++ b/Utlis/MazeParser.cs @@ -0,0 +1,95 @@ +using Maze.Nodes; + +namespace Maze.Utlis; + +internal class MazeParser +{ + public T[,] FromFile(string filePath, out T startNode) where T : BaseMazeNode, new() + { + return FromString(File.ReadAllText(filePath), out startNode); + } + + public T[,] FromString(string input, out T startNode) where T : BaseMazeNode, new() + { + 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]; + + // Create nodes from input + for (int y = 0; y < lines.Length; y++) + { + for (int x = 0; x < lines[0].Length; x++) + { + char c = lines[y][x]; + + T node = new T + { + Wall = c == '+', + Start = c == 'S', + Goal = c == 'G' + }; + + if (node.Start) + { + if (startNode is not null) + { + throw new MazeException("Multiple start nodes found."); + } + + startNode = node; + } + + if (node.Goal) + { + if (goalNode is not null) + { + throw new MazeException("Multiple goal nodes found."); + } + goalNode = node; + } + + nodes[y, x] = node; + } + } + + if (startNode is null) + { + throw new MazeException("No start node found."); + } + + if (goalNode is null) + { + throw new MazeException("No goal node found."); + } + + // Add neighbors to nodes based on their position in the maze + for (int y = 0; y < lines.Length; y++) + { + for (int x = 0; x < lines[0].Length; x++) + { + T node = nodes[y, x]; + + if (x < lines[0].Length - 1) + { + node.Neighbors.Add(nodes[y, x + 1]); + } + if (x > 0) + { + node.Neighbors.Add(nodes[y, x - 1]); + } + if (y < lines.Length - 1) + { + node.Neighbors.Add(nodes[y + 1, x]); + } + if (y > 0) + { + node.Neighbors.Add(nodes[y - 1, x]); + } + } + } + + return nodes; + } +} \ No newline at end of file diff --git a/Utlis/MazePrinter.cs b/Utlis/MazePrinter.cs new file mode 100644 index 0000000..42a5334 --- /dev/null +++ b/Utlis/MazePrinter.cs @@ -0,0 +1,132 @@ +using Maze.Nodes; + +using Stone_Red_Utilities.ConsoleExtentions; + +namespace Maze.Utlis; + +internal class MazePrinter +{ + public void Print(T[,] nodes, List? solution = null, bool redrawAll = false) where T : BaseMazeNode + { + for (int y = 0; y < nodes.GetLength(0); y++) + { + for (int x = 0; x < nodes.GetLength(1); x++) + { + T node = nodes[y, x]; + + if (!node.Updated && !redrawAll) + { + continue; + } + + node.Updated = false; + + Console.SetCursorPosition(x, y); + + if (node.Wall) + { + Console.Write('+'); + } + else if (node.Start) + { + Console.Write('S'); + } + else if (node.Goal) + { + Console.Write('G'); + } + else if (solution?.Contains(node) == true) + { + Console.Write(GetDirection(x, y, node, nodes, solution)); + } + else if (node.Visited) + { + Console.Write('-'); + } + else + { + Console.Write(' '); + } + } + } + } + + public void PrintColored(T[,] nodes, List? solution = null, bool redrawAll = false) where T : BaseMazeNode + { + Console.BackgroundColor = ConsoleColor.Black; + Console.CursorVisible = false; + + for (int y = 0; y < nodes.GetLength(0); y++) + { + for (int x = 0; x < nodes.GetLength(1); x++) + { + T node = nodes[y, x]; + + if (!node.Updated && !redrawAll) + { + continue; + } + + node.Updated = false; + + Console.SetCursorPosition(x, y); + + if (node.Wall) + { + ConsoleExt.Write('+', ConsoleColor.White); + } + else if (node.Start) + { + ConsoleExt.Write('S', ConsoleColor.Magenta); + } + else if (node.Goal) + { + ConsoleExt.Write('G', ConsoleColor.Red); + } + else if (solution?.Contains(node) == true) + { + ConsoleExt.Write(GetDirection(x, y, node, nodes, solution), ConsoleColor.Green); + } + else if (node.Visited) + { + ConsoleExt.Write('-', ConsoleColor.DarkGray); + } + else + { + Console.Write(' '); + } + } + } + + Console.ResetColor(); + Console.CursorVisible = false; + } + + // Get the direction of the next node in the solution list + private static char GetDirection(int x, int y, T node, T[,] nodes, List solution) + { + int index = solution.IndexOf(node); + T? nextNode = solution.ElementAtOrDefault(index - 1); + + if (y > 0 && nextNode?.Equals(nodes[y - 1, x]) == true) + { + return '^'; + } + else if (y < nodes.GetLength(0) - 1 && nextNode?.Equals(nodes[y + 1, x]) == true) + { + return 'v'; + } + else if (x > 0 && nextNode?.Equals(nodes[y, x - 1]) == true) + { + return '<'; + } + else if (x < nodes.GetLength(1) - 1 && nextNode?.Equals(nodes[y, x + 1]) == true) + { + return '>'; + } + else + { + return 'O'; + } + } +} \ No newline at end of file diff --git a/input.txt b/input.txt new file mode 100644 index 0000000..f91b521 --- /dev/null +++ b/input.txt @@ -0,0 +1,33 @@ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++G + + + + + + + +++++ + ++++++++++ ++++ ++++ + ++++++++++ + ++++ + + ++ + + + + + + + + + ++ + ++++ ++++ +++++++ + + ++++ + + + + + +++++++ ++ + + + + + + + + + + ++ ++++++++++++++++ ++++++++++ ++++ ++++ + + ++++++++++ ++ + + + + + + + + + ++ + ++++ + ++++ ++++++++++++++++ + + +++++++ + + + ++ + + + + + + + + + + + + + ++ + + + ++++ + ++++ + + +++++++++++++ + ++++ ++++ ++ + + + + + + + + + + + + ++ + + ++++ + + +++++++ ++++ + ++++++++++ ++++ + + ++ + + + + + + + + + + + +++++++++++ + ++++ ++++ +++++++ + + ++++ + + + + + ++ + + + + + + + + +++++ +++++++ ++++ + ++++ +++++++++++++ ++++++++++ ++++ ++ + + + + + + + + + +++++ + + + + +++++++ + + ++++ + +++++++ ++++++++++ ++ + + + + + + + + + + +++++++++++ ++++++++++ + ++++++++++ + + + ++++++++++ + ++ + + + + + + + + + + + ++ + ++++ ++++++++++++++++ ++++ + ++++ + +++++++ + + ++ + + + + + + + + + + +++++ ++++ ++++ + +++++++ ++++ + ++++ + ++++ ++++ + ++ + + + + + + + + + + +++++ +++++++ ++++ + + ++++ + + + ++++ ++++++++++ + ++ + + + + + + + + + + + + + + + ++ + +++++++ + + ++++ + ++++ + ++++ ++++ ++++ + + ++ + + + + + + + ++ ++++ ++++++++++ ++++++++++ ++++ + ++++++++++ + ++++ ++ + + + + + + + S+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file