From b983a0735ac17ec82695ab1e8173f6ec4d31294a Mon Sep 17 00:00:00 2001 From: zwarenelle Date: Wed, 22 May 2024 12:43:35 +0200 Subject: [PATCH] add astar test --- .gitignore | 4 +- src/Pathfinder/AStarPathfinding.sln | 22 +++ .../AStarPathfinding/AStarPathfinding.csproj | 59 +++++++ src/Pathfinder/AStarPathfinding/App.config | 6 + src/Pathfinder/AStarPathfinding/Program.cs | 146 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++ .../bin/Debug/AStarPathfinding.exe | Bin 0 -> 8192 bytes .../bin/Debug/AStarPathfinding.exe.config | 6 + .../bin/Debug/AStarPathfinding.pdb | Bin 0 -> 22016 bytes 9 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 src/Pathfinder/AStarPathfinding.sln create mode 100644 src/Pathfinder/AStarPathfinding/AStarPathfinding.csproj create mode 100644 src/Pathfinder/AStarPathfinding/App.config create mode 100644 src/Pathfinder/AStarPathfinding/Program.cs create mode 100644 src/Pathfinder/AStarPathfinding/Properties/AssemblyInfo.cs create mode 100644 src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe create mode 100644 src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe.config create mode 100644 src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.pdb diff --git a/.gitignore b/.gitignore index ec6cb9f..3e21425 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ src/tmp node_modules/ obj/ -out/ \ No newline at end of file +out/ +/src/Client/RobotController/.vs +/.vs diff --git a/src/Pathfinder/AStarPathfinding.sln b/src/Pathfinder/AStarPathfinding.sln new file mode 100644 index 0000000..ae00c25 --- /dev/null +++ b/src/Pathfinder/AStarPathfinding.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStarPathfinding", "AStarPathfinding\AStarPathfinding.csproj", "{97647F1E-1A0A-444D-A437-A809F9EB855F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {97647F1E-1A0A-444D-A437-A809F9EB855F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97647F1E-1A0A-444D-A437-A809F9EB855F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97647F1E-1A0A-444D-A437-A809F9EB855F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97647F1E-1A0A-444D-A437-A809F9EB855F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Pathfinder/AStarPathfinding/AStarPathfinding.csproj b/src/Pathfinder/AStarPathfinding/AStarPathfinding.csproj new file mode 100644 index 0000000..ac6f6a3 --- /dev/null +++ b/src/Pathfinder/AStarPathfinding/AStarPathfinding.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {97647F1E-1A0A-444D-A437-A809F9EB855F} + Exe + Properties + AStarPathfinding + AStarPathfinding + v4.8 + 512 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Pathfinder/AStarPathfinding/App.config b/src/Pathfinder/AStarPathfinding/App.config new file mode 100644 index 0000000..4bfa005 --- /dev/null +++ b/src/Pathfinder/AStarPathfinding/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Pathfinder/AStarPathfinding/Program.cs b/src/Pathfinder/AStarPathfinding/Program.cs new file mode 100644 index 0000000..9efb94d --- /dev/null +++ b/src/Pathfinder/AStarPathfinding/Program.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AStarPathfinding +{ + class Location + { + public int X; + public int Y; + public int F; + public int G; + public int H; + public Location Parent; + } + + class Program + { + static void Main(string[] args) + { + Console.Title = "A* Pathfinding"; + + // draw map + + string[] map = new string[] + { + "+------+", + "| |", + "|A X |", + "|XXX |", + "| X |", + "| B |", + "| |", + "+------+", + }; + + foreach (var line in map) + Console.WriteLine(line); + + // algorithm + + Location current = null; + var start = new Location { X = 1, Y = 2 }; + var target = new Location { X = 2, Y = 5 }; + var openList = new List(); + var closedList = new List(); + int g = 0; + + // start by adding the original position to the open list + openList.Add(start); + + while (openList.Count > 0) + { + // get the square with the lowest F score + var lowest = openList.Min(l => l.F); + current = openList.First(l => l.F == lowest); + + // add the current square to the closed list + closedList.Add(current); + + // show current square on the map + Console.SetCursorPosition(current.X, current.Y); + Console.Write('.'); + Console.SetCursorPosition(current.X, current.Y); + System.Threading.Thread.Sleep(1000); + + // remove it from the open list + openList.Remove(current); + + // if we added the destination to the closed list, we've found a path + if (closedList.FirstOrDefault(l => l.X == target.X && l.Y == target.Y) != null) + break; + + var adjacentSquares = GetWalkableAdjacentSquares(current.X, current.Y, map); + g++; + + foreach(var adjacentSquare in adjacentSquares) + { + // if this adjacent square is already in the closed list, ignore it + if (closedList.FirstOrDefault(l => l.X == adjacentSquare.X + && l.Y == adjacentSquare.Y) != null) + continue; + + // if it's not in the open list... + if (openList.FirstOrDefault(l => l.X == adjacentSquare.X + && l.Y == adjacentSquare.Y) == null) + { + // compute its score, set the parent + adjacentSquare.G = g; + adjacentSquare.H = ComputeHScore(adjacentSquare.X, adjacentSquare.Y, target.X, target.Y); + adjacentSquare.F = adjacentSquare.G + adjacentSquare.H; + adjacentSquare.Parent = current; + + // and add it to the open list + openList.Insert(0, adjacentSquare); + } + else + { + // test if using the current G score makes the adjacent square's F score + // lower, if yes update the parent because it means it's a better path + if (g + adjacentSquare.H < adjacentSquare.F) + { + adjacentSquare.G = current.G + 1; + adjacentSquare.F = adjacentSquare.G + adjacentSquare.H; + adjacentSquare.Parent = current; + } + } + } + } + + // assume path was found; let's show it + while (current != null) + { + Console.SetCursorPosition(current.X, current.Y); + Console.Write('_'); + Console.SetCursorPosition(current.X, current.Y); + current = current.Parent; + System.Threading.Thread.Sleep(1000); + } + + // end + + Console.ReadLine(); + } + + static List GetWalkableAdjacentSquares(int x, int y, string[] map) + { + var proposedLocations = new List() + { + new Location { X = x, Y = y - 1 }, + new Location { X = x, Y = y + 1 }, + new Location { X = x - 1, Y = y }, + new Location { X = x + 1, Y = y }, + }; + + return proposedLocations.Where(l => map[l.Y][l.X] == ' ' || map[l.Y][l.X] == 'B').ToList(); + } + + static int ComputeHScore(int x, int y, int targetX, int targetY) + { + return Math.Abs(targetX - x) + Math.Abs(targetY - y); + } + } +} diff --git a/src/Pathfinder/AStarPathfinding/Properties/AssemblyInfo.cs b/src/Pathfinder/AStarPathfinding/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4d824f2 --- /dev/null +++ b/src/Pathfinder/AStarPathfinding/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AStarPathfinding")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AStarPathfinding")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("41c6c38d-e6f0-4437-b8a8-fa0a8ea19eab")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe b/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe new file mode 100644 index 0000000000000000000000000000000000000000..692050cfd32ca151055400068f67aee5e03e4371 GIT binary patch literal 8192 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 T)BsXYb|^C#&4hY|R1zqm8n literal 0 HcmV?d00001 diff --git a/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe.config b/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe.config new file mode 100644 index 0000000..4bfa005 --- /dev/null +++ b/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.exe.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.pdb b/src/Pathfinder/AStarPathfinding/bin/Debug/AStarPathfinding.pdb new file mode 100644 index 0000000000000000000000000000000000000000..5b97d58a4a5abc47e76a3371ffffd59777680051 GIT binary patch literal 22016 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 literal 0 HcmV?d00001