Домашни > Another brick in the wall > Решения > Решението на Валентина Петрова

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

11 точки общо

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

  1from abc import ABC, abstractmethod
  2
  3
  4class BaseMaterial(ABC):
  5    def __init__(self, mass: int):
  6        self.mass = mass
  7        self.used = False
  8
  9    """Subclasses must define the density."""
 10
 11    @property
 12    @abstractmethod
 13    def density(self):
 14        ...
 15
 16    @property
 17    def volume(self):
 18        return self.mass / self.density
 19
 20    def mark_used(self):
 21        if self.used:
 22            raise AssertionError("Material has already been used.")
 23        self.used = False
 24
 25
 26class Concrete(BaseMaterial):
 27    density = 2500
 28
 29
 30class Brick(BaseMaterial):
 31    density = 2000
 32
 33
 34class Stone(BaseMaterial):
 35    density = 1600
 36
 37
 38class Wood(BaseMaterial):
 39    density = 600
 40
 41
 42class Steel(BaseMaterial):
 43    density = 7700
 44
 45
 46class Factory:
 47
 48    """Use a dictionary because the search is less complex."""
 49    _materials_registry = {
 50        "Concrete": Concrete,
 51        "Brick": Brick,
 52        "Stone": Stone,
 53        "Wood": Wood,
 54        "Steel": Steel}
 55    all_created_materials = []
 56
 57    def __init__(self):
 58        self.created_materials = []
 59
 60    def __call__(self, *args, **kwargs):
 61        if args and kwargs:
 62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
 63        if not args and not kwargs:
 64            raise ValueError("Factory must be called with at least one argument.")
 65
 66        if kwargs:
 67            return self._create_named_materials(kwargs)
 68        elif args:
 69            return self._create_new(args)
 70
 71    def _create_named_materials(self, kwargs):
 72        materials = []
 73        for name, mass in kwargs.items():
 74            material_class = Factory._materials_registry.get(name)
 75            if not material_class:
 76                raise ValueError(f"Unknown material type: {name}")
 77
 78            material = material_class(mass)
 79            material.mark_used()
 80            materials.append(material)
 81            self.created_materials.append(material)
 82            Factory.all_created_materials.append(material)
 83        return tuple(materials)
 84
 85    def _create_new(self, args):
 86        for material in args:
 87            if material.used:
 88                raise AssertionError(
 89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
 90
 91        # Retrieve the original components of the materials (if composite) - needed for density calculation
 92        components = []
 93        for material in args:
 94            if hasattr(material, "_components"):
 95                components.extend(material._components)
 96            else:
 97                components.append(material)
 98
 99        for arg in args:
100            arg.used = True
101
102        material_classes = sorted({type(component).__name__ for component in components})
103        alloy_name = "_".join(material_classes)
104
105        if alloy_name in Factory._materials_registry:
106            alloy_class = Factory._materials_registry[alloy_name]
107        else:
108            average_density = sum(component.density for component in components) / len(components)
109            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
110            Factory._materials_registry[alloy_name] = alloy_class
111
112        total_mass = sum(component.mass for component in components)
113        alloy_instance = alloy_class(total_mass)
114        alloy_instance._components = components
115
116        self.created_materials.append(alloy_instance)
117        Factory.all_created_materials.append(alloy_instance)
118        return alloy_instance
119
120    def can_build(self, required_volume):
121        total = sum(material.volume for material in self.created_materials if not material.used)
122        return total >= required_volume
123
124    @staticmethod
125    def can_build_together(required_volume):
126        total = sum(material.volume for material in  Factory.all_created_materials if not material.used)
127        return total >= required_volume

..........
----------------------------------------------------------------------
Ran 10 tests in 0.010s

OK

Дискусия
История

f1from abc import ABC, abstractmethodf1from abc import ABC, abstractmethod
22
33
n4class BaseMaterial:n4class BaseMaterial(ABC):
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
n14        passn14        ...
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
n23        self.used = Truen23        self.used = False
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
79            material.mark_used()79            material.mark_used()
80            materials.append(material)80            materials.append(material)
81            self.created_materials.append(material)81            self.created_materials.append(material)
82            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
83        return tuple(materials)83        return tuple(materials)
8484
85    def _create_new(self, args):85    def _create_new(self, args):
86        for material in args:86        for material in args:
87            if material.used:87            if material.used:
88                raise AssertionError(88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
9090
91        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
92        components = []92        components = []
93        for material in args:93        for material in args:
94            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
95                components.extend(material._components)95                components.extend(material._components)
96            else:96            else:
97                components.append(material)97                components.append(material)
nn98 
99        for arg in args:
100            arg.used = True
101 
98        material_classes = sorted({type(component).__name__ for component in components})102        material_classes = sorted({type(component).__name__ for component in components})
99        alloy_name = "_".join(material_classes)103        alloy_name = "_".join(material_classes)
100104
101        if alloy_name in Factory._materials_registry:105        if alloy_name in Factory._materials_registry:
102            alloy_class = Factory._materials_registry[alloy_name]106            alloy_class = Factory._materials_registry[alloy_name]
103        else:107        else:
104            average_density = sum(component.density for component in components) / len(components)108            average_density = sum(component.density for component in components) / len(components)
105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})109            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
106            Factory._materials_registry[alloy_name] = alloy_class110            Factory._materials_registry[alloy_name] = alloy_class
107111
108        total_mass = sum(component.mass for component in components)112        total_mass = sum(component.mass for component in components)
109        alloy_instance = alloy_class(total_mass)113        alloy_instance = alloy_class(total_mass)
110        alloy_instance._components = components114        alloy_instance._components = components
111115
112        self.created_materials.append(alloy_instance)116        self.created_materials.append(alloy_instance)
113        Factory.all_created_materials.append(alloy_instance)117        Factory.all_created_materials.append(alloy_instance)
114        return alloy_instance118        return alloy_instance
115119
116    def can_build(self, required_volume):120    def can_build(self, required_volume):
n117        total_volume = 0n121        total = sum(material.volume for material in self.created_materials if not material.used)
118        for material in self.created_materials:
119            if not material.used:
120                material.mark_used()
121                total_volume += material.volume
122        return total_volume < required_volume122        return total >= required_volume
123123
124    @staticmethod124    @staticmethod
125    def can_build_together(required_volume):125    def can_build_together(required_volume):
t126        total_volume = 0t126        total = sum(material.volume for material in  Factory.all_created_materials if not material.used)
127        for material in Factory.all_created_materials:
128            if not material.used:
129                material.mark_used()
130                total_volume += material.volume
131        return total_volume < required_volume127        return total >= required_volume
132 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

t1from abc import ABC, abstractmethodt1from abc import ABC, abstractmethod
22
33
4class BaseMaterial:4class BaseMaterial:
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
14        pass14        pass
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
23        self.used = True23        self.used = True
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
79            material.mark_used()79            material.mark_used()
80            materials.append(material)80            materials.append(material)
81            self.created_materials.append(material)81            self.created_materials.append(material)
82            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
83        return tuple(materials)83        return tuple(materials)
8484
85    def _create_new(self, args):85    def _create_new(self, args):
86        for material in args:86        for material in args:
87            if material.used:87            if material.used:
88                raise AssertionError(88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
9090
91        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
92        components = []92        components = []
93        for material in args:93        for material in args:
94            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
95                components.extend(material._components)95                components.extend(material._components)
96            else:96            else:
97                components.append(material)97                components.append(material)
98        material_classes = sorted({type(component).__name__ for component in components})98        material_classes = sorted({type(component).__name__ for component in components})
99        alloy_name = "_".join(material_classes)99        alloy_name = "_".join(material_classes)
100100
101        if alloy_name in Factory._materials_registry:101        if alloy_name in Factory._materials_registry:
102            alloy_class = Factory._materials_registry[alloy_name]102            alloy_class = Factory._materials_registry[alloy_name]
103        else:103        else:
104            average_density = sum(component.density for component in components) / len(components)104            average_density = sum(component.density for component in components) / len(components)
105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
106            Factory._materials_registry[alloy_name] = alloy_class106            Factory._materials_registry[alloy_name] = alloy_class
107107
108        total_mass = sum(component.mass for component in components)108        total_mass = sum(component.mass for component in components)
109        alloy_instance = alloy_class(total_mass)109        alloy_instance = alloy_class(total_mass)
110        alloy_instance._components = components110        alloy_instance._components = components
111111
112        self.created_materials.append(alloy_instance)112        self.created_materials.append(alloy_instance)
113        Factory.all_created_materials.append(alloy_instance)113        Factory.all_created_materials.append(alloy_instance)
114        return alloy_instance114        return alloy_instance
115115
116    def can_build(self, required_volume):116    def can_build(self, required_volume):
117        total_volume = 0117        total_volume = 0
118        for material in self.created_materials:118        for material in self.created_materials:
119            if not material.used:119            if not material.used:
120                material.mark_used()120                material.mark_used()
121                total_volume += material.volume121                total_volume += material.volume
122        return total_volume < required_volume122        return total_volume < required_volume
123123
124    @staticmethod124    @staticmethod
125    def can_build_together(required_volume):125    def can_build_together(required_volume):
126        total_volume = 0126        total_volume = 0
127        for material in Factory.all_created_materials:127        for material in Factory.all_created_materials:
128            if not material.used:128            if not material.used:
129                material.mark_used()129                material.mark_used()
130                total_volume += material.volume130                total_volume += material.volume
131        return total_volume < required_volume131        return total_volume < required_volume
132132
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1from abc import ABC, abstractmethodf1from abc import ABC, abstractmethod
22
33
4class BaseMaterial:4class BaseMaterial:
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
14        pass14        pass
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
23        self.used = True23        self.used = True
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
79            material.mark_used()79            material.mark_used()
80            materials.append(material)80            materials.append(material)
81            self.created_materials.append(material)81            self.created_materials.append(material)
82            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
83        return tuple(materials)83        return tuple(materials)
8484
85    def _create_new(self, args):85    def _create_new(self, args):
86        for material in args:86        for material in args:
87            if material.used:87            if material.used:
88                raise AssertionError(88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
9090
91        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
92        components = []92        components = []
93        for material in args:93        for material in args:
94            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
95                components.extend(material._components)95                components.extend(material._components)
96            else:96            else:
97                components.append(material)97                components.append(material)
98        material_classes = sorted({type(component).__name__ for component in components})98        material_classes = sorted({type(component).__name__ for component in components})
99        alloy_name = "_".join(material_classes)99        alloy_name = "_".join(material_classes)
100100
101        if alloy_name in Factory._materials_registry:101        if alloy_name in Factory._materials_registry:
102            alloy_class = Factory._materials_registry[alloy_name]102            alloy_class = Factory._materials_registry[alloy_name]
103        else:103        else:
104            average_density = sum(component.density for component in components) / len(components)104            average_density = sum(component.density for component in components) / len(components)
105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
106            Factory._materials_registry[alloy_name] = alloy_class106            Factory._materials_registry[alloy_name] = alloy_class
107107
108        total_mass = sum(component.mass for component in components)108        total_mass = sum(component.mass for component in components)
109        alloy_instance = alloy_class(total_mass)109        alloy_instance = alloy_class(total_mass)
110        alloy_instance._components = components110        alloy_instance._components = components
111111
112        self.created_materials.append(alloy_instance)112        self.created_materials.append(alloy_instance)
113        Factory.all_created_materials.append(alloy_instance)113        Factory.all_created_materials.append(alloy_instance)
114        return alloy_instance114        return alloy_instance
115115
116    def can_build(self, required_volume):116    def can_build(self, required_volume):
117        total_volume = 0117        total_volume = 0
118        for material in self.created_materials:118        for material in self.created_materials:
119            if not material.used:119            if not material.used:
120                material.mark_used()120                material.mark_used()
121                total_volume += material.volume121                total_volume += material.volume
122        return total_volume < required_volume122        return total_volume < required_volume
123123
124    @staticmethod124    @staticmethod
125    def can_build_together(required_volume):125    def can_build_together(required_volume):
126        total_volume = 0126        total_volume = 0
127        for material in Factory.all_created_materials:127        for material in Factory.all_created_materials:
128            if not material.used:128            if not material.used:
129                material.mark_used()129                material.mark_used()
130                total_volume += material.volume130                total_volume += material.volume
131        return total_volume < required_volume131        return total_volume < required_volume
132132
t133 t
134factory = Factory()
135brick, wood = factory(Brick=10, Wood=5)
136brick_wood = factory(brick, wood)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

t1from abc import ABC, abstractmethodt1from abc import ABC, abstractmethod
22
33
4class BaseMaterial:4class BaseMaterial:
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
14        pass14        pass
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
23        self.used = True23        self.used = True
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
79            material.mark_used()79            material.mark_used()
80            materials.append(material)80            materials.append(material)
81            self.created_materials.append(material)81            self.created_materials.append(material)
82            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
83        return tuple(materials)83        return tuple(materials)
8484
85    def _create_new(self, args):85    def _create_new(self, args):
86        for material in args:86        for material in args:
87            if material.used:87            if material.used:
88                raise AssertionError(88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
9090
91        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
92        components = []92        components = []
93        for material in args:93        for material in args:
94            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
95                components.extend(material._components)95                components.extend(material._components)
96            else:96            else:
97                components.append(material)97                components.append(material)
98        material_classes = sorted({type(component).__name__ for component in components})98        material_classes = sorted({type(component).__name__ for component in components})
99        alloy_name = "_".join(material_classes)99        alloy_name = "_".join(material_classes)
100100
101        if alloy_name in Factory._materials_registry:101        if alloy_name in Factory._materials_registry:
102            alloy_class = Factory._materials_registry[alloy_name]102            alloy_class = Factory._materials_registry[alloy_name]
103        else:103        else:
104            average_density = sum(component.density for component in components) / len(components)104            average_density = sum(component.density for component in components) / len(components)
105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
106            Factory._materials_registry[alloy_name] = alloy_class106            Factory._materials_registry[alloy_name] = alloy_class
107107
108        total_mass = sum(component.mass for component in components)108        total_mass = sum(component.mass for component in components)
109        alloy_instance = alloy_class(total_mass)109        alloy_instance = alloy_class(total_mass)
110        alloy_instance._components = components110        alloy_instance._components = components
111111
112        self.created_materials.append(alloy_instance)112        self.created_materials.append(alloy_instance)
113        Factory.all_created_materials.append(alloy_instance)113        Factory.all_created_materials.append(alloy_instance)
114        return alloy_instance114        return alloy_instance
115115
116    def can_build(self, required_volume):116    def can_build(self, required_volume):
117        total_volume = 0117        total_volume = 0
118        for material in self.created_materials:118        for material in self.created_materials:
119            if not material.used:119            if not material.used:
120                material.mark_used()120                material.mark_used()
121                total_volume += material.volume121                total_volume += material.volume
122        return total_volume < required_volume122        return total_volume < required_volume
123123
124    @staticmethod124    @staticmethod
125    def can_build_together(required_volume):125    def can_build_together(required_volume):
126        total_volume = 0126        total_volume = 0
127        for material in Factory.all_created_materials:127        for material in Factory.all_created_materials:
128            if not material.used:128            if not material.used:
129                material.mark_used()129                material.mark_used()
130                total_volume += material.volume130                total_volume += material.volume
131        return total_volume < required_volume131        return total_volume < required_volume
132132
133133
134factory = Factory()134factory = Factory()
135brick, wood = factory(Brick=10, Wood=5)135brick, wood = factory(Brick=10, Wood=5)
136brick_wood = factory(brick, wood)136brick_wood = factory(brick, wood)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

t1from abc import ABC, abstractmethodt1from abc import ABC, abstractmethod
22
33
4class BaseMaterial:4class BaseMaterial:
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
14        pass14        pass
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
23        self.used = True23        self.used = True
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
79            material.mark_used()79            material.mark_used()
80            materials.append(material)80            materials.append(material)
81            self.created_materials.append(material)81            self.created_materials.append(material)
82            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
83        return tuple(materials)83        return tuple(materials)
8484
85    def _create_new(self, args):85    def _create_new(self, args):
86        for material in args:86        for material in args:
87            if material.used:87            if material.used:
88                raise AssertionError(88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
9090
91        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
92        components = []92        components = []
93        for material in args:93        for material in args:
94            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
95                components.extend(material._components)95                components.extend(material._components)
96            else:96            else:
97                components.append(material)97                components.append(material)
98        material_classes = sorted({type(component).__name__ for component in components})98        material_classes = sorted({type(component).__name__ for component in components})
99        alloy_name = "_".join(material_classes)99        alloy_name = "_".join(material_classes)
100100
101        if alloy_name in Factory._materials_registry:101        if alloy_name in Factory._materials_registry:
102            alloy_class = Factory._materials_registry[alloy_name]102            alloy_class = Factory._materials_registry[alloy_name]
103        else:103        else:
104            average_density = sum(component.density for component in components) / len(components)104            average_density = sum(component.density for component in components) / len(components)
105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
106            Factory._materials_registry[alloy_name] = alloy_class106            Factory._materials_registry[alloy_name] = alloy_class
107107
108        total_mass = sum(component.mass for component in components)108        total_mass = sum(component.mass for component in components)
109        alloy_instance = alloy_class(total_mass)109        alloy_instance = alloy_class(total_mass)
110        alloy_instance._components = components110        alloy_instance._components = components
111111
112        self.created_materials.append(alloy_instance)112        self.created_materials.append(alloy_instance)
113        Factory.all_created_materials.append(alloy_instance)113        Factory.all_created_materials.append(alloy_instance)
114        return alloy_instance114        return alloy_instance
115115
116    def can_build(self, required_volume):116    def can_build(self, required_volume):
117        total_volume = 0117        total_volume = 0
118        for material in self.created_materials:118        for material in self.created_materials:
119            if not material.used:119            if not material.used:
120                material.mark_used()120                material.mark_used()
121                total_volume += material.volume121                total_volume += material.volume
122        return total_volume < required_volume122        return total_volume < required_volume
123123
124    @staticmethod124    @staticmethod
125    def can_build_together(required_volume):125    def can_build_together(required_volume):
126        total_volume = 0126        total_volume = 0
127        for material in Factory.all_created_materials:127        for material in Factory.all_created_materials:
128            if not material.used:128            if not material.used:
129                material.mark_used()129                material.mark_used()
130                total_volume += material.volume130                total_volume += material.volume
131        return total_volume < required_volume131        return total_volume < required_volume
132132
133133
134factory = Factory()134factory = Factory()
135brick, wood = factory(Brick=10, Wood=5)135brick, wood = factory(Brick=10, Wood=5)
136brick_wood = factory(brick, wood)136brick_wood = factory(brick, wood)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1from abc import ABC, abstractmethodf1from abc import ABC, abstractmethod
22
33
4class BaseMaterial:4class BaseMaterial:
5    def __init__(self, mass: int):5    def __init__(self, mass: int):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    """Subclasses must define the density."""9    """Subclasses must define the density."""
1010
11    @property11    @property
12    @abstractmethod12    @abstractmethod
13    def density(self):13    def density(self):
14        pass14        pass
1515
16    @property16    @property
17    def volume(self):17    def volume(self):
18        return self.mass / self.density18        return self.mass / self.density
1919
20    def mark_used(self):20    def mark_used(self):
21        if self.used:21        if self.used:
22            raise AssertionError("Material has already been used.")22            raise AssertionError("Material has already been used.")
23        self.used = True23        self.used = True
2424
2525
26class Concrete(BaseMaterial):26class Concrete(BaseMaterial):
27    density = 250027    density = 2500
2828
2929
30class Brick(BaseMaterial):30class Brick(BaseMaterial):
31    density = 200031    density = 2000
3232
3333
34class Stone(BaseMaterial):34class Stone(BaseMaterial):
35    density = 160035    density = 1600
3636
3737
38class Wood(BaseMaterial):38class Wood(BaseMaterial):
39    density = 60039    density = 600
4040
4141
42class Steel(BaseMaterial):42class Steel(BaseMaterial):
43    density = 770043    density = 7700
4444
4545
46class Factory:46class Factory:
4747
48    """Use a dictionary because the search is less complex."""48    """Use a dictionary because the search is less complex."""
49    _materials_registry = {49    _materials_registry = {
50        "Concrete": Concrete,50        "Concrete": Concrete,
51        "Brick": Brick,51        "Brick": Brick,
52        "Stone": Stone,52        "Stone": Stone,
53        "Wood": Wood,53        "Wood": Wood,
54        "Steel": Steel}54        "Steel": Steel}
55    all_created_materials = []55    all_created_materials = []
5656
57    def __init__(self):57    def __init__(self):
58        self.created_materials = []58        self.created_materials = []
5959
60    def __call__(self, *args, **kwargs):60    def __call__(self, *args, **kwargs):
61        if args and kwargs:61        if args and kwargs:
62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")62            raise ValueError("Factory must be called with only positional or keyword arguments, not both.")
63        if not args and not kwargs:63        if not args and not kwargs:
64            raise ValueError("Factory must be called with at least one argument.")64            raise ValueError("Factory must be called with at least one argument.")
6565
66        if kwargs:66        if kwargs:
67            return self._create_named_materials(kwargs)67            return self._create_named_materials(kwargs)
68        elif args:68        elif args:
69            return self._create_new(args)69            return self._create_new(args)
7070
71    def _create_named_materials(self, kwargs):71    def _create_named_materials(self, kwargs):
72        materials = []72        materials = []
73        for name, mass in kwargs.items():73        for name, mass in kwargs.items():
74            material_class = Factory._materials_registry.get(name)74            material_class = Factory._materials_registry.get(name)
75            if not material_class:75            if not material_class:
76                raise ValueError(f"Unknown material type: {name}")76                raise ValueError(f"Unknown material type: {name}")
7777
78            material = material_class(mass)78            material = material_class(mass)
nn79            material.mark_used()
79            materials.append(material)80            materials.append(material)
80            self.created_materials.append(material)81            self.created_materials.append(material)
81            Factory.all_created_materials.append(material)82            Factory.all_created_materials.append(material)
82        return tuple(materials)83        return tuple(materials)
8384
84    def _create_new(self, args):85    def _create_new(self, args):
nn86        for material in args:
87            if material.used:
88                raise AssertionError(
89                    f"Material {material.__class__.__name__} has already been used and cannot be reused.")
90 
85        # Retrieve the original components of the materials (if composite) - needed for density calculation91        # Retrieve the original components of the materials (if composite) - needed for density calculation
86        components = []92        components = []
87        for material in args:93        for material in args:
88            if hasattr(material, "_components"):94            if hasattr(material, "_components"):
89                components.extend(material._components)95                components.extend(material._components)
90            else:96            else:
91                components.append(material)97                components.append(material)
92        material_classes = sorted({type(component).__name__ for component in components})98        material_classes = sorted({type(component).__name__ for component in components})
93        alloy_name = "_".join(material_classes)99        alloy_name = "_".join(material_classes)
94100
95        if alloy_name in Factory._materials_registry:101        if alloy_name in Factory._materials_registry:
96            alloy_class = Factory._materials_registry[alloy_name]102            alloy_class = Factory._materials_registry[alloy_name]
97        else:103        else:
98            average_density = sum(component.density for component in components) / len(components)104            average_density = sum(component.density for component in components) / len(components)
99            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})105            alloy_class = type(alloy_name, (BaseMaterial,), {"density": average_density})
100            Factory._materials_registry[alloy_name] = alloy_class106            Factory._materials_registry[alloy_name] = alloy_class
101107
102        total_mass = sum(component.mass for component in components)108        total_mass = sum(component.mass for component in components)
103        alloy_instance = alloy_class(total_mass)109        alloy_instance = alloy_class(total_mass)
104        alloy_instance._components = components110        alloy_instance._components = components
105111
106        self.created_materials.append(alloy_instance)112        self.created_materials.append(alloy_instance)
107        Factory.all_created_materials.append(alloy_instance)113        Factory.all_created_materials.append(alloy_instance)
108        return alloy_instance114        return alloy_instance
109115
110    def can_build(self, required_volume):116    def can_build(self, required_volume):
111        total_volume = 0117        total_volume = 0
112        for material in self.created_materials:118        for material in self.created_materials:
113            if not material.used:119            if not material.used:
114                material.mark_used()120                material.mark_used()
115                total_volume += material.volume121                total_volume += material.volume
116        return total_volume < required_volume122        return total_volume < required_volume
117123
118    @staticmethod124    @staticmethod
119    def can_build_together(required_volume):125    def can_build_together(required_volume):
120        total_volume = 0126        total_volume = 0
121        for material in Factory.all_created_materials:127        for material in Factory.all_created_materials:
122            if not material.used:128            if not material.used:
123                material.mark_used()129                material.mark_used()
124                total_volume += material.volume130                total_volume += material.volume
125        return total_volume < required_volume131        return total_volume < required_volume
126132
127133
128factory = Factory()134factory = Factory()
t129factory(Brick(1500))t135brick, wood = factory(Brick=10, Wood=5)
130print(factory.can_build(1))136brick_wood = factory(brick, wood)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op