diff --git a/.coverage b/.coverage
index f5d8bf3..6281315 100644
Binary files a/.coverage and b/.coverage differ
diff --git a/htmlcov/d_a44f0ac069e85531_test_rover_py.html b/htmlcov/d_a44f0ac069e85531_test_rover_py.html
index 46d0c37..d1e8c71 100644
--- a/htmlcov/d_a44f0ac069e85531_test_rover_py.html
+++ b/htmlcov/d_a44f0ac069e85531_test_rover_py.html
@@ -22,8 +22,8 @@
- 19 statements
-
+ 23 statements
+
@@ -101,12 +101,40 @@
47def test_rover_can_receive_multiple_commands(init, command, expected):
48 rover = Rover(*init)
49 assert rover.move(command) == expected
+ 50
+ 51
+ 52@pytest.mark.parametrize(
+ 53 ("init", "obstacles", "command", "expected"),
+ 54 [
+ 55 (
+ 56 (0, 0, "NORTH"),
+ 57 [[0, 1]],
+ 58 "F",
+ 59 (0, 0, "NORTH", "STOPPED"),
+ 60 ),
+ 61 (
+ 62 (0, 0, "NORTH"),
+ 63 [[1, 1]],
+ 64 "FRF",
+ 65 (0, 1, "EAST", "STOPPED"),
+ 66 ),
+ 67 (
+ 68 (4, 2, "EAST"),
+ 69 [[1, 4], [5, 5], [7, 4]],
+ 70 "FLFFFRFLB",
+ 71 (5, 4, "NORTH", "STOPPED"),
+ 72 ),
+ 73 ],
+ 74)
+ 75def test_rover_avoids_obstacles(init, obstacles, command, expected):
+ 76 rover = Rover(*init, obstacles=obstacles)
+ 77 assert rover.move(command) == expected
diff --git a/htmlcov/d_bf1a7b34124815c2_rover_py.html b/htmlcov/d_bf1a7b34124815c2_rover_py.html
index 23ddf25..fd13ad7 100644
--- a/htmlcov/d_bf1a7b34124815c2_rover_py.html
+++ b/htmlcov/d_bf1a7b34124815c2_rover_py.html
@@ -22,8 +22,8 @@
- 30 statements
-
+ 48 statements
+
@@ -60,49 +60,73 @@
6 x: int
7 y: int
8 direction: str
- 9
- 10 valid_commands = ("F", "B", "R", "L")
- 11
- 12 direction_map = {
- 13 "NORTH": (0, 1, "WEST", "EAST"),
- 14 "EAST": (1, 0, "NORTH", "SOUTH"),
- 15 "SOUTH": (0, -1, "EAST", "WEST"),
- 16 "WEST": (-1, 0, "SOUTH", "NORTH"),
- 17 }
- 18
- 19 def is_valid_command(self, command):
- 20 for ch in command:
- 21 if ch not in self.valid_commands:
- 22 return False
- 23
- 24 return True
- 25
- 26 def move(self, command: str):
- 27 if not self.is_valid_command(command):
- 28 raise ValueError("invalid command. The rover does not move")
+ 9 obstacles: list[list[int]] = dataclasses.field(default_factory=list)
+ 10
+ 11 valid_commands = ("F", "B", "R", "L")
+ 12
+ 13 direction_map = {
+ 14 "NORTH": (0, 1, "WEST", "EAST"),
+ 15 "EAST": (1, 0, "NORTH", "SOUTH"),
+ 16 "SOUTH": (0, -1, "EAST", "WEST"),
+ 17 "WEST": (-1, 0, "SOUTH", "NORTH"),
+ 18 }
+ 19
+ 20 def is_valid_command(self, command):
+ 21 for ch in command:
+ 22 if ch not in self.valid_commands:
+ 23 return False
+ 24
+ 25 return True
+ 26
+ 27 def is_obstacle(self, x: int, y: int):
+ 28 return [x, y] in self.obstacles
29
- 30 for ch in command:
- 31 self._move_one_step(ch)
- 32
- 33 return self.x, self.y, self.direction
- 34
- 35 def _move_one_step(self, command):
- 36 if command == "B":
- 37 self.x -= self.direction_map[self.direction][0]
- 38 self.y -= self.direction_map[self.direction][1]
- 39 if command == "F":
- 40 self.x += self.direction_map[self.direction][0]
- 41 self.y += self.direction_map[self.direction][1]
- 42 if command == "R":
- 43 self.direction = self.direction_map[self.direction][3]
- 44 if command == "L":
- 45 self.direction = self.direction_map[self.direction][2]
+ 30 def move(self, command: str):
+ 31 if not self.is_valid_command(command):
+ 32 raise ValueError("invalid command. The rover does not move")
+ 33
+ 34 for ch in command:
+ 35 x, y, direction = self._compute_new_coordinates(ch)
+ 36 if obstacle := self.is_obstacle(x, y):
+ 37 return self.new_coordinates_output(obstacle)
+ 38
+ 39 self.apply_new_coordinates(x, y, direction)
+ 40
+ 41 return self.new_coordinates_output()
+ 42
+ 43 def new_coordinates_output(self, obstacle: bool = False):
+ 44 if obstacle:
+ 45 return self.x, self.y, self.direction, "STOPPED"
+ 46 return self.x, self.y, self.direction
+ 47
+ 48 def _compute_new_coordinates(self, command):
+ 49 x = self.x
+ 50 y = self.y
+ 51 direction = self.direction
+ 52
+ 53 if command == "B":
+ 54 x -= self.direction_map[self.direction][0]
+ 55 y -= self.direction_map[self.direction][1]
+ 56 if command == "F":
+ 57 x += self.direction_map[self.direction][0]
+ 58 y += self.direction_map[self.direction][1]
+ 59 if command == "R":
+ 60 direction = self.direction_map[self.direction][3]
+ 61 if command == "L":
+ 62 direction = self.direction_map[self.direction][2]
+ 63
+ 64 return x, y, direction
+ 65
+ 66 def apply_new_coordinates(self, x, y, direction):
+ 67 self.x = x
+ 68 self.y = y
+ 69 self.direction = direction
diff --git a/htmlcov/index.html b/htmlcov/index.html
index 4b75b35..ac0c549 100644
--- a/htmlcov/index.html
+++ b/htmlcov/index.html
@@ -53,10 +53,10 @@
| Total |
- 54 |
+ 76 |
0 |
0 |
- 100% |
+ 100% |
@@ -69,10 +69,10 @@
| rover/rover.py |
- 30 |
+ 48 |
0 |
0 |
- 100% |
+ 100% |
| tests/__init__.py |
@@ -90,10 +90,10 @@
| tests/test_rover.py |
- 19 |
+ 23 |
0 |
0 |
- 100% |
+ 100% |
@@ -105,7 +105,7 @@
coverage.py v6.0b1,
- created at 2021-08-27 11:19 +0200
+ created at 2021-08-27 11:47 +0200
diff --git a/htmlcov/status.json b/htmlcov/status.json
index 1d2d24c..792bb67 100644
--- a/htmlcov/status.json
+++ b/htmlcov/status.json
@@ -1 +1 @@
-{"format":2,"version":"6.0b1","globals":"9bd57ebde26eb2f4bf8646481dbf1d3b","files":{"d_bf1a7b34124815c2___init___py":{"hash":"3c77fc9ef7f887ac2508d4109cf92472","index":{"nums":[0,1,0,0,0,0,0,0],"html_filename":"d_bf1a7b34124815c2___init___py.html","relative_filename":"rover/__init__.py"}},"d_a44f0ac069e85531___init___py":{"hash":"3c77fc9ef7f887ac2508d4109cf92472","index":{"nums":[0,1,0,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531___init___py.html","relative_filename":"tests/__init__.py"}},"d_a44f0ac069e85531_test_rover_py":{"hash":"4d1bd2b75fabcbf83a857a2c86f6afe8","index":{"nums":[0,1,19,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531_test_rover_py.html","relative_filename":"tests/test_rover.py"}},"d_bf1a7b34124815c2_rover_py":{"hash":"07cd27855c88f8cfc60965c599b883d4","index":{"nums":[0,1,30,0,0,0,0,0],"html_filename":"d_bf1a7b34124815c2_rover_py.html","relative_filename":"rover/rover.py"}},"d_a44f0ac069e85531_conftest_py":{"hash":"131dc5829333225ffeda75380140e18e","index":{"nums":[0,1,5,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531_conftest_py.html","relative_filename":"tests/conftest.py"}}}}
\ No newline at end of file
+{"format":2,"version":"6.0b1","globals":"9bd57ebde26eb2f4bf8646481dbf1d3b","files":{"d_bf1a7b34124815c2___init___py":{"hash":"3c77fc9ef7f887ac2508d4109cf92472","index":{"nums":[0,1,0,0,0,0,0,0],"html_filename":"d_bf1a7b34124815c2___init___py.html","relative_filename":"rover/__init__.py"}},"d_a44f0ac069e85531___init___py":{"hash":"3c77fc9ef7f887ac2508d4109cf92472","index":{"nums":[0,1,0,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531___init___py.html","relative_filename":"tests/__init__.py"}},"d_a44f0ac069e85531_test_rover_py":{"hash":"56847e16289e9409f1589e7acd9df071","index":{"nums":[0,1,23,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531_test_rover_py.html","relative_filename":"tests/test_rover.py"}},"d_bf1a7b34124815c2_rover_py":{"hash":"d446e537c9a216d7ef2cb3482a0b83a6","index":{"nums":[0,1,48,0,0,0,0,0],"html_filename":"d_bf1a7b34124815c2_rover_py.html","relative_filename":"rover/rover.py"}},"d_a44f0ac069e85531_conftest_py":{"hash":"131dc5829333225ffeda75380140e18e","index":{"nums":[0,1,5,0,0,0,0,0],"html_filename":"d_a44f0ac069e85531_conftest_py.html","relative_filename":"tests/conftest.py"}}}}
\ No newline at end of file
diff --git a/rover/rover.py b/rover/rover.py
index 11d29fd..8fbacf6 100644
--- a/rover/rover.py
+++ b/rover/rover.py
@@ -6,6 +6,7 @@ class Rover:
x: int
y: int
direction: str
+ obstacles: list[list[int]] = dataclasses.field(default_factory=list)
valid_commands = ("F", "B", "R", "L")
@@ -23,23 +24,46 @@ class Rover:
return True
+ def is_obstacle(self, x: int, y: int):
+ 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:
- self._move_one_step(ch)
+ 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 _move_one_step(self, command):
+ def _compute_new_coordinates(self, command):
+ x = self.x
+ y = self.y
+ direction = self.direction
+
if command == "B":
- self.x -= self.direction_map[self.direction][0]
- self.y -= self.direction_map[self.direction][1]
+ x -= self.direction_map[self.direction][0]
+ y -= self.direction_map[self.direction][1]
if command == "F":
- self.x += self.direction_map[self.direction][0]
- self.y += self.direction_map[self.direction][1]
+ x += self.direction_map[self.direction][0]
+ y += self.direction_map[self.direction][1]
if command == "R":
- self.direction = self.direction_map[self.direction][3]
+ direction = self.direction_map[self.direction][3]
if command == "L":
- self.direction = self.direction_map[self.direction][2]
+ direction = self.direction_map[self.direction][2]
+
+ return x, y, direction
+
+ def apply_new_coordinates(self, x, y, direction):
+ self.x = x
+ self.y = y
+ self.direction = direction
diff --git a/tests/test_rover.py b/tests/test_rover.py
index 7fb081e..9400442 100644
--- a/tests/test_rover.py
+++ b/tests/test_rover.py
@@ -47,3 +47,31 @@ def test_rover_rejects_invalid_commands(rover):
def test_rover_can_receive_multiple_commands(init, command, expected):
rover = Rover(*init)
assert rover.move(command) == expected
+
+
+@pytest.mark.parametrize(
+ ("init", "obstacles", "command", "expected"),
+ [
+ (
+ (0, 0, "NORTH"),
+ [[0, 1]],
+ "F",
+ (0, 0, "NORTH", "STOPPED"),
+ ),
+ (
+ (0, 0, "NORTH"),
+ [[1, 1]],
+ "FRF",
+ (0, 1, "EAST", "STOPPED"),
+ ),
+ (
+ (4, 2, "EAST"),
+ [[1, 4], [5, 5], [7, 4]],
+ "FLFFFRFLB",
+ (5, 4, "NORTH", "STOPPED"),
+ ),
+ ],
+)
+def test_rover_avoids_obstacles(init, obstacles, command, expected):
+ rover = Rover(*init, obstacles=obstacles)
+ assert rover.move(command) == expected