-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
139 lines (109 loc) · 4.59 KB
/
main.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
import numpy as np
CARDINAL_POINTS_ORDERED = ['N', 'E', 'S', 'W']
class Rover:
def __init__(self, plateau, pos_x: str, pos_y: str, cardinal_point: str):
self.plateau = plateau
self.pos_x = int(pos_x)
self.pos_y = int(pos_y)
self.cardinal_point = cardinal_point
def move(self, instructions: str) -> bool:
"""Moves the rover according to the given instructions"""
hit_limit = False
for instruction in instructions:
hit_limit = False
if instruction == 'L':
self._move_l()
elif instruction == 'R':
self._move_r()
elif instruction == 'M':
hit_limit = self._move_m()
else:
print(f'Wrong command for the rover, it will be ignored: {instruction}')
if hit_limit:
break
return hit_limit
def get_position(self) -> str:
"""Returns the position of the rover formatted"""
return f'{self.pos_x} {self.pos_y} {self.cardinal_point}'
def _move_l(self):
"""Makes the rover spin 90° to the left"""
current_idx = CARDINAL_POINTS_ORDERED.index(self.cardinal_point)
self.cardinal_point = CARDINAL_POINTS_ORDERED[current_idx - 1]
def _move_r(self):
"""Makes the rover spin 90° to the right"""
current_idx = CARDINAL_POINTS_ORDERED.index(self.cardinal_point)
next_idx = current_idx + 1 if current_idx != 3 else 0
self.cardinal_point = CARDINAL_POINTS_ORDERED[next_idx]
def _move_m(self) -> bool:
"""Moves the rover forward one grid point, if possible"""
next_x = self.pos_x
next_y = self.pos_y
hit_limit = False
if self.cardinal_point == 'N':
next_y += 1
elif self.cardinal_point == 'S':
next_y -= 1
elif self.cardinal_point == 'E':
next_x += 1
elif self.cardinal_point == 'W':
next_x -= 1
if self.plateau.is_valid_position(next_x, next_y):
self.pos_x = next_x
self.pos_y = next_y
else:
hit_limit = True
return hit_limit
class Plateau:
def __init__(self, upper: int, right: int):
self.max_y = int(upper)
self.max_x = int(right)
self.grid = np.zeros((self.max_x + 1, self.max_y + 1))
def save_rover_pos(self, pos_x: int, pos_y: int):
"""Save the position of the rover in the grid"""
self.grid[pos_x, pos_y] = 1
def is_valid_position(self, pos_x: int, pos_y: int) -> bool:
"""Checks if a position is valid: is inside of the grid and there's no obstacles in that position."""
if 0 <= pos_x <= self.max_x and 0 <= pos_y <= self.max_y:
valid = self.grid[pos_x, pos_y] == 0
else:
valid = False
return valid
class MarsMission:
def __init__(self, command_input: str):
self.command_input = command_input
self.plateau = None
self.output = ""
def start(self):
"""Starts the Mars Mission"""
commands = self._get_command_list()
self._initialize_plateau(commands.pop(0))
self._manage_rovers(commands)
def get_output(self) -> str:
"""Returns the output string of the mission """
return self.output
def _get_command_list(self) -> list:
"""Extracts a list of commands from the input command string"""
return self.command_input.splitlines()
def _initialize_plateau(self, plateau_coordinates: str):
"""Initializes de plateau with the given size"""
coordinates = plateau_coordinates.split(' ')
if len(coordinates) == 2 and all(num.isdigit() for num in coordinates):
self.plateau = Plateau(*coordinates)
else:
raise ValueError('Wrong input for plateau initialization')
def _manage_rovers(self, rover_commands: list):
"""Creates and manages the rovers according to the given commands"""
while rover_commands:
rover_coordinates = rover_commands.pop(0)
rover = Rover(self.plateau, *rover_coordinates.split(' '))
rover_instructions = rover_commands.pop(0)
limit_hit = rover.move(rover_instructions)
self.plateau.save_rover_pos(rover.pos_x, rover.pos_y)
if limit_hit:
print(f'Limit or obstacle hit, stopping rover')
self.output += rover.get_position() + "\n"
if __name__ == "__main__":
input_example = "5 5\n1 2 N\nLMLMLMLMM\n3 3 E\nMMRMMRMRRM"
mission = MarsMission(input_example)
mission.start()
print(mission.get_output())