Files
notes/CS1527/assessment-1/assessment1.py
bluepython508 b7b584a989 Typo
2024-04-11 12:58:08 +01:00

269 lines
8.2 KiB
Python

# The following is a template of the design.
# you will need to complete the definition of each class, including class attributes,
# instance attributes, and instance methods. However, please do not change the class
# names provided below.
# IMPORTANT: In order to get your program pass the test, make sure your class constructors
# use exactly the same parameter names as in the test examples provided at the end of this template.
# ================Your codes start here=============
# Notes:
# - Should a motorboat (or eboat) really *be* an engine?
# - Why are the keyword arguments abbreviated?
def class_bases(cls):
"""Generator of the base classes of a class (including the given class).
Depth-first, post-order, may yield duplicates
"""
for cls_ in cls.__bases__:
yield from class_bases(cls_)
yield cls
def field_repr(obj) -> str:
"""String representation of an object
Lists fields with type annotations in object's class and superclasses"""
classes = class_bases(obj.__class__)
attrs = (
attr for cls in classes for attr in getattr(cls, "__annotations__", {}).keys()
)
attrs_vals = ",".join(f"{attr}={getattr(obj, attr, None)!r}" for attr in attrs)
return f"{obj.__class__.__name__}({attrs_vals})"
class Boat:
"""A boat
Attributes:
- `color`: color of boat
- `brand`: boat brand
- `year`: manufacture year
Class Attributes:
- `all_boats`: a list of all boats ever constructed
"""
all_boats = []
color: str
brand: str
year: int
def __init__(
self,
*,
co: str,
br: str,
yr: int,
**kwargs,
):
"""Initialize a `Boat`.
Takes keyword-only arguments `co` (color), `br` (brand), and `yr` (year)
as described in class docstring
"""
Boat.all_boats.append(self)
super().__init__(**kwargs)
self.color = co
self.brand = br
self.year = yr
def __str__(self):
return field_repr(self)
def get_boat_age(self, current_year: int) -> int:
"""Get the age of this boat given the current year"""
return current_year - self.year
class Engine:
"""An Engine
Attributes:
- `tech`: Technology used by the engine.
Either 'gas' or 'electric'
- `engine_speed`: maximum speed in miles per hour
determined by `tech` - gas engines have speed 80mph, electric 20mph
Class Attributes:
- `speeds`: mapping of engine tech to speed
"""
speeds = {"gas": 80, "electric": 20}
engine_speed: float
tech: str
def __init__(self, *, tech: str, **kwargs):
"""Initialize an `Engine`
Takes keyword-only argument `tech` (see class docstring)
"""
super().__init__(**kwargs)
self.tech = tech
self.engine_speed = Engine.speeds[tech]
def __str__(self):
return field_repr(self)
def get_engine_speed(self) -> float:
"""Get the engine speed for this engine in miles per hour"""
return self.engine_speed
class Motorboat(Boat, Engine):
"""A Motorboat
Always uses 'gas' engine tech
Attributes:
- `fuel_level`: remaining level of fuel in gallons
- `fuel_efficiency`: range with a certain amount of fuel in miles per gallon
"""
fuel_level: float
fuel_efficiency: float
def __init__(self, *, fl: float, fe: float, **kwargs):
"""Initialize a `Motorboat`
Takes keyword-only arguments `fl` (fuel level) and `fe` (fuel efficiency)
as described in class docstring, in addition to the arguments described in `Boat`
"""
super().__init__(**kwargs, tech="gas")
self.fuel_level = fl
self.fuel_efficiency = fe
def get_max_speed(self) -> float:
"""Get the max speed of the motorboat"""
return self.engine_speed
def cal_travel_time(self, distance: float) -> float:
"""Calculate the time to travel `distance` miles
Prints a message and returns max engine runtime
if the engine would run out of fuel before the destination
"""
range = self.fuel_level * self.fuel_efficiency
if range < distance:
print(
f"This motorboat runs out of fuel {distance - range} miles away from the destination."
)
return min(range, distance) / self.engine_speed
class Pedalboat(Boat):
"""A Pedalboat
Attributes:
- `pedal_speed`: speed attainable by pedalling in miles per hour
Generally in range [10, 20]
"""
pedal_speed: float
def __init__(self, *, ps: float, **kwargs):
"""Initialize a `Pedalboat`
Clamps `pedal_speed` to `10 <= pedal_speed <= 20`
Takes keyword-only argument `ps` (pedal speed), as described in the class docstring,
in addition to the arguments described in `Boat`
"""
super().__init__(**kwargs)
self.pedal_speed = ps
self.check_speed()
def get_pedal_speed(self) -> float:
"""Get the pedalling speed of the boat in miles per hour"""
return self.pedal_speed
def cal_travel_time(self, distance: float) -> float:
"""Calculate the time to travel `distance` miles
"""
return distance / self.pedal_speed
def check_speed(self):
"""Clamps `pedal_speed` to `10 <= pedal_speed <= 20`
Returns whether the speed was already in this range
"""
if 10 <= self.pedal_speed <= 20:
return True
self.pedal_speed = min(20, max(self.pedal_speed, 10))
return False
class Eboat(Pedalboat, Engine):
"""An `Eboat`
Always has engine tech 'electric'
Attributes:
- `battery_time`: remaining battery running time in hours
"""
battery_time: float
def __init__(self, *, bt: float, **kwargs):
"""Initialize an `Eboat`
Takes keyword-only argument `bt` (battery time), as described in the class docstring,
in addition to the arguments described in `Pedalboat`
"""
super().__init__(**kwargs, tech="electric")
self.battery_time = bt
def get_max_speed(self) -> float:
"""The maximum speed attainable in this boat by running the engine and pedalling"""
return self.pedal_speed + self.engine_speed
def cal_travel_time(self, distance: float) -> float:
"""Calculate the time to travel `distance` miles
"""
battery_range = self.get_max_speed() * self.battery_time
return (
min(distance, battery_range) / self.get_max_speed()
+ max(distance - battery_range, 0) / self.pedal_speed
)
# ============ End of your codes here ==================
# ============No modification beyond here =============
# the following is a list of test instances, please do not modify them
if __name__ == "__main__":
# arguments: co - color, br - brand, yr - year, tech - technology used in engine
boat1 = Boat(co="Black", br="Trek", yr=2012)
engine1 = Engine(tech="gas")
print(engine1.get_engine_speed())
# arguments: co - color, br - brand, yr - year, ps - pedal speed
pedalboat1 = Pedalboat(co="Red", br="GIANT", yr=2015, ps=15)
pedalboat2 = Pedalboat(co="Red", br="GIANT", yr=2015, ps=30)
print(pedalboat1.get_pedal_speed())
print(pedalboat2.get_pedal_speed())
print(pedalboat1.cal_travel_time(300))
# arguments: co - color, br - brand, yr - year, ps - pedal speed, bt - battery time
eboat1 = Eboat(co="Blue", br="Basis", yr=2018, ps=15, bt=10)
print(eboat1.get_max_speed())
print(eboat1.cal_travel_time(350))
print(eboat1.cal_travel_time(650))
# arguments: co - color, br - brand, yr - year, fl - fuel level, fe - fuel efficiency
motorboat1 = Motorboat(co="Silver", br="YAMAHA", yr=2013, fl=40, fe=12)
print(motorboat1.get_max_speed())
print(motorboat1.cal_travel_time(300))
print(motorboat1.cal_travel_time(600))
# get the age of all bikes created
for b in Boat.all_boats:
print(b.get_boat_age(2023))