Skip to content

Commit ff1660c

Browse files
authored
Merge branch 'master' into directroy-tree-generator
2 parents 072a03a + cdbe7ef commit ff1660c

File tree

3 files changed

+105
-21
lines changed

3 files changed

+105
-21
lines changed

pyqt-calculator-tutorial/pycalc/LICENSE.txt

Lines changed: 0 additions & 21 deletions
This file was deleted.

python-heapq-module/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Finding the Shortest Path on a Map
2+
3+
Code supplementing the [Using the Python "heapq" Module and Priority Queues](https://realpython.com/python-heapq-module/) article.
4+
5+
## Usage
6+
7+
Run the following program:
8+
9+
```shell
10+
$ python shortest-path.py
11+
```
12+
13+
It will print out a map with the shortest path from the top-left corner to the bottom-right corner indicated with `@`.
14+
15+
## Changing the Map
16+
17+
In order to change the map the robot uses, modify the triple-quoted string that is assigned to `map` near the top of the file. Anything except `X` is interpreted as free from obstacles. Using `.` makes the map easier to read directly. You can make the map bigger, and a lot more complicated.
18+
19+
If there are so many obstacles that make finding a path from the top-left corner to the bottom right corner impossible, the program will raise an exception.
20+
21+
## Changing the Rules
22+
23+
If you want to play around with the code, here are some changes that you can make:
24+
25+
* How would you change the code so that the robot cannot go diagonally?
26+
* How would you change the code so that the robot can only move right or down, but never left or up?
27+
* (Harder) How would you change the code so that every step consumes energy, squares with `*` give energy, and the robot cannot move if it is out of energy?
28+
* (Challenge) How would you change the code so that areas marked with `#` are not obstacles, but take twice as long to move through?

python-heapq-module/shortest-path.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import heapq
2+
3+
4+
map = """\
5+
.......X..
6+
.......X..
7+
....XXXX..
8+
..........
9+
..........
10+
"""
11+
12+
13+
def parse_map(map):
14+
lines = map.splitlines()
15+
origin = 0, 0
16+
destination = len(lines[-1]) - 1, len(lines) - 1
17+
return lines, origin, destination
18+
19+
20+
def is_valid(lines, position):
21+
x, y = position
22+
if not (0 <= y < len(lines) and 0 <= x < len(lines[y])):
23+
return False
24+
if lines[y][x] == "X":
25+
return False
26+
return True
27+
28+
29+
def get_neighbors(lines, current):
30+
x, y = current
31+
for dx in [-1, 0, 1]:
32+
for dy in [-1, 0, 1]:
33+
if dx == 0 and dy == 0:
34+
continue
35+
position = x + dx, y + dy
36+
if is_valid(lines, position):
37+
yield position
38+
39+
40+
def get_shorter_paths(tentative, positions, through):
41+
path = tentative[through] + [through]
42+
for position in positions:
43+
if position in tentative and len(tentative[position]) <= len(path):
44+
continue
45+
yield position, path
46+
47+
48+
def find_path(map):
49+
lines, origin, destination = parse_map(map)
50+
tentative = {origin: []}
51+
candidates = [(0, origin)]
52+
certain = set()
53+
while destination not in certain and len(candidates) > 0:
54+
_ignored, current = heapq.heappop(candidates)
55+
if current in certain:
56+
continue
57+
certain.add(current)
58+
neighbors = set(get_neighbors(lines, current)) - certain
59+
shorter = get_shorter_paths(tentative, neighbors, current)
60+
for neighbor, path in shorter:
61+
tentative[neighbor] = path
62+
heapq.heappush(candidates, (len(path), neighbor))
63+
if destination in tentative:
64+
return tentative[destination] + [destination]
65+
else:
66+
raise ValueError("no path")
67+
68+
69+
def show_path(path, map):
70+
lines = map.splitlines()
71+
for x, y in path:
72+
lines[y] = lines[y][:x] + "@" + lines[y][x + 1 :]
73+
return "\n".join(lines) + "\n"
74+
75+
76+
path = find_path(map)
77+
print(show_path(path, map))

0 commit comments

Comments
 (0)