Passed
Push — main ( 20f858...b2f07a )
by Rahn20
01:07
created

src.scooter.Scooter.move_to_station()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 2
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
#!/usr/bin/python3
2
3
""" File for handling scooter data with Scooter class. """
4
5
import math
6
import random
7
import re
8
from geopy.distance import geodesic, distance
9
10
class Scooter():
11
    """ Scooter class """
12
13
    ## scooter's data
14
    data = {
15
        "id": 0,
16
        "lat": 59.173228,       # coordinates
17
        "lon":  17.603204,      # coordinates
18
        "speed": 0,             # km/h
19
        "battery": 50,          # %
20
        "status": "running"
21
    }
22
23
    ## city's data
24
    city = {
25
        "id": 2,
26
        "area": 25.84,      # km²
27
        "lat": 59.19554,    # coordinates
28
        "lon": 17.62525     # coordinates
29
    }
30
31
    ## scooter's new coordinates
32
    location = ""
33
34
35
    def __init__(self) -> None:
36
        """ Initialize class """
37
38
39
    def add_scooter_data(self, scooter: dict) -> None:
40
        """ Add scooter API data to data dictionary. """
41
        self.data = {
42
            "id": scooter["id"],
43
            "lat": scooter["latitude"],
44
            "lon":  scooter["longitude"],
45
            "speed": scooter["speed"],
46
            "battery": scooter["battery"],
47
            "status": "running"
48
        }
49
50
51
    def __str__(self) -> str:
52
        """ Returns scooters data """
53
        return "Scooter id: {0}\nLocation: {1}, {2}\nSpeed: {3}km/h\nBattery: {4}%".format(
54
            self.data["id"],
55
            self.data["lat"],
56
            self.data["lon"],
57
            self.data["speed"],
58
            self.data["battery"],
59
        )
60
61
62
    def move_scooter(self) -> None:
63
        """
64
        Move the scooter from one position to another and reduce battery level.
65
        Max scooter speed is 20km/h.
66
        """
67
        ## get random speed
68
        speed = random.randrange(1, 21)
69
        points = re.split("Point|, ", self.location)
70
71
        self.data["lat"] = float(points[1][1:])
72
        self.data["lon"] = float(points[2])
73
        self.data["speed"] = speed
74
        self.data["battery"] -= 1
75
76
77
    def change_location(self) -> None:
78
        """
79
        Get random location inside the city zone.
80
        Speed = distance ÷ time => distance = speed * time
81
        Bearing in degrees: North: 0, East: 90, South: 180, West: 270.
82
        """
83
        ## 5 seconds is sleep time, scooter moves every 5 seconds
84
        ## but for better simulation I increase it to 10
85
        distance_km = self.data["speed"] * (10 / 3600)
86
87
        ## get random position
88
        bearing = random.randint(0, 3)
89
        degrees = [0, 90, 180, 270]
90
91
        new_location = repr(distance(kilometers = distance_km).destination(
92
            (self.data["lat"], self.data["lon"]),
93
            bearing = degrees[bearing])
94
        )
95
96
        self.location = new_location
97
98
99
    def stop_scooter(self, status = "running") -> None:
100
        """ Stop the scooter from running. Change status and speed. """
101
        self.data["status"] = status
102
        self.data["speed"] = 0
103
104
105
    def check_battery(self) -> bool:
106
        """ Returns True if the battery level < 20%. """
107
        return self.data["battery"] < 20
108
109
110
    def move_to_station(self, station: dict) -> None:
111
        """ Move the scooter to charging/maintenance station. """
112
        self.data["lat"] = station["latitude"]
113
        self.data["lon"] = station["longitude"]
114
115
116
    @staticmethod
117
    def check_maintenance() -> bool:
118
        """
119
        Returns true if the random number is 1 otherwise False, since scooters are not
120
        real, the maintenance check will be randomly.
121
        The probability that the scooter receives maintenance is 10%.
122
        """
123
        probability = random.randint(1, 10)
124
        return probability == 1
125
126
127
    def check_scooter_in_city(self) -> bool:
128
        """
129
        Check if scooter is inside the city zone. If the distance between
130
        two points 'city center and scooter' <= circle radius return True.
131
        """
132
        ## Circle Area = pi * r^2 => r^2 = A/pi
133
        radius = math.sqrt((self.city["area"] / math.pi))
134
        scooter = (self.data["lat"], self.data["lon"])
135
        city = (self.city["lat"], self.city["lon"])
136
137
        calculate = geodesic(scooter, city).km
138
139
        if calculate <= radius:
140
            return True
141
        return False
142