-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmazeChar.py
195 lines (174 loc) · 7.33 KB
/
mazeChar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# Maze Mode File
# image from
# https://github.com/ZiadElGafy/Fireboy-And-Watergirl/tree/master/assets/graphics
from cmu_112_graphics import *
import random
import maze as mz
NORTH = (0,-1)
SOUTH = (0,1)
WEST = (-1,0)
EAST = (1,0)
def manhattanDistance(ax,ay,bx,by):
return abs(ax-bx) + abs(ay-by)
def findShortestMD(ax,ay,positionList): # best template to find nearest target
bestx,besty = 1000,1000
bestMD = 1000
for bx,by in positionList:
currMD = manhattanDistance(ax,ay,bx,by)
if currMD < bestMD:
bestMD = currMD
bestx,besty = bx,by
return bestx,besty
class Char(object):
def __init__(self,px,py,element): # position expressed as grid, color decides image
self.px = px
self.py = py
self.element = element
self.image = ''
self.doorImage = ''
self.gemImage = ''
self.gemPosition = []
self.doorPosition = []
self.doorOpen = False
self.path = []
self.hint = 3
self.hintOn = False
self.hintCount = 0
self.win = False
def mazeAppRun(self,app): # put under appStarted
if self.element == 'fire':
self.image = app.scaleImage(app.loadImage('fireBoy.png'),0.3)
self.doorImage = app.scaleImage(app.loadImage('firedoormaze.png'),0.3)
self.gemImage = app.scaleImage(app.loadImage('redGem.png'),0.4)
else:
self.image = app.scaleImage(app.loadImage('waterGirl.png'),0.3)
self.doorImage = app.scaleImage(app.loadImage('waterdoormaze.png'),0.3)
self.gemImage = app.scaleImage(app.loadImage('blueGem.png'),0.4)
### random gem generation ###
randEmpty = []
for i in range(app.maze.row):
for j in range(app.maze.col):
if (manhattanDistance(1,1,i,j) > 8 and i > 1 and j > 1
and i < app.maze.row-1 and j < app.maze.col-1 and app.maze.maze[i][j] != 1):
randEmpty.append((i,j))
while len(self.gemPosition) < 5: # could be changed according to difficulty
g = random.choice(randEmpty)
while g in self.gemPosition:
g = random.choice(randEmpty)
self.gemPosition.append(g)
### random door generation ###
randDoor = []
for i in range(app.maze.row):
for j in range(app.maze.col):
if (i == 0 or i == app.maze.row-1) or (j == 0 or j == app.maze.col-1):
if self.element == 'fire':
if manhattanDistance(1,1,i,j) > 14:
randDoor.append((i,j))
elif self.element == 'water':
if manhattanDistance(1,app.maze.col-1,i,j) > 14:
randDoor.append((i,j))
dx,dy = random.choice(randDoor)
while isNotValid(app,dx,dy):
dx,dy = random.choice(randDoor) # make sure the door can be reached
self.doorPosition.append((dx,dy))
app.maze.maze[dx][dy] = 9 # represent door
def mazeCharKeyPressed(self,app,event): # put under keyPressed
if self.element == 'fire':
dx,dy = 0,0
if event.key == 'Up':
dx,dy = NORTH
elif event.key == 'Down':
dx,dy = SOUTH
elif event.key == 'Left':
dx,dy = WEST
elif event.key == 'Right':
dx,dy = EAST
row = self.px + dx
col = self.py + dy
if not(row < 0 or row > app.maze.row-1 or
col < 0 or col > app.maze.col - 1 or app.maze.maze[row][col] == 1):
self.px = row
self.py = col
if event.key == '1' and self.hint > 0: # draw hint line
self.hintOn = True
if self.element == 'water':
dx,dy = 0,0
if event.key == 'w':
dx,dy = NORTH
elif event.key == 's':
dx,dy = SOUTH
elif event.key == 'a':
dx,dy = WEST
elif event.key == 'd':
dx,dy = EAST
row = self.px + dx
col = self.py + dy
if not(row < 0 or row > app.maze.row-1 or
col < 0 or col > app.maze.col - 1 or app.maze.maze[row][col] ==1):
self.px = row
self.py = col
if event.key == 'h' and self.hint > 0:
self.hintOn = True
def eatGem(self):
if len(self.gemPosition) == 0:
dx,dy = self.doorPosition[0]
self.doorOpen = True
if self.px ==dx and self.py == dy:
self.win = True
else:
for gx, gy in self.gemPosition:
if gx == self.px and gy == self.py:
self.gemPosition.remove((gx,gy))
def hintCounter(self,app):
if self.hintOn:
self.hintCount += 1
if self.hintCount > 30:
self.hintCount = 0
self.hintOn =False
self.hint -= 1
def placeChar(self,app):
for i in range(app.maze.row):
for j in range(app.maze.col):
if self.element == 'fire':
if app.maze.maze[i][j] == 5 and (i != self.px or j != self.py):
# occupied by fireBoy but char not on this spot
app.maze.maze[i][j] = 0
elif app.maze.maze[i][j] == 0 and i == self.px and j == self.py:
app.maze.maze[i][j] = 5 # occupuied by fireBoy (5)
elif self.element == 'water':
if app.maze.maze[i][j] == 8 and (i != self.px or j != self.py):
# occupied by waterGirl but char not on this spot
app.maze.maze[i][j] = 0
elif app.maze.maze[i][j] == 0 and i == self.px and j == self.py:
app.maze.maze[i][j] = 8 # occupuied by waterGirl (8)
def findTarget(self):
if self.doorOpen == False:
return findShortestMD(self.px,self.py,self.gemPosition)
else:
dx,dy = self.doorPosition[0]
if dx ==0:
dx = 1
elif dx == self.maze.row-1:
dx = self.maze.row-2
elif dy == 0:
dy = 1
elif dy == self.maze.col-1:
dy = self.maze.col-2
return dx,dy
def solvePath(self,app):
startRow = self.px
startCol = self.py
endRow,endCol = self.findTarget()
self.path = mz.solveMaze(app,startRow,startCol,endRow,endCol)
def isNotValid(app,dx,dy): # helper that tells if the door is not valid
if dx == 0:
if app.maze.maze[dx+1][dy] == 1: return True # not valid
elif dx == app.maze.col-1:
if app.maze.maze[dx-1][dy] == 1: return True
elif dy == 0:
if app.maze.maze[dx][dy+1] == 1: return True
elif dy == app.maze.row-1 :
if app.maze.maze[dx][dy-1] == 1: return True
elif dx==dy or (dx==app.maze.row-1 and dy == 0) or (dy == app.maze.col-1 and dx == 0):
return True # on the corner
return False