I'm currently applying for a job at a well known company in Stockholm, and I need some help with reviewing my initial draft of my solution to the Mars Rover problem. I mainly use JavaScript when I develop, but the company requires me to solve it using Java, C# or Python.
Luckily for me I've got some basic Python skills, but I'd really like to get some feedback on this initial solution. Even though I realise there might be bugs in the code I'm more focused on best practice, any OOP misses I might have performed (I've never used classes over multiple files before) and such.
Obviously if you find any bugs, that would be great too. I've only worked on the problem for about 3 hours and I've got a week or so left on solving it.
However ugly it is, it does solve the basic test cases. So for all intents and purposes it should "work.
With no further ado, here is the code:
main.py (the brainz)
#!/usr/bin/env python3
from Rover import Rover
from Mars import Mars
def validate_mars(x, y):
"""
"""
if x.isdigit() and y.isdigit():
mars = Mars(int(x), int(y))
Rover.Mars = mars
return True
else:
print("Only numerical elements. Try again!")
return False
def validate_rover(x, y, direction):
if x.isdigit() and y.isdigit() and direction.isalpha():
return True
return False
def validate_operations(op):
import re
pattern = re.compile("^[MRL]*$")
if pattern.match(op):
return True
else:
return False
def move(op, r):
try:
for operation in op:
if operation == "L":
r.turnLeft()
elif operation == "R":
r.turnRight()
else:
r.forward()
except Exception as err:
op = input("Your rover went outside of Mars surface.\nCurrently the rover's position \
is {} facing {}. Try again!\n>>> ".format(r.getPosition(), r.getDirection())).upper()
move(op, r)
def main ():
#
# A while loop to validate user input.
# Using a boolean flag to check the integrity of the loop.
#
flag = False
rovers = []
while (flag == False):
choice = input("Please enter the size of mars (2 numbers, separated by a space and higher than 0.)\n>>> ").split()
if len(choice) == 2:
flag = validate_mars(choice[0], choice[1])
else:
print("Incorrect input. Please ensure you enter a string with two numerical elements")
print("\n--------------------------------------\n")
flag = False # reset flag to input rovers
while (flag == False):
choice = input("Please enter the current rover's initial position.\nRemember to keep inside Mars limits!\n>>> ").split()
if len(choice) == 3:
if(validate_rover(choice[0], choice[1], choice[2])):
rover = Rover(int(choice[0]), int(choice[1]), choice[2])
choice = input("Please enter the operations you wish for this rover to execute.\n>>> ").upper()
if validate_operations(choice):
move(choice, rover)
rovers.append(rover)
print("\n--------------------------------------\n")
else:
print("You appear to have entered an incorrect sequence. Two numbers followed by a single character (N,E,S,W)\nTry again!")
if "exit" in choice:
print("--------------- Output ---------------")
for rover in rovers:
print("| {} is on position: {} facing {}".format(rover.getRoverId(), rover.getPosition(), rover.getDirection()))
print("--------------------------------------")
exit()
if __name__ == "__main__":
main()
Mars.py (the "board")
class Mars ():
def __init__(self, x, y):
self.x = x
self.y = y
print("Mars initiated with size: " + str(Mars.getX(self)) + ", " + str(Mars.getY(self)))
def getX(self):
return self.x
def getY(self):
return self.y
Rover.py (the controller)
import operator
directions = ["N", "E", "S", "W"]
class Rover():
rvrCount = 0 #initialize the count of rovers to 0.
Mars = ""
def __init__(self, x, y, direction):
"""
Initialize a rover and increment the count of rovers by one (1).
"""
self.direction = direction
self.x = x
self.y = y
Rover.rvrCount += 1
self.id = "Rover " + str(Rover.rvrCount)
print("Rover{} initiated on {} {} facing {}".format(str(Rover.rvrCount), str(self.x), str(self.y), self.direction))
direction = property(operator.attrgetter('_direction'))
@direction.setter
def direction(self, d):
if d.upper() not in directions: raise Exception("Direction not correct, use 'N, E, S or W'")
self._direction = d.upper()
x = property(operator.attrgetter('_x'))
@x.setter
def x(self, x):
if (x < 0 or x > Rover.Mars.getX()): raise Exception("This rover's x-value is out of bounds. It should be value should be < 0 and > " + str(Mars.getX()))
self._x = x
y = property(operator.attrgetter('_y'))
@y.setter
def y(self, y):
if (y < 0 or y > Rover.Mars.getY()): raise Exception("This rover's y-value is out of bounds. It should be value should be < 0 and > " + str(Mars.getY()))
self._y = y
def getDirection(self):
return self.direction
def getPosition(self):
return str(self.x) + " " + str(self.y)
def getRoverId(self):
return self.id
def turnRight(self):
self.direction = directions[0] if directions.index(self._direction) == 3 else directions[directions.index(self._direction) + 1]
def turnLeft(self):
self.direction = directions[3] if directions.index(self._direction) == 0 else directions[directions.index(self._direction) - 1]
def forward(self):
if self._direction == "N":
self.y = self._y + 1
elif self._direction == "S":
self.y = self._y - 1
elif self._direction == "E":
self.x = self._x + 1
else:
self.x = self._x - 1