mirror of
https://github.com/rjNemo/mars-rover-kata
synced 2026-06-06 02:36:48 +00:00
78 lines
2.2 KiB
Python
78 lines
2.2 KiB
Python
from dataclasses import dataclass, field
|
|
from typing import Tuple
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Coordinates:
|
|
x: int
|
|
y: int
|
|
left: str
|
|
right: str
|
|
|
|
|
|
@dataclass
|
|
class Rover:
|
|
x: int
|
|
y: int
|
|
direction: str
|
|
obstacles: list[list[int]] = field(default_factory=list)
|
|
|
|
valid_commands = ("F", "B", "R", "L")
|
|
|
|
direction_map = {
|
|
"NORTH": Coordinates(0, 1, "WEST", "EAST"),
|
|
"EAST": Coordinates(1, 0, "NORTH", "SOUTH"),
|
|
"SOUTH": Coordinates(0, -1, "EAST", "WEST"),
|
|
"WEST": Coordinates(-1, 0, "SOUTH", "NORTH"),
|
|
}
|
|
|
|
def is_valid_command(self, command: str) -> bool:
|
|
for ch in command:
|
|
if ch not in self.valid_commands:
|
|
return False
|
|
|
|
return True
|
|
|
|
def is_obstacle(self, x: int, y: int) -> bool:
|
|
return [x, y] in self.obstacles
|
|
|
|
def move(self, command: str):
|
|
if not self.is_valid_command(command):
|
|
raise ValueError("invalid command. The rover does not move")
|
|
|
|
for ch in command:
|
|
x, y, direction = self._compute_new_coordinates(ch)
|
|
if obstacle := self.is_obstacle(x, y):
|
|
return self._new_coordinates_output(obstacle)
|
|
|
|
self._apply_new_coordinates(x, y, direction)
|
|
|
|
return self._new_coordinates_output()
|
|
|
|
def _new_coordinates_output(self, obstacle: bool = False):
|
|
if obstacle:
|
|
return self.x, self.y, self.direction, "STOPPED"
|
|
return self.x, self.y, self.direction
|
|
|
|
def _compute_new_coordinates(self, command: str) -> Tuple[int, int, str]:
|
|
x = self.x
|
|
y = self.y
|
|
direction = self.direction
|
|
|
|
if command == "B":
|
|
x -= self.direction_map[self.direction].x
|
|
y -= self.direction_map[self.direction].y
|
|
if command == "F":
|
|
x += self.direction_map[self.direction].x
|
|
y += self.direction_map[self.direction].y
|
|
if command == "R":
|
|
direction = self.direction_map[self.direction].right
|
|
if command == "L":
|
|
direction = self.direction_map[self.direction].left
|
|
|
|
return x, y, direction
|
|
|
|
def _apply_new_coordinates(self, x: int, y: int, direction: str) -> None:
|
|
self.x = x
|
|
self.y = y
|
|
self.direction = direction
|