Домашни > Another brick in the wall > Решения > Решението на Даниел Стефанов

Резултати
10 точки от тестове
0 точки от учител

10 точки общо

10 успешни теста
0 неуспешни теста
Код

  1CONCRETE_DENSITY = 2500
  2BRICK_DENSITY = 2000
  3STONE_DENSITY = 1600
  4WOOD_DENSITY = 600
  5STEEL_DENSITY = 7700
  6BASE_MATERIALS_COUNT = 5
  7BASE_MATERIAL_DENSITIES = [BRICK_DENSITY,
  8                           CONCRETE_DENSITY,
  9                           STEEL_DENSITY,
 10                           STONE_DENSITY,
 11                           WOOD_DENSITY]
 12
 13ERROR_MESSAGE = "6ff9dc6e00d1e166f1612e919e934af22eb204b931539f629e152324a2e5a221"
 14
 15
 16class Material:
 17    density = 0
 18
 19    def __init__(self, mass):
 20        self.mass = mass
 21        self.is_used = False
 22
 23    @property
 24    def volume(self):
 25        if self.density == 0:
 26            raise ZeroDivisionError(ERROR_MESSAGE)
 27        return self.mass / self.density
 28
 29
 30class Concrete(Material):
 31
 32    def __init__(self, mass):
 33        super().__init__(mass)
 34        Concrete.density = CONCRETE_DENSITY
 35
 36
 37class Brick(Material):
 38
 39    def __init__(self, mass):
 40        super().__init__(mass)
 41        Brick.density = BRICK_DENSITY
 42
 43
 44class Stone(Material):
 45
 46    def __init__(self, mass):
 47        super().__init__(mass)
 48        Stone.density = STONE_DENSITY
 49
 50
 51class Wood(Material):
 52
 53    def __init__(self, mass):
 54        super().__init__(mass)
 55        Wood.density = WOOD_DENSITY
 56
 57
 58class Steel(Material):
 59
 60    def __init__(self, mass):
 61        super().__init__(mass)
 62        Steel.density = STEEL_DENSITY
 63
 64
 65BASE_MATERIAL_CLASSES = [Brick, Concrete, Steel, Stone, Wood]
 66BASE_MATERIALS_NAMES = [x.__name__ for x in BASE_MATERIAL_CLASSES]
 67
 68
 69class Factory:
 70    alloys = [*BASE_MATERIAL_CLASSES]
 71    created_materials_from_factories = []
 72
 73    def __init__(self):
 74        self.created_materials = []
 75
 76    def __call__(self, *args, **kwargs):
 77        if (args and kwargs) or (not args and not kwargs):
 78            raise ValueError(ERROR_MESSAGE)
 79
 80        return self._kwargs_case_handler(**kwargs) if kwargs else self._args_case_handler(*args)
 81
 82    def _kwargs_case_handler(self, **kwargs):
 83        result = []
 84        for class_name, mass in kwargs.items():
 85            class_type = next((cls for cls in self.alloys if cls.__name__ == class_name), None)
 86
 87            if class_type is None:
 88                raise ValueError(ERROR_MESSAGE)
 89
 90            current_created_material = class_type(mass)
 91            self.created_materials.append(current_created_material)
 92            self.created_materials_from_factories.append(current_created_material)
 93            result.append(current_created_material)
 94
 95        return tuple(result)
 96
 97    def _args_case_handler(self, *args):
 98        concatenated_names = "_".join([arg.__class__.__name__ for arg in args])
 99        extracted_base_names = set(concatenated_names.split("_"))
100        current_class_name = '_'.join(sorted(extracted_base_names))
101
102        if any([arg.is_used for arg in args]):
103            raise AssertionError(ERROR_MESSAGE)
104
105        if current_class_name not in [current_class.__name__ for current_class in self.alloys]:
106            current_class_density = sum(
107                [BASE_MATERIAL_DENSITIES[i]
108                 for i in range(BASE_MATERIALS_COUNT)
109                 if BASE_MATERIALS_NAMES[i] in extracted_base_names]
110            )
111            current_class_density /= len(extracted_base_names)
112
113            self.alloys.append(type(current_class_name, (Material,), {"density": current_class_density}))
114
115        for arg in args:
116            arg.is_used = True
117
118        current_instance_mass = sum([arg.mass for arg in args])
119        current_class_type = next(cls for cls in self.alloys if cls.__name__ == current_class_name)
120        current_created_material = current_class_type(current_instance_mass)
121        self.created_materials.append(current_created_material)
122        self.created_materials_from_factories.append(current_created_material)
123        return current_created_material
124
125    def can_build(self, wall_volume):
126        materials_volume = sum(mat.volume for mat in self.created_materials if not mat.is_used)
127        return materials_volume >= wall_volume
128
129    @classmethod
130    def can_build_together(cls, wall_volume):
131        materials_volume = sum(mat.volume for mat in cls.created_materials_from_factories if not mat.is_used)
132        return materials_volume >= wall_volume

..........
----------------------------------------------------------------------
Ran 10 tests in 0.015s

OK

Дискусия
Георги Кунчев
21.11.2024 15:38

XOR е супер! Ама ти си решаваш. Ето как можеш да постигнеш същото наследяване. Аналогично за другите класове. ``` class Concrete(Material): density = CONCRETE_DENSITY ``` Мисля, че е очевидно, но споменавам - това ти е целият клас. Вече няма да имаш нужда от `__init__`.
Даниел Стефанов
21.11.2024 15:35

За XOR-a реших да не го променям, защото не ми изглежда четимо. Този коментар не го разбрах: "Ако това го сетнеш като атрибут на класа, както е в Material, ще си спестиш дефиницията на нов __init__ за всички под-класове.". Поне ги оправих да са си клас абтрибути.
Георги Кунчев
21.11.2024 13:37

Един коментар, който оставям тук, защото не е случай, с който плануваме да тестваме, но си заслужава да се отбележи. Поради факта, че държиш материали в инстанциите и в класа си, не покриваш случай, който в реалния свят е напълно валиден - дадена фабрика се срутва, съсипвайки всички създадени материали (разбирай `del some_factory`). При този случай не можеш да разбереш кои неща от `created_materials_from_factories` си изгубил и какво да изтриеш. Ако вместо `created_materials_from_factories` пазиш иснтанциите на `Factory`, ще си ок: ``` class Factory: _instances = [] def __init__(self): self.created_materials = [] self._instances.append(self) ``` Мисля, че ти е ясно после как да ги обходиш, ама ако не е, питай.
История

f1CONCRETE_DENSITY = 2500f1CONCRETE_DENSITY = 2500
2BRICK_DENSITY = 20002BRICK_DENSITY = 2000
3STONE_DENSITY = 16003STONE_DENSITY = 1600
4WOOD_DENSITY = 6004WOOD_DENSITY = 600
5STEEL_DENSITY = 77005STEEL_DENSITY = 7700
6BASE_MATERIALS_COUNT = 56BASE_MATERIALS_COUNT = 5
7BASE_MATERIAL_DENSITIES = [BRICK_DENSITY,7BASE_MATERIAL_DENSITIES = [BRICK_DENSITY,
8                           CONCRETE_DENSITY,8                           CONCRETE_DENSITY,
9                           STEEL_DENSITY,9                           STEEL_DENSITY,
10                           STONE_DENSITY,10                           STONE_DENSITY,
11                           WOOD_DENSITY]11                           WOOD_DENSITY]
1212
13ERROR_MESSAGE = "6ff9dc6e00d1e166f1612e919e934af22eb204b931539f629e152324a2e5a221"13ERROR_MESSAGE = "6ff9dc6e00d1e166f1612e919e934af22eb204b931539f629e152324a2e5a221"
1414
1515
16class Material:16class Material:
17    density = 017    density = 0
1818
19    def __init__(self, mass):19    def __init__(self, mass):
20        self.mass = mass20        self.mass = mass
21        self.is_used = False21        self.is_used = False
2222
23    @property23    @property
24    def volume(self):24    def volume(self):
25        if self.density == 0:25        if self.density == 0:
26            raise ZeroDivisionError(ERROR_MESSAGE)26            raise ZeroDivisionError(ERROR_MESSAGE)
27        return self.mass / self.density27        return self.mass / self.density
2828
2929
30class Concrete(Material):30class Concrete(Material):
3131
32    def __init__(self, mass):32    def __init__(self, mass):
33        super().__init__(mass)33        super().__init__(mass)
n34        self.density = CONCRETE_DENSITYn34        Concrete.density = CONCRETE_DENSITY
3535
3636
37class Brick(Material):37class Brick(Material):
3838
39    def __init__(self, mass):39    def __init__(self, mass):
40        super().__init__(mass)40        super().__init__(mass)
n41        self.density = BRICK_DENSITYn41        Brick.density = BRICK_DENSITY
4242
4343
44class Stone(Material):44class Stone(Material):
4545
46    def __init__(self, mass):46    def __init__(self, mass):
47        super().__init__(mass)47        super().__init__(mass)
n48        self.density = STONE_DENSITYn48        Stone.density = STONE_DENSITY
4949
5050
51class Wood(Material):51class Wood(Material):
5252
53    def __init__(self, mass):53    def __init__(self, mass):
54        super().__init__(mass)54        super().__init__(mass)
n55        self.density = WOOD_DENSITYn55        Wood.density = WOOD_DENSITY
5656
5757
58class Steel(Material):58class Steel(Material):
5959
60    def __init__(self, mass):60    def __init__(self, mass):
61        super().__init__(mass)61        super().__init__(mass)
t62        self.density = STEEL_DENSITYt62        Steel.density = STEEL_DENSITY
6363
6464
65BASE_MATERIAL_CLASSES = [Brick, Concrete, Steel, Stone, Wood]65BASE_MATERIAL_CLASSES = [Brick, Concrete, Steel, Stone, Wood]
66BASE_MATERIALS_NAMES = [x.__name__ for x in BASE_MATERIAL_CLASSES]66BASE_MATERIALS_NAMES = [x.__name__ for x in BASE_MATERIAL_CLASSES]
6767
6868
69class Factory:69class Factory:
70    alloys = [*BASE_MATERIAL_CLASSES]70    alloys = [*BASE_MATERIAL_CLASSES]
71    created_materials_from_factories = []71    created_materials_from_factories = []
7272
73    def __init__(self):73    def __init__(self):
74        self.created_materials = []74        self.created_materials = []
7575
76    def __call__(self, *args, **kwargs):76    def __call__(self, *args, **kwargs):
77        if (args and kwargs) or (not args and not kwargs):77        if (args and kwargs) or (not args and not kwargs):
78            raise ValueError(ERROR_MESSAGE)78            raise ValueError(ERROR_MESSAGE)
7979
80        return self._kwargs_case_handler(**kwargs) if kwargs else self._args_case_handler(*args)80        return self._kwargs_case_handler(**kwargs) if kwargs else self._args_case_handler(*args)
8181
82    def _kwargs_case_handler(self, **kwargs):82    def _kwargs_case_handler(self, **kwargs):
83        result = []83        result = []
84        for class_name, mass in kwargs.items():84        for class_name, mass in kwargs.items():
85            class_type = next((cls for cls in self.alloys if cls.__name__ == class_name), None)85            class_type = next((cls for cls in self.alloys if cls.__name__ == class_name), None)
8686
87            if class_type is None:87            if class_type is None:
88                raise ValueError(ERROR_MESSAGE)88                raise ValueError(ERROR_MESSAGE)
8989
90            current_created_material = class_type(mass)90            current_created_material = class_type(mass)
91            self.created_materials.append(current_created_material)91            self.created_materials.append(current_created_material)
92            self.created_materials_from_factories.append(current_created_material)92            self.created_materials_from_factories.append(current_created_material)
93            result.append(current_created_material)93            result.append(current_created_material)
9494
95        return tuple(result)95        return tuple(result)
9696
97    def _args_case_handler(self, *args):97    def _args_case_handler(self, *args):
98        concatenated_names = "_".join([arg.__class__.__name__ for arg in args])98        concatenated_names = "_".join([arg.__class__.__name__ for arg in args])
99        extracted_base_names = set(concatenated_names.split("_"))99        extracted_base_names = set(concatenated_names.split("_"))
100        current_class_name = '_'.join(sorted(extracted_base_names))100        current_class_name = '_'.join(sorted(extracted_base_names))
101101
102        if any([arg.is_used for arg in args]):102        if any([arg.is_used for arg in args]):
103            raise AssertionError(ERROR_MESSAGE)103            raise AssertionError(ERROR_MESSAGE)
104104
105        if current_class_name not in [current_class.__name__ for current_class in self.alloys]:105        if current_class_name not in [current_class.__name__ for current_class in self.alloys]:
106            current_class_density = sum(106            current_class_density = sum(
107                [BASE_MATERIAL_DENSITIES[i]107                [BASE_MATERIAL_DENSITIES[i]
108                 for i in range(BASE_MATERIALS_COUNT)108                 for i in range(BASE_MATERIALS_COUNT)
109                 if BASE_MATERIALS_NAMES[i] in extracted_base_names]109                 if BASE_MATERIALS_NAMES[i] in extracted_base_names]
110            )110            )
111            current_class_density /= len(extracted_base_names)111            current_class_density /= len(extracted_base_names)
112112
113            self.alloys.append(type(current_class_name, (Material,), {"density": current_class_density}))113            self.alloys.append(type(current_class_name, (Material,), {"density": current_class_density}))
114114
115        for arg in args:115        for arg in args:
116            arg.is_used = True116            arg.is_used = True
117117
118        current_instance_mass = sum([arg.mass for arg in args])118        current_instance_mass = sum([arg.mass for arg in args])
119        current_class_type = next(cls for cls in self.alloys if cls.__name__ == current_class_name)119        current_class_type = next(cls for cls in self.alloys if cls.__name__ == current_class_name)
120        current_created_material = current_class_type(current_instance_mass)120        current_created_material = current_class_type(current_instance_mass)
121        self.created_materials.append(current_created_material)121        self.created_materials.append(current_created_material)
122        self.created_materials_from_factories.append(current_created_material)122        self.created_materials_from_factories.append(current_created_material)
123        return current_created_material123        return current_created_material
124124
125    def can_build(self, wall_volume):125    def can_build(self, wall_volume):
126        materials_volume = sum(mat.volume for mat in self.created_materials if not mat.is_used)126        materials_volume = sum(mat.volume for mat in self.created_materials if not mat.is_used)
127        return materials_volume >= wall_volume127        return materials_volume >= wall_volume
128128
129    @classmethod129    @classmethod
130    def can_build_together(cls, wall_volume):130    def can_build_together(cls, wall_volume):
131        materials_volume = sum(mat.volume for mat in cls.created_materials_from_factories if not mat.is_used)131        materials_volume = sum(mat.volume for mat in cls.created_materials_from_factories if not mat.is_used)
132        return materials_volume >= wall_volume132        return materials_volume >= wall_volume
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1CONCRETE_DENSITY = 2500f1CONCRETE_DENSITY = 2500
2BRICK_DENSITY = 20002BRICK_DENSITY = 2000
3STONE_DENSITY = 16003STONE_DENSITY = 1600
4WOOD_DENSITY = 6004WOOD_DENSITY = 600
5STEEL_DENSITY = 77005STEEL_DENSITY = 7700
nn6BASE_MATERIALS_COUNT = 5
6BASE_MATERIAL_DENSITIES = [BRICK_DENSITY,7BASE_MATERIAL_DENSITIES = [BRICK_DENSITY,
7                           CONCRETE_DENSITY,8                           CONCRETE_DENSITY,
8                           STEEL_DENSITY,9                           STEEL_DENSITY,
9                           STONE_DENSITY,10                           STONE_DENSITY,
10                           WOOD_DENSITY]11                           WOOD_DENSITY]
1112
12ERROR_MESSAGE = "6ff9dc6e00d1e166f1612e919e934af22eb204b931539f629e152324a2e5a221"13ERROR_MESSAGE = "6ff9dc6e00d1e166f1612e919e934af22eb204b931539f629e152324a2e5a221"
1314
1415
15class Material:16class Material:
16    density = 017    density = 0
1718
18    def __init__(self, mass):19    def __init__(self, mass):
19        self.mass = mass20        self.mass = mass
20        self.is_used = False21        self.is_used = False
2122
22    @property23    @property
23    def volume(self):24    def volume(self):
24        if self.density == 0:25        if self.density == 0:
n25            raise ValueError(ERROR_MESSAGE)n26            raise ZeroDivisionError(ERROR_MESSAGE)
26        return self.mass / self.density27        return self.mass / self.density
2728
2829
29class Concrete(Material):30class Concrete(Material):
3031
31    def __init__(self, mass):32    def __init__(self, mass):
32        super().__init__(mass)33        super().__init__(mass)
33        self.density = CONCRETE_DENSITY34        self.density = CONCRETE_DENSITY
3435
3536
36class Brick(Material):37class Brick(Material):
3738
38    def __init__(self, mass):39    def __init__(self, mass):
39        super().__init__(mass)40        super().__init__(mass)
40        self.density = BRICK_DENSITY41        self.density = BRICK_DENSITY
4142
4243
43class Stone(Material):44class Stone(Material):
4445
45    def __init__(self, mass):46    def __init__(self, mass):
46        super().__init__(mass)47        super().__init__(mass)
47        self.density = STONE_DENSITY48        self.density = STONE_DENSITY
4849
4950
50class Wood(Material):51class Wood(Material):
5152
52    def __init__(self, mass):53    def __init__(self, mass):
53        super().__init__(mass)54        super().__init__(mass)
54        self.density = WOOD_DENSITY55        self.density = WOOD_DENSITY
5556
5657
57class Steel(Material):58class Steel(Material):
5859
59    def __init__(self, mass):60    def __init__(self, mass):
60        super().__init__(mass)61        super().__init__(mass)
61        self.density = STEEL_DENSITY62        self.density = STEEL_DENSITY
6263
6364
n64base_materials_classes = [Brick, Concrete, Steel, Stone, Wood]n65BASE_MATERIAL_CLASSES = [Brick, Concrete, Steel, Stone, Wood]
65base_materials_names = [x.__name__ for x in base_materials_classes]66BASE_MATERIALS_NAMES = [x.__name__ for x in BASE_MATERIAL_CLASSES]
6667
6768
68class Factory:69class Factory:
n69    alloys = [*base_materials_classes]n70    alloys = [*BASE_MATERIAL_CLASSES]
70    created_materials_from_factories = []71    created_materials_from_factories = []
7172
72    def __init__(self):73    def __init__(self):
73        self.created_materials = []74        self.created_materials = []
7475
75    def __call__(self, *args, **kwargs):76    def __call__(self, *args, **kwargs):
76        if (args and kwargs) or (not args and not kwargs):77        if (args and kwargs) or (not args and not kwargs):
77            raise ValueError(ERROR_MESSAGE)78            raise ValueError(ERROR_MESSAGE)
7879
79        return self._kwargs_case_handler(**kwargs) if kwargs else self._args_case_handler(*args)80        return self._kwargs_case_handler(**kwargs) if kwargs else self._args_case_handler(*args)
8081
81    def _kwargs_case_handler(self, **kwargs):82    def _kwargs_case_handler(self, **kwargs):
n82        res = []n83        result = []
83        for class_name, mass in kwargs.items():84        for class_name, mass in kwargs.items():
84            class_type = next((cls for cls in self.alloys if cls.__name__ == class_name), None)85            class_type = next((cls for cls in self.alloys if cls.__name__ == class_name), None)
8586
86            if class_type is None:87            if class_type is None:
87                raise ValueError(ERROR_MESSAGE)88                raise ValueError(ERROR_MESSAGE)
8889
89            current_created_material = class_type(mass)90            current_created_material = class_type(mass)
90            self.created_materials.append(current_created_material)91            self.created_materials.append(current_created_material)
91            self.created_materials_from_factories.append(current_created_material)92            self.created_materials_from_factories.append(current_created_material)
n92            res.append(current_created_material)n93            result.append(current_created_material)
9394
n94        return tuple(res)n95        return tuple(result)
9596
96    def _args_case_handler(self, *args):97    def _args_case_handler(self, *args):
97        concatenated_names = "_".join([arg.__class__.__name__ for arg in args])98        concatenated_names = "_".join([arg.__class__.__name__ for arg in args])
98        extracted_base_names = set(concatenated_names.split("_"))99        extracted_base_names = set(concatenated_names.split("_"))
99        current_class_name = '_'.join(sorted(extracted_base_names))100        current_class_name = '_'.join(sorted(extracted_base_names))
100101
101        if any([arg.is_used for arg in args]):102        if any([arg.is_used for arg in args]):
102            raise AssertionError(ERROR_MESSAGE)103            raise AssertionError(ERROR_MESSAGE)
103104
104        if current_class_name not in [current_class.__name__ for current_class in self.alloys]:105        if current_class_name not in [current_class.__name__ for current_class in self.alloys]:
105            current_class_density = sum(106            current_class_density = sum(
106                [BASE_MATERIAL_DENSITIES[i]107                [BASE_MATERIAL_DENSITIES[i]
t107                 for i in range(0, 5)t108                 for i in range(BASE_MATERIALS_COUNT)
108                 if base_materials_names[i] in extracted_base_names]109                 if BASE_MATERIALS_NAMES[i] in extracted_base_names]
109            )110            )
110            current_class_density /= len(extracted_base_names)111            current_class_density /= len(extracted_base_names)
111112
112            self.alloys.append(type(current_class_name, (Material,), {"density": current_class_density}))113            self.alloys.append(type(current_class_name, (Material,), {"density": current_class_density}))
113114
114        for arg in args:115        for arg in args:
115            arg.is_used = True116            arg.is_used = True
116117
117        current_instance_mass = sum([arg.mass for arg in args])118        current_instance_mass = sum([arg.mass for arg in args])
118        current_class_type = next(cls for cls in self.alloys if cls.__name__ == current_class_name)119        current_class_type = next(cls for cls in self.alloys if cls.__name__ == current_class_name)
119        current_created_material = current_class_type(current_instance_mass)120        current_created_material = current_class_type(current_instance_mass)
120        self.created_materials.append(current_created_material)121        self.created_materials.append(current_created_material)
121        self.created_materials_from_factories.append(current_created_material)122        self.created_materials_from_factories.append(current_created_material)
122        return current_created_material123        return current_created_material
123124
124    def can_build(self, wall_volume):125    def can_build(self, wall_volume):
125        materials_volume = sum(mat.volume for mat in self.created_materials if not mat.is_used)126        materials_volume = sum(mat.volume for mat in self.created_materials if not mat.is_used)
126        return materials_volume >= wall_volume127        return materials_volume >= wall_volume
127128
128    @classmethod129    @classmethod
129    def can_build_together(cls, wall_volume):130    def can_build_together(cls, wall_volume):
130        materials_volume = sum(mat.volume for mat in cls.created_materials_from_factories if not mat.is_used)131        materials_volume = sum(mat.volume for mat in cls.created_materials_from_factories if not mat.is_used)
131        return materials_volume >= wall_volume132        return materials_volume >= wall_volume
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op