feat: added live coding features - obstacles and half-directions.

This commit is contained in:
Chris Davoren 2023-11-15 12:32:08 +10:00
parent aff508d835
commit 9abe516ec7
4 changed files with 87 additions and 14 deletions

11
example_e.txt Normal file
View File

@ -0,0 +1,11 @@
BLOCK 2,2
BLOCK 3,2
PLACE 1,2,EAST
BLOCK 1,2
MOVE
LEFT
MOVE
REPORT
PLACE 3,1
MOVE
REPORT

6
example_f.txt Normal file
View File

@ -0,0 +1,6 @@
BLOCK 0,4,ghjghjhg,hjghjgjhdts
PLACE 1,2,NORTHWEST
MOVE
RIGHT
MOVE
REPORT

View File

@ -26,12 +26,17 @@ class Robot:
# Directions ordered such that adding 1 corresponds to RIGHT turn # Directions ordered such that adding 1 corresponds to RIGHT turn
DIRECTIONS = { DIRECTIONS = {
"NORTH": 0, "NORTH": 0,
"EAST": 1, "NORTHEAST": 1,
"SOUTH": 2, "EAST": 2,
"WEST": 3, "SOUTHEAST": 3,
"SOUTH": 4,
"SOUTHWEST": 5,
"WEST": 6,
"NORTHWEST": 7
} }
VALID_COMMANDS = [ VALID_COMMANDS = [
"BLOCK",
"PLACE", "PLACE",
"MOVE", "MOVE",
"LEFT", "LEFT",
@ -45,9 +50,13 @@ class Robot:
# positive y is EAST) # positive y is EAST)
_MOVEMENT_VECTORS = { _MOVEMENT_VECTORS = {
0: {"x": 0, "y": 1}, 0: {"x": 0, "y": 1},
1: {"x": 1, "y": 0}, 1: {"x": 1, "y": 1},
2: {"x": 0, "y": -1}, 2: {"x": 1, "y": 0},
3: {"x": -1, "y": 0}, 3: {"x": 1, "y": -1},
4: {"x": 0, "y": -1},
5: {"x": -1, "y": -1},
6: {"x": -1, "y": 0},
7: {"x": -1, "y": 1},
} }
def __init__(self, max_x: int = DEFAULT_MAX_X, max_y: int = DEFAULT_MAX_Y): def __init__(self, max_x: int = DEFAULT_MAX_X, max_y: int = DEFAULT_MAX_Y):
@ -79,6 +88,8 @@ class Robot:
self._position_y = None self._position_y = None
self._direction = None self._direction = None
self._blocks = []
def valid_position(self, x: int, y: int) -> bool: def valid_position(self, x: int, y: int) -> bool:
""" """
Calculates whether the given coordinates are valid for the limits set Calculates whether the given coordinates are valid for the limits set
@ -95,7 +106,18 @@ class Robot:
bool: True if given coordinates are within limits, otherwise False. bool: True if given coordinates are within limits, otherwise False.
""" """
return x >= 0 and y >= 0 and x <= self._max_x and y <= self._max_y within_limits = x >= 0 and y >= 0 and x <= self._max_x and y <= self._max_y
on_block = (x, y) in self._blocks
# print(self._blocks)
# print(within_limits)
# print(on_block)
return within_limits and not on_block
def add_block(self, x: int, y: int):
if x == self._position_x and y == self._position_y:
return
self._blocks.append((x, y))
def is_initialized(self): def is_initialized(self):
""" """
@ -159,8 +181,10 @@ class Robot:
# Must be careful not to make any state changes until all inputs # Must be careful not to make any state changes until all inputs
# have been validated # have been validated
# print('Checking position...')
if not self.valid_position(position_x, position_y): if not self.valid_position(position_x, position_y):
return return
# print('Position check passed.')
if direction_name is not None: if direction_name is not None:
direction_name = direction_name.upper() direction_name = direction_name.upper()
@ -220,7 +244,7 @@ class Robot:
if not self.is_initialized(): if not self.is_initialized():
return return
self._direction = (self._direction - 1) % 4 self._direction = (self._direction - 1) % len(Robot.DIRECTIONS)
def rotate_right(self): def rotate_right(self):
""" """
@ -234,7 +258,7 @@ class Robot:
if not self.is_initialized(): if not self.is_initialized():
return return
self._direction = (self._direction + 1) % 4 self._direction = (self._direction + 1) % len(Robot.DIRECTIONS)
def interpret_command(self, command: str): def interpret_command(self, command: str):
""" """
@ -252,11 +276,32 @@ class Robot:
command = command.upper() command = command.upper()
command_tokens = [x.strip() for x in command.split(' ') if len(x) > 0] command_tokens = [x.strip() for x in command.split(' ') if len(x) > 0]
# This is not strictly necessary as case
if len(command_tokens) == 0 or not command_tokens[0] in \ if len(command_tokens) == 0 or not command_tokens[0] in \
Robot.VALID_COMMANDS: Robot.VALID_COMMANDS:
return return
match command_tokens[0]: match command_tokens[0]:
case "BLOCK":
# print('Found block...')
try:
if len(command_tokens) < 2:
# print('Insufficient tokens...')
return
parameter_tokens = [x.strip() for x in command_tokens[1].split(',')]
if len(parameter_tokens) < 2:
# print('Insufficient parameters...')
return
block_x = int(parameter_tokens[0])
block_y = int(parameter_tokens[1])
# print("Adding block: {} {}".format(block_x, block_y))
self.add_block(block_x, block_y)
except ValueError as ve:
# print('Integer parsing error...')
return
case "PLACE": case "PLACE":
try: try:
# Must have parameters # Must have parameters
@ -276,6 +321,7 @@ class Robot:
# Direction parameter is optional on second and subsequent # Direction parameter is optional on second and subsequent
# placements. The place() method accounts for an absent # placements. The place() method accounts for an absent
# direction on first call and fails silently. # direction on first call and fails silently.
# print("PLACE command parsed: {}, {}".format(place_x, place_y))
if len(parameter_tokens) > 2: if len(parameter_tokens) > 2:
place_direction = parameter_tokens[2] place_direction = parameter_tokens[2]
self.place(place_x, place_y, place_direction) self.place(place_x, place_y, place_direction)
@ -305,8 +351,9 @@ class Robot:
if not self.is_initialized(): if not self.is_initialized():
return "Uninitialized" return "Uninitialized"
return "{},{},{}".format( return "{},{},{} | BLOCKS : {}".format(
self._position_x, self._position_x,
self._position_y, self._position_y,
self.get_direction() self.get_direction(),
":".join([str(x) for x in self._blocks])
) )

View File

@ -2,6 +2,7 @@
import toyrobot import toyrobot
def feed_file(filename: str, robot: toyrobot.Robot): def feed_file(filename: str, robot: toyrobot.Robot):
with open(filename) as f: with open(filename) as f:
for line in f: for line in f:
@ -9,6 +10,7 @@ def feed_file(filename: str, robot: toyrobot.Robot):
print(line) print(line)
robot.interpret_command(line) robot.interpret_command(line)
def main(): def main():
print('a)') print('a)')
feed_file('example_a.txt', toyrobot.Robot()) feed_file('example_a.txt', toyrobot.Robot())
@ -26,5 +28,12 @@ def main():
feed_file('example_d.txt', toyrobot.Robot()) feed_file('example_d.txt', toyrobot.Robot())
print() print()
print('e)')
feed_file('example_e.txt', toyrobot.Robot())
print()
print('f)')
feed_file('example_f.txt', toyrobot.Robot())
print()
if __name__ == "__main__": if __name__ == "__main__":
main() main()