diff --git a/app/car.py b/app/car.py new file mode 100644 index 00000000..88b7c108 --- /dev/null +++ b/app/car.py @@ -0,0 +1,17 @@ +from __future__ import annotations + + +class Car: + def __init__(self, brand: str, fuel_consumption: float) -> None: + self.brand = brand + self.fuel_consumption = fuel_consumption + + @classmethod + def create_car(cls, car_info: dict[str, str | float | int]) -> Car: + return cls( + brand=car_info["brand"], + fuel_consumption=car_info["fuel_consumption"] + ) + + def calculate_fuel_consumption(self, distance: float) -> float: + return (self.fuel_consumption / 100) * distance diff --git a/app/customer.py b/app/customer.py new file mode 100644 index 00000000..414b00b5 --- /dev/null +++ b/app/customer.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from app.car import Car +from app.point import Point +from app.shop import Shop + + +class Customer: + def __init__( + self, + name: str, + product_cart: dict[str, int], + location: Point, + money: float, + car: Car + ) -> None: + self.name = name + self.product_cart = product_cart or {} + self.location = location + self.money = money + self.car = car + + @classmethod + def create_customer( + cls, + source: dict[str, str | dict[str, int] | list[int] | int] + ) -> Customer: + return cls( + source["name"], + source["product_cart"], + Point.create_from_location(source["location"]), + source["money"], + Car.create_car(source["car"]) + ) + + def choose_shop(self, shops: list) -> Shop | None: + for shop in shops: + print(f"{self.name}'s trip to the {shop.name} " + f"costs {self._calculate_total_expenses(shop)}") + + cheapest_shop = min( + shops, + key=lambda shop: self._calculate_total_expenses(shop) + ) + total_expenses = self._calculate_total_expenses(cheapest_shop) + if self.money < total_expenses: + return None + self.money -= total_expenses + return cheapest_shop + + def _calculate_total_expenses(self, shop: Shop) -> float: + distance = self.location.calculate_distance_to(shop.location) + fuel_expenses = ( + (self.car.calculate_fuel_consumption(distance) * 2) * 2.4 + ) + groceries_expenses = ( + self._calculate_groceries_expenses(shop.products) + ) + + return round(fuel_expenses + groceries_expenses, 2) + + def _calculate_groceries_expenses(self, prices: dict) -> float: + return sum( + prices[product_name] * amount + for product_name, amount in self.product_cart.items() + ) diff --git a/app/main.py b/app/main.py index 558d7d94..8bb51d3c 100644 --- a/app/main.py +++ b/app/main.py @@ -1,3 +1,30 @@ -def shop_trip(): - # write your code here - pass +import json +from typing import Callable + +from app.shop import Shop +from app.customer import Customer + + +def get_data(info_key: str, creation_func: Callable) -> list: + with open("app/config.json", "r") as source: + data = json.load(source) + return [creation_func(info) for info in data[info_key]] + + +def shop_trip() -> None: + customers = get_data("customers", Customer.create_customer) + shops = get_data("shops", Shop.create_shop) + + for client in customers: + print(f"{client.name} has {client.money} dollars") + + client_shop_choice = client.choose_shop(shops) + if client_shop_choice is None: + print(f"{client.name} doesn't have enough " + f"money to make a purchase in any shop") + return + print(f"{client.name} rides to {client_shop_choice.name}\n") + client_shop_choice.sell(client) + + +shop_trip() diff --git a/app/point.py b/app/point.py new file mode 100644 index 00000000..41adb327 --- /dev/null +++ b/app/point.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import math + + +class Point: + def __init__(self, cor_x: int, cor_y: int) -> None: + self.x = cor_x + self.y = cor_y + + @classmethod + def create_from_location(cls, location: list[int]) -> Point: + return cls(cor_x=location[0], cor_y=location[1]) + + def calculate_distance_to(self, destination: Point) -> float: + return math.sqrt( + math.pow(destination.x - self.x, 2) + + math.pow(destination.y - self.y, 2) + ) diff --git a/app/shop.py b/app/shop.py new file mode 100644 index 00000000..4b22136d --- /dev/null +++ b/app/shop.py @@ -0,0 +1,45 @@ +from __future__ import annotations +from typing import Any + +from app.point import Point + + +class Shop: + def __init__( + self, + name: str, + location: Point, + products: dict[str, float | int] + ) -> None: + self.name = name + self.location = location + self.products = products + + @classmethod + def create_shop( + cls, + shop_info: dict[str, str | list[int] | dict[str, (int | float)]] + ) -> Shop: + return cls( + name=shop_info["name"], + location=Point.create_from_location(shop_info["location"]), + products=shop_info["products"] + ) + + def sell(self, customer: Any) -> None: + print("Date: 04/01/2021 12:33:41") + print(f"Thanks, {customer.name}, for your purchase!") + print("You have bought:") + for name, amount in customer.product_cart.items(): + product_price = amount * self.products[name] + if product_price % int(product_price) == 0: + product_price = int(product_price) + print(f"{amount} {name}s for {product_price} dollars") + total_cost = sum( + amount * self.products[name] + for name, amount in customer.product_cart.items() + ) + print(f"Total cost is {round(total_cost, 2)} dollars") + print("See you again!\n") + print(f"{customer.name} rides home") + print(f"{customer.name} now has {customer.money} dollars\n")