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 @@ Show keyboard shortcuts

- 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 @@ Show keyboard shortcuts

- 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