kata/rover/rover.py

97 lines
2.3 KiB
Python
Raw Normal View History

2019-11-15 20:43:59 +01:00
import enum
from copy import deepcopy
from typing import List
2019-11-15 20:29:06 +01:00
from pydantic import BaseModel, validator
2019-11-15 20:29:06 +01:00
class Vector(BaseModel):
x: int = 0
y: int = 0
2019-11-15 20:34:34 +01:00
@validator("x")
def _x_must_be_positive(x):
if x < 0:
raise ValueError("x must be positive")
return x
@validator("y")
def _y_must_be_positive(y):
if y < 0:
raise ValueError("y must be positive")
return y
2019-11-15 20:34:34 +01:00
2019-11-15 20:43:59 +01:00
class Direction(enum.Enum):
NORTH = "N"
SOUTH = "S"
EAST = "E"
WEST = "W"
class ObstacleError(RuntimeError):
pass
2019-11-15 21:29:37 +01:00
DIRECTIONS = [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST]
class Rover(BaseModel):
pos: Vector = Vector(x=0, y=0)
planet_size: Vector = Vector(x=100, y=100)
2019-11-15 20:43:59 +01:00
dir: Direction = Direction.NORTH
2019-11-15 21:20:42 +01:00
def _translate(self, value):
if self.dir == Direction.NORTH:
2019-11-15 21:20:42 +01:00
self.pos.y += value
elif self.dir == Direction.SOUTH:
2019-11-15 21:20:42 +01:00
self.pos.y -= value
elif self.dir == Direction.EAST:
2019-11-15 21:20:42 +01:00
self.pos.x += value
elif self.dir == Direction.WEST:
2019-11-15 21:20:42 +01:00
self.pos.x -= value
2019-11-15 21:12:51 +01:00
if self.pos.x < 0:
self.pos.x += self.planet_size.x
if self.pos.y < 0:
self.pos.y += self.planet_size.y
self.pos.x %= self.planet_size.x
self.pos.y %= self.planet_size.y
2019-11-15 21:20:42 +01:00
def forward(self):
self._translate(1)
def backward(self):
self._translate(-1)
2019-11-15 21:29:37 +01:00
def _turn(self, value):
index: int = DIRECTIONS.index(self.dir)
self.dir = DIRECTIONS[(index + value) % len(DIRECTIONS)]
def turn_left(self):
self._turn(-1)
def turn_right(self):
self._turn(1)
2019-11-15 21:29:57 +01:00
class Commander(BaseModel):
rover: Rover = Rover()
obstacles: List[Vector] = []
def parse_execute(self, commands: str):
for command in commands:
save: Vector = deepcopy(self.rover.pos)
if command == "F":
self.rover.forward()
elif command == "B":
self.rover.backward()
elif command == "L":
self.rover.turn_left()
elif command == "R":
self.rover.turn_right()
if self.rover.pos in self.obstacles:
self.rover.pos = save
raise ObstacleError