From 3cccdc7eb80d1dea7fc51501fa6d74684f1f1bc2 Mon Sep 17 00:00:00 2001 From: Karma Riuk Date: Tue, 15 Aug 2023 17:22:10 +0200 Subject: [PATCH] feat: implememented dijkstra algorithm --- solver/dijkstra.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ solver/solver.go | 8 +++-- 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 solver/dijkstra.go diff --git a/solver/dijkstra.go b/solver/dijkstra.go new file mode 100644 index 0000000..68fac5e --- /dev/null +++ b/solver/dijkstra.go @@ -0,0 +1,85 @@ +package solver + +import ( + "maze-solver/maze" + "maze-solver/utils" + "slices" + "sort" +) + +type DijkstraSolver struct { + dist_from_start map[*maze.Node]int + parent map[*maze.Node]*maze.Node + stack sorted_stack +} + +type sorted_stack []*maze.Node + +func (s *DijkstraSolver) Solve(m *maze.Maze) *maze.SolvedMaze { + defer utils.Timer("Dijkstra algorithm", 2)() + s.dist_from_start = make(map[*maze.Node]int, len(m.Nodes)) + s.parent = make(map[*maze.Node]*maze.Node, len(m.Nodes)) + + for _, node := range m.Nodes { + s.dist_from_start[node] = 0 + } + + current, end := m.Nodes[0], m.Nodes[len(m.Nodes)-1] + + for current != end { + current.Visited = true + + for _, child := range []*maze.Node{current.Left, current.Right, current.Up, current.Down} { + if child != nil { + dist := s.dist_from_start[current] + int(current.Coords.Distance(child.Coords)) + if !child.Visited { + s.parent[child] = current + s.dist_from_start[child] = dist + s.stack.insert(child, &s.dist_from_start) + } else if s.dist_from_start[child] > dist { + s.parent[child] = current + s.dist_from_start[child] = dist + sort.Slice(s.stack, func(i, j int) bool { + return s.dist_from_start[s.stack[i]] < s.dist_from_start[s.stack[j]] + }) + } + } + } + current = s.stack.pop() + } + + solution := make([]*maze.Node, 0, len(m.Nodes)) + for current != m.Nodes[0] { + solution = append(solution, current) + current = s.parent[current] + } + solution = append(solution, m.Nodes[0]) + + for i, j := 0, len(solution)-1; i < j; i, j = i+1, j-1 { + solution[i], solution[j] = solution[j], solution[i] + } + + return &maze.SolvedMaze{ + Maze: m, + Solution: solution, + } +} + +func (s *sorted_stack) insert(node *maze.Node, dists *map[*maze.Node]int) { + var dummy *maze.Node + *s = append(*s, dummy) // extend the slice + + i, _ := slices.BinarySearchFunc(*s, node, func(e, t *maze.Node) int { + return (*dists)[t] - (*dists)[e] + }) + + copy((*s)[i+1:], (*s)[i:]) // make room + (*s)[i] = node +} + +func (s *sorted_stack) pop() *maze.Node { + last_i := len(*s) - 1 + ret := (*s)[last_i] + *s = (*s)[:last_i] + return ret +} diff --git a/solver/solver.go b/solver/solver.go index 80186f0..bb985c4 100644 --- a/solver/solver.go +++ b/solver/solver.go @@ -14,13 +14,15 @@ type SolverFactory struct { } const ( - _DFS = "dfs" - _BFS = "bfs" + _DFS = "dfs" + _BFS = "bfs" + _Dijkstra = "dijkstra" ) var TYPES = []string{ _DFS, _BFS, + _Dijkstra, } func (f *SolverFactory) Get() Solver { @@ -29,6 +31,8 @@ func (f *SolverFactory) Get() Solver { return &DFSSolver{} case _BFS: return &BFSSolver{} + case _Dijkstra: + return &DijkstraSolver{} } panic(fmt.Sprintf("Unrecognized solver type %q", *f.Type)) }