You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+54-22
Original file line number
Diff line number
Diff line change
@@ -18,9 +18,32 @@ This is different because I refactored all the logic in propositional layers. Th
18
18
19
19
It comes with a `maze_solving_example.py` snippet to test the algorithm in a simple weighted maze ( with random weights ). If you run it you will obtain something like this:
20
20
21
-
<palign="center">
22
-
<imgsrc="./doc/sample.png">
23
-
</p>
21
+
```
22
+
$ python examples/maze_solving_example.py
23
+
↓ ↓ ← ← ← ← ← ← ← .
24
+
↓ ↓ ← ← ← ↑ ↑ ← ← .
25
+
↓ ↓ ← ← ← . . ↑ ← .
26
+
↓ ↓ ← ##########. . . ↑ .
27
+
→ S ← ##########. . . ↑ .
28
+
↑ ↑ ← ##########. . . ↑ .
29
+
↑ ↑ ← ##########. . → ↑ .
30
+
↑ ↑ ← ##########. . ↑ . .
31
+
↑ ↑ ← ##########. . E . .
32
+
↑ ↑ ← ##########. . . . .
33
+
34
+
5 4 5 6 7 8 9 10 11 .
35
+
4 3 4 5 10 10 10 11 12 .
36
+
3 2 3 4 11 . . 12 13 .
37
+
2 1 2 ##########. . . 14 .
38
+
1 S 1 ##########. . . 15 .
39
+
2 1 2 ##########. . . 16 .
40
+
3 2 3 ##########. . 18 17 .
41
+
4 3 4 ##########. . 19 . .
42
+
5 4 5 ##########. . E . .
43
+
6 5 6 ##########. . . . .
44
+
45
+
[...]
46
+
```
24
47
25
48
The first diagram represents where each point came from. Starting in the E ( standing for ENDING POINT) we backtrack each arrow untill we reach the S ( standing for STARTING POINT). This path is the shortest path. And you know what?
26
49
@@ -30,6 +53,8 @@ The arcane forces of A* make that if you start in a visited point and backtrack
30
53
31
54
The second diagram is the cost to reach each point from the START (S).
32
55
56
+
A third diagram, not shown here, will also be printed. This diagram shows the estimated total cost from START (S) to END (E) at each point, which is central to the efficiency of the A* algoritm as explained below.
57
+
33
58
# Can you EXPLAIN the algorithm?
34
59
35
60
Yeah! The idea of the A* algorithm is that starting from the start point we visit the points that are cheaper to visit. The cost of visiting a neighbor point depends on how costly is to go from the current point to a neighbor. So we check for all the points what is the neighbor that is cheaper to visit and we visit it.
This line creates a DijkstraHeap object and puts the starting point in it. We will see later how this can be implemented but the best part is that....This is not part of the algorithm! What is a DijkstraHeap then? This is a **cost queue** that has the following properties:
@@ -86,25 +114,26 @@ This line creates a DijkstraHeap object and puts the starting point in it. We wi
86
114
87
115
Cool! So this DijkstraHeap knows the visiting order of the elements. Its **like a heap but never pops an already visited element**.
88
116
89
-
By the way, a Node object is a tuple of the form ( cost_so_far, point, point_from_we_came ).
117
+
By the way, a Node object is a tuple of the form ( total_cost_estimate, point, point_from_we_came ).
90
118
91
119
```python
92
-
whilefrontier:
120
+
whileTrue:
93
121
```
94
122
95
-
We loop while we have elements in the queue.
96
-
97
-
98
-
At this point maybe you are asking yourself why the name `frontier`? Well, this is because when you are at the starting point and you visit neighbors, the queue of the nodes to be visited is like a expanding frontier (imagine a closed curve that becomes bigger and bigger in size). From which sides this frontier will expand first depends on the weights of the nodes among other things (like the distance to the ending point...etc).
123
+
We loop until we have found a path, or failed to find one by exhausting all elements in the queue.
99
124
100
125
```python
101
126
current_node = frontier.pop()
102
127
```
103
128
104
129
Each iteration we pop an element from the DijkstraHeap. This element always has the lowest cost element because the DijkstraHeap has this property ( because is a heap and heaps are awesome ).
105
130
131
+
At this point maybe you are asking yourself why the name `frontier`? Well, this is because when you are at the starting point and you visit neighbors, the queue of the nodes to be visited is like a expanding frontier (imagine a closed curve that becomes bigger and bigger in size). From which sides this frontier will expand first depends on the weights of the nodes among other things (like the distance to the ending point...etc).
132
+
106
133
```python
107
-
ifnot current_node or current_node.point == end:
134
+
if current_node isNone:
135
+
raiseValueError("No path exists")
136
+
if current_node.point == end:
108
137
return frontier
109
138
```
110
139
@@ -117,25 +146,28 @@ for neighbor in graph.neighbors( current_node.point ):
For each neighbor we calculate the new cost of reaching this neighbor from the current point. This cost is formed by three quantities:
131
161
132
-
1. The current cost of reaching the current point.
162
+
1. The cost of reaching the current point, which is the stored cost estimate minus the heuristic distance at that point (explained below).
133
163
2. The cost of going from the current point to the neighbor.
134
164
3. The distance of the neighbor to the end point that we are looking.
135
165
136
166
Why this 3rd cost? Because we want to explore first the points that are near the end destination and expend less time in the points that are far from it. So if we artificially give the point a higher cost if the point is far from the destination it will be visited later.
137
167
138
-
When we have calculated this new cost we insert the point in the cost queue.
168
+
The new cost is thus an estimate of the total cost, without knowing what lies ahead. It grows along the path as we encounter obstacles or higher-cost steps. It is essential that the heuristic never overestimates the remaining distance, otherwise the path is not necessarily optimal since the best path may not be visited before we find the end (and terminate).
169
+
170
+
When we have calculated this new cost estimate we insert the point in the cost queue.
0 commit comments