1 """Some handy algorithms for use in games, etc.
3 <p>please note that this file is alpha, and is subject to modification in
4 future versions of pgu!</p>
7 # The manhattan distance metric
8 def manhattan_dist(a
,b
):
9 return abs(a
[0]-b
[0]) + abs(a
[1]-b
[1])
12 def __init__(self
, prev
, pos
, dest
, dist
):
13 self
.prev
,self
.pos
,self
.dest
= prev
,pos
,dest
14 if self
.prev
== None: self
.g
= 0
15 else: self
.g
= self
.prev
.g
+ 1
16 self
.h
= dist(pos
,dest
)
17 self
.f
= self
.g
+self
.h
20 def astar(start
,end
,layer
,dist
=manhattan_dist
):
21 """uses the a* algorithm to find a path
23 <pre>astar(start,end,layer,dist): return [list of positions]</pre>
26 <dt>start<dd>start position
27 <dt>end<dd>end position
28 <dt>layer<dd>a grid where zero cells are open and non-zero cells are walls
29 <dt>dist<dd>a distance function dist(a,b) - manhattan distance is used by default
32 <p>returns a list of positions from start to end</p>
35 w
,h
= len(layer
[0]),len(layer
)
36 if start
[0] < 0 or start
[1] < 0 or start
[0] >= w
or start
[1] >= h
:
37 return [] #start outside of layer
38 if end
[0] < 0 or end
[1] < 0 or end
[0] >= w
or end
[1] >= h
:
39 return [] #end outside of layer
41 if layer
[start
[1]][start
[0]]:
42 return [] #start is blocked
43 if layer
[end
[1]][end
[0]]:
44 return [] #end is blocked
49 cur
= node(None, start
, end
, dist
)
54 if cur
.pos
not in open: continue
57 if cur
.pos
== end
: break
58 for dx
,dy
in [(0,-1),(1,0),(0,1),(-1,0)]:#(-1,-1),(1,-1),(-1,1),(1,1)]:
59 pos
= cur
.pos
[0]+dx
,cur
.pos
[1]+dy
60 # Check if the point lies in the grid
61 if (pos
[0] < 0 or pos
[1] < 0 or
62 pos
[0] >= w
or pos
[1] >= h
or
63 layer
[pos
[0]][pos
[1]]):
65 #check for blocks of diagonals
66 if layer
[cur
.pos
[1]+dy
][cur
.pos
[0]]: continue
67 if layer
[cur
.pos
[1]][cur
.pos
[0]+dx
]: continue
68 new
= node(cur
, pos
, end
, dist
)
69 if pos
in open and new
.f
>= open[pos
].f
: continue
70 if pos
in closed
and new
.f
>= closed
[pos
].f
: continue
71 if pos
in open: del open[pos
]
72 if pos
in closed
: del closed
[pos
]
78 if new
.f
< opens
[mid
].f
: hi
= mid
86 while cur
.prev
!= None:
94 """returns a path of points from a to b
96 <pre>getline(a,b): return [list of points]</pre>
99 <dt>a<dd>starting point
100 <dt>b<dd>ending point
103 <p>returns a list of points from a to b</p>
110 dx
,dy
= abs(x2
-x1
),abs(y2
-y1
)
112 if x2
>= x1
: xi1
,xi2
= 1,1
113 else: xi1
,xi2
= -1,-1
115 if y2
>= y1
: yi1
,yi2
= 1,1
116 else: yi1
,yi2
= -1,-1