diff --git a/src/Avans.FlatGalaxy.Models/CelestialBodies/CelestialBody.cs b/src/Avans.FlatGalaxy.Models/CelestialBodies/CelestialBody.cs index a0750bd..779575d 100644 --- a/src/Avans.FlatGalaxy.Models/CelestialBodies/CelestialBody.cs +++ b/src/Avans.FlatGalaxy.Models/CelestialBodies/CelestialBody.cs @@ -56,6 +56,8 @@ public void Collide(CelestialBody other) CollisionState.Collide(this, other); } + public double DistanceTo(CelestialBody target) => Math.Pow(CenterX - target.CenterX, 2) + Math.Pow(CenterY - target.CenterY, 2); + public IDisposable Subscribe(IObserver observer) { _observers.Add(observer); diff --git a/src/Avans.FlatGalaxy.Presentation/SimulationWindow.xaml.cs b/src/Avans.FlatGalaxy.Presentation/SimulationWindow.xaml.cs index c73e12f..f0d4cc2 100644 --- a/src/Avans.FlatGalaxy.Presentation/SimulationWindow.xaml.cs +++ b/src/Avans.FlatGalaxy.Presentation/SimulationWindow.xaml.cs @@ -10,7 +10,6 @@ using Avans.FlatGalaxy.Presentation.Extensions; using Avans.FlatGalaxy.Simulation; using Avans.FlatGalaxy.Simulation.Data; -using Color=System.Drawing.Color; namespace Avans.FlatGalaxy.Presentation { diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/BreadthFirstPathFinder.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/BreadthFirstPathFinder.cs index e5cd2ca..684b4e6 100644 --- a/src/Avans.FlatGalaxy.Simulation/PathFinding/BreadthFirstPathFinder.cs +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/BreadthFirstPathFinder.cs @@ -5,7 +5,7 @@ namespace Avans.FlatGalaxy.Simulation.PathFinding { public class BreadthFirstPathFinder : PathFinder { - protected override List Find(Planet start, Planet end) + protected override List Find(Planet start, Planet end, List planets) { var previous = new Dictionary(); var queue = new Queue(); diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraEdge.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraEdge.cs new file mode 100644 index 0000000..b151e77 --- /dev/null +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraEdge.cs @@ -0,0 +1,15 @@ +namespace Avans.FlatGalaxy.Simulation.PathFinding.Data +{ + public class DijkstraEdge + { + public DijkstraNode Node { get; set; } + + public double Weight { get; set; } + + public DijkstraEdge(DijkstraNode node, double weight) + { + Node = node; + Weight = weight; + } + } +} diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraGraph.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraGraph.cs new file mode 100644 index 0000000..45788d2 --- /dev/null +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraGraph.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Linq; +using Avans.FlatGalaxy.Models.CelestialBodies; + +namespace Avans.FlatGalaxy.Simulation.PathFinding.Data +{ + public class DijkstraGraph + { + public List Nodes { get; } + + public DijkstraGraph(List planets) + { + Nodes = planets.Select(planet => new DijkstraNode(planet)).ToList(); + + foreach (var node in Nodes) + { + foreach (var neighbour in node.Planet.Neighbours) + { + var neighbourNode = Nodes.First(node1 => node1.Planet == neighbour); + + node.Neighbours.Add(new(neighbourNode, node.Planet.DistanceTo(neighbour))); + } + } + } + } +} diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraNode.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraNode.cs new file mode 100644 index 0000000..7fa13a1 --- /dev/null +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/Data/DijkstraNode.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Avans.FlatGalaxy.Models.CelestialBodies; + +namespace Avans.FlatGalaxy.Simulation.PathFinding.Data +{ + public class DijkstraNode + { + public Planet Planet { get; } + + public KeyValuePair Weight { get; set; } + + public List Neighbours { get; } + + public bool Visited { get; set; } + + public DijkstraNode(Planet planet) + { + Neighbours = new(); + Weight = new(null, double.PositiveInfinity); + Planet = planet; + } + } +} diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/DijkstraPathFinder.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/DijkstraPathFinder.cs index 41a7c28..7fc635c 100644 --- a/src/Avans.FlatGalaxy.Simulation/PathFinding/DijkstraPathFinder.cs +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/DijkstraPathFinder.cs @@ -1,16 +1,48 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using Avans.FlatGalaxy.Models.CelestialBodies; +using Avans.FlatGalaxy.Simulation.PathFinding.Data; namespace Avans.FlatGalaxy.Simulation.PathFinding { public class DijkstraPathFinder : PathFinder { - protected override List Find(Planet start, Planet end) + protected override List Find(Planet start, Planet end, List planets) { - return null; - } + var graph = new DijkstraGraph(planets); + var startNode = graph.Nodes.First(node => node.Planet == start); + startNode.Weight = new(null, 0); + var unvisited = new List { startNode }; + + while (unvisited.Any()) + { + var node = unvisited.OrderBy(node1 => node1.Weight.Value).First(); + + foreach (var neighbour in node.Neighbours) + { + if (neighbour.Weight + node.Weight.Value < neighbour.Node.Weight.Value) + { + neighbour.Node.Weight = new(node.Planet, neighbour.Weight + node.Weight.Value); - private static double GetDistance(Planet origin, Planet target) => Math.Pow(origin.CenterX - target.CenterX, 2) + Math.Pow(origin.CenterY - target.CenterY, 2); + if (!unvisited.Contains(neighbour.Node) && !neighbour.Node.Visited) + { + unvisited.Add(neighbour.Node); + } + } + } + node.Visited = true; + unvisited.Remove(node); + } + + var endNode = graph.Nodes.First(node => node.Planet == end); + var path = new List { endNode }; + while (endNode.Weight.Key != null) + { + endNode = endNode.Neighbours.OrderBy(edge => edge.Node.Weight.Value).First().Node; + path.Add(endNode); + } + + return path.Select(node => node.Planet).ToList(); + } } } diff --git a/src/Avans.FlatGalaxy.Simulation/PathFinding/PathFinder.cs b/src/Avans.FlatGalaxy.Simulation/PathFinding/PathFinder.cs index d764a5a..142563d 100644 --- a/src/Avans.FlatGalaxy.Simulation/PathFinding/PathFinder.cs +++ b/src/Avans.FlatGalaxy.Simulation/PathFinding/PathFinder.cs @@ -6,12 +6,13 @@ namespace Avans.FlatGalaxy.Simulation.PathFinding { public abstract class PathFinder { - protected abstract List Find(Planet start, Planet end); + protected abstract List Find(Planet start, Planet end, List planets); public List Get(ISimulator simulator) { - var stepPlanets = simulator.Galaxy.CelestialBodies.OfType().OrderByDescending(planet => planet.Radius).ToList(); - return stepPlanets.Count < 2 ? null : Find(stepPlanets[0], stepPlanets[1]); + var planets = simulator.Galaxy.CelestialBodies.OfType().ToList(); + var planets2 = planets.OrderByDescending(planet => planet.Radius).ToList(); + return planets2.Count < 2 ? null : Find(planets2[0], planets2[1], planets); } } } \ No newline at end of file diff --git a/src/Avans.FlatGalaxy.Simulation/Simulator.cs b/src/Avans.FlatGalaxy.Simulation/Simulator.cs index aaf6f8d..73daa99 100644 --- a/src/Avans.FlatGalaxy.Simulation/Simulator.cs +++ b/src/Avans.FlatGalaxy.Simulation/Simulator.cs @@ -122,8 +122,8 @@ private void Tick(CancellationToken token) _collisionHandler.Detect(this); - PathSteps = new BreadthFirstPathFinder().Get(this); - // PathSteps = new CheapestPathFinder().Get(this); + // PathSteps = new BreadthFirstPathFinder().Get(this); + PathSteps = new DijkstraPathFinder().Get(this); _lastTick = DateTime.UtcNow; if ((DateTime.UtcNow - _lastBookmark).TotalSeconds >= ISimulator.BookmarkTime)