diff --git a/CS1527/assesment-1/assessment1.pdf b/CS1527/assesment-1/assessment1.pdf new file mode 100644 index 0000000..0267315 Binary files /dev/null and b/CS1527/assesment-1/assessment1.pdf differ diff --git a/CS1527/assesment-1/assessment1.py b/CS1527/assesment-1/assessment1.py new file mode 100644 index 0000000..ba99775 --- /dev/null +++ b/CS1527/assesment-1/assessment1.py @@ -0,0 +1,268 @@ +# 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))