-
Notifications
You must be signed in to change notification settings - Fork 1
/
Karel.py
428 lines (346 loc) · 11.6 KB
/
Karel.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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
"""
This file defines the Karel class, which provides the actual
implementation of all functions described in the Karel Reference
Guide.
All instances of a Karel object store a reference to the world
in which they exist. Each Karel object exists on a given
(avenue, street) intersection and holds a certain number of beepers
in its beeper bag.
Original Author: Nicholas Bowman
Credits: Kylie Jue
License: MIT
Version: 1.0.0
Email: nbowman@stanford.edu
Date of Creation: 10/1/2019
Last Modified: 3/31/2020
"""
from karel.kareldefinitions import *
class Karel():
def __init__(self, world):
"""
This functions instantiates a new Karel instance and sets its
location and current number of beepers to be the default starting
values as indicated by the given world object.
Parameters:
world (KarelWorld) - The world that Karel should exists in
Returns: None
"""
self._world = world
self._avenue, self._street = self._world.karel_starting_location
self._direction = self._world.karel_starting_direction
self._num_beepers = self._world.karel_starting_beeper_count
@property
def avenue(self):
"""
This property can be used to access Karel's current avenue location.
Parameters: None
Returns:
avenue (int) - The current avenue Karel is standing on.
"""
return self._avenue
@avenue.setter
def avenue(self, val):
"""
This property can be used to set Karel's current avenue location.
Parameters:
val (int) - The new avenue that Karel will be standing on.
Returns: None
"""
self._avenue = val
@property
def street(self):
"""
This property can be used to access Karel's current street location.
Parameters: None
Returns:
street (int) - The current street Karel is standing on.
"""
return self._street
@street.setter
def street(self, val):
"""
This property can be used to set Karel's current street location.
Parameters:
val (int) - The new street that Karel will be standing on.
Returns: None
"""
self._street = val
@property
def direction(self):
"""
This property can be used to access Karel's current direction.
Parameters: None
Returns:
street (Direction[Enum]) - The current direction Karel is facing.
"""
return self._direction
@direction.setter
def direction(self, val):
"""
This property can be used to set Karel's current direction.
Parameters:
val (Direction[Enum]) - The new direction that Karel will be facing.
Returns: None
"""
self._direction = val
@property
def num_beepers(self):
"""
This property can be used to access Karel's current number of beepers.
Parameters: None
Returns:
num_beepers (int) - The current number of beepers Karel has.
"""
return self._num_beepers
@num_beepers.setter
def num_beepers(self, val):
"""
This property can be used to set Karel's current number of beepers.
Parameters:
val (int) - The new number of beepers that Karel will have.
Returns: None
"""
self._num_beepers = val
def reset_state(self):
"""
This function is used to reset Karel's location and direction to the original
starting parameters as indicated by the world that Karel lives in.
Parameters: None
Returns: None
"""
self._avenue, self._street = self._world.karel_starting_location
self._direction = self._world.karel_starting_direction
self._num_beepers = self._world.karel_starting_beeper_count
def move(self):
"""
This function moves Karel forward one space in the direction that it is
currently facing. If Karel's front is not clear (blocked by wall or boundary
of world) then a KarelException will be raised).
Parameters: None
Returns: None
"""
if not self.front_is_clear():
raise KarelException(self._avenue, self._street, self._direction,
"Karel attempted to move, but its front was blocked.")
delta_avenue, delta_street = DIRECTION_DELTA_MAP[self._direction]
self._avenue += delta_avenue
self._street += delta_street
def turn_left(self):
"""
This function turns Karel 90 degrees counterclockwise.
Parameters: None
Returns: None
"""
self._direction = NEXT_DIRECTION_MAP[self._direction]
def put_beeper(self):
"""
This function places a beeper on the corner that Karel is currently standing
on and decreases Karel's beeper count by 1. If Karel has no more beepers in its
beeper bag, then this function raises a KarelException.
Parameters: None
Returns: None
"""
if self._num_beepers == 0:
raise KarelException(self._avenue, self._street, self._direction,
"Karel attempted to put a beeper, but it had none left in its bag.")
if self._num_beepers != INFINITY:
self._num_beepers -= 1
self._world.add_beeper(self._avenue, self._street)
def pick_beeper(self):
"""
This function removes a beeper from the corner that Karel is currently standing on
and increases Karel's beeper count by 1. If there are no beepers on Karel's current
corner, then this function raises a KarelException.
Parameters: None
Returns: None
"""
if not self.beepers_present():
raise KarelException(self._avenue, self._street, self._direction,
"Karel attempted to pick up a beeper, but there were none on the current corner.")
if self._num_beepers != INFINITY:
self._num_beepers += 1
self._world.remove_beeper(self._avenue, self._street)
def front_is_clear(self):
"""
This function returns a boolean indicating whether or not there is a wall
in front of Karel.
Parameters: None
Returns:
is_clear (Bool) - True if there is no wall in front of Karel
False otherwise
"""
return self.direction_is_clear(self._direction)
def direction_is_clear(self, direction):
"""
This is a helper function that returns a boolean indicating whether
or not there is a barrier in the specified direction of Karel.
Parameters:
direction (Direction[Enum]) - The direction in which to check for a barrier
Returns:
is_clear (Bool) - True if there is no barrier in the specified direction
False otherwise
"""
delta_avenue, delta_street = DIRECTION_DELTA_MAP[direction]
next_avenue = self._avenue + delta_avenue
next_street = self._street + delta_street
opposite_direction = NEXT_DIRECTION_MAP[NEXT_DIRECTION_MAP[direction]]
# front is not clear if we are about to go out of bounds
if not self._world.in_bounds(next_avenue, next_street):
return False
# front is not clear if wall exists in same direction of where we're currently facing
if self._world.wall_exists(self._avenue, self._street, direction):
return False
# must also check for alternate possible representation of wall
if self._world.wall_exists(next_avenue, next_street, opposite_direction):
return False
# If all previous conditions checked out, then the front is clear
return True
def front_is_blocked(self):
"""
This function returns a boolean indicating whether there is a wall
in front of Karel.
Parameters: None
Returns:
is_blocked (Bool) - True if there is a wall in front of Karel
False otherwise
"""
return not self.front_is_clear()
def left_is_clear(self):
"""
This function returns a boolean indicating whether or not there is a wall
to the left of Karel.
Parameters: None
Returns:
is_clear (Bool) - True if there is no wall to the left of Karel
False otherwise
"""
return self.direction_is_clear(NEXT_DIRECTION_MAP[self._direction])
def left_is_blocked(self):
"""
This function returns a boolean indicating whether there is a wall
to the left of Karel.
Parameters: None
Returns:
is_blocked (Bool) - True if there is a wall to the left of Karel
False otherwise
"""
return not self.left_is_clear()
def right_is_clear(self):
"""
This function returns a boolean indicating whether or not there is a wall
to the right of Karel.
Parameters: None
Returns:
is_clear (Bool) - True if there is no wall to the right of Karel
False otherwise
"""
return self.direction_is_clear(NEXT_DIRECTION_MAP_RIGHT[self._direction])
def right_is_blocked(self):
"""
This function returns a boolean indicating whether there is a wall
to the right of Karel.
Parameters: None
Returns:
is_blocked (Bool) - True if there is a wall to the right of Karel
False otherwise
"""
return not self.right_is_clear()
def beepers_present(self):
"""
This function returns a boolean indicating whether or not there is
a beeper on Karel's current corner.
Parameters: None
Returns:
beeepers_on_corner (Bool) - True if there is at least one beeper on Karel's current corner
False otherwise
"""
return self._world.beepers[(self.avenue, self.street)] != 0
def no_beepers_present(self):
return not self.beepers_present()
def beepers_in_bag(self):
"""
This function returns a boolean indicating whether or not there is
at least one beeper in Karel's beeper bag.
Parameters: None
Returns:
beepers_in_bag (Bool) - True if there is at least one beeper in Karel's bag
False otherwise
"""
# Can't check > 0 because INFINITY beepers is -1
return self._num_beepers != 0
def no_beepers_in_bag(self):
# Only 0 beepers in bag indicates empty bag – negative numbers represent INFINITY
return self._num_beepers == 0
def facing_north(self):
"""
This function returns a boolean indicating whether or not Karel is currently
facing North.
Parameters: None
Returns:
facing_north (Bool) - True if Karel is currently facing North
False otherwise
"""
return self.direction == Direction.NORTH
def not_facing_north(self):
return not self.facing_north()
def facing_east(self):
"""
This function returns a boolean indicating whether or not Karel is currently
facing East.
Parameters: None
Returns:
facing_east (Bool) - True if Karel is currently facing East
False otherwise
"""
return self.direction == Direction.EAST
def not_facing_east(self):
return not self.facing_east()
def facing_west(self):
"""
This function returns a boolean indicating whether or not Karel is currently
facing West.
Parameters: None
Returns:
facing_west (Bool) - True if Karel is currently facing West
False otherwise
"""
return self.direction == Direction.WEST
def not_facing_west(self):
return not self.facing_west()
def facing_south(self):
"""
This function returns a boolean indicating whether or not Karel is currently
facing South.
Parameters: None
Returns:
facing_south (Bool) - True if Karel is currently facing South
False otherwise
"""
return self.direction == Direction.SOUTH
def not_facing_south(self):
return not self.facing_south()
def paint_corner(self, color):
"""
This function makes Karel paint it's current corner the indicated color.
This function will raise a KarelExcpetion if the indicated color is not one
of the valid predefined colors. For this list of colors, check the
kareldefinitions.py file.
Parameters:
color (str) - The color string specifying which color to paint the corner
Returns: None
"""
if color and color not in COLOR_MAP.values():
raise KarelException(self._avenue, self._street, self._direction,
f"Karel attempted to paint the corner with color {color}, which is not valid.")
self._world.paint_corner(self.avenue, self.street, color)
def corner_color_is(self, color):
"""
This function returns a boolean indicating whether or not Karel's current
corner is the specified color.
Parameters:
color (str) - Color string representing the color to check the current corner for
Returns:
is_color (Bool) - True if Karel's current corner is the specified color
False otherwise
"""
return self._world.corner_color(self.avenue, self.street) == color