Skip to content

Commit 81c5477

Browse files
committed
Complete Laptop allocation exercise sprint 5
1 parent 407b010 commit 81c5477

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from dataclasses import dataclass
2+
from enum import Enum
3+
from typing import List, Dict, Optional, Tuple
4+
import itertools
5+
import sys
6+
7+
class OperatingSystem(Enum):
8+
MACOS = "macOS"
9+
ARCH = "Arch Linux"
10+
UBUNTU = "Ubuntu"
11+
12+
@dataclass(frozen=True)
13+
class Person:
14+
name: str
15+
age: int
16+
preferred_operating_system: List[OperatingSystem]
17+
18+
# custom hash to hash the immutable version of the list
19+
def __hash__(self) -> int:
20+
return hash((self.name, self.age, tuple(self.preferred_operating_system)))
21+
22+
23+
@dataclass(frozen=True)
24+
class Laptop:
25+
id: int
26+
manufacturer: str
27+
model: str
28+
screen_size_in_inches: float
29+
operating_system: OperatingSystem
30+
31+
# =====define parse operating system======
32+
def parse_operating_system(raw: str) -> OperatingSystem:
33+
normalized = raw.strip().lower()
34+
35+
aliases = {
36+
"macos": OperatingSystem.MACOS,
37+
"mac": OperatingSystem.MACOS,
38+
"arch": OperatingSystem.ARCH,
39+
"arch linux": OperatingSystem.ARCH,
40+
"ubuntu": OperatingSystem.UBUNTU,
41+
}
42+
43+
if normalized not in aliases:
44+
valid = ", ".join(sorted(aliases.keys()))
45+
print(f"Error: invalid operating system. Try one of: {valid}", file=sys.stderr)
46+
sys.exit(1)
47+
48+
return aliases[normalized]
49+
50+
# ======= sadness helper ============
51+
def sadness(person: Person, laptop: Laptop) -> int:
52+
laptop_os = laptop.operating_system
53+
preferences = person.preferred_operating_system
54+
if laptop_os not in preferences:
55+
return 100
56+
return preferences.index(laptop_os)
57+
58+
# ======= Laptop allocation ============
59+
def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]:
60+
if len(laptops) < len(people):
61+
raise ValueError("Not enough laptops to allocate one per person.")
62+
63+
best_assignment: Optional[Dict[Person, Laptop]] = None
64+
best_total_sadness: Optional[int] = None
65+
66+
for chosen_laptops in itertools.combinations(laptops, len(people)):
67+
for permuted_laptops in itertools.permutations(chosen_laptops):
68+
total = 0
69+
for i in range(len(people)):
70+
person = people[i]
71+
laptop = permuted_laptops[i]
72+
total += sadness(person, laptop)
73+
74+
if best_total_sadness is None or total < best_total_sadness:
75+
best_total_sadness = total
76+
best_assignment = {people[i]: permuted_laptops[i] for i in range(len(people))}
77+
78+
if best_assignment is None:
79+
raise RuntimeError("Allocation failed unexpectedly.")
80+
81+
return best_assignment
82+
83+
# ======define main ================
84+
def main() -> None:
85+
laptops = [
86+
Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13.0, operating_system=OperatingSystem.ARCH),
87+
Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15.0, operating_system=OperatingSystem.UBUNTU),
88+
Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15.0, operating_system=OperatingSystem.UBUNTU),
89+
Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13.0, operating_system=OperatingSystem.MACOS),
90+
]
91+
92+
people = [
93+
Person(name="Imran", age=22, preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH, OperatingSystem.MACOS]),
94+
Person(name="Eliza", age=34, preferred_operating_system=[OperatingSystem.ARCH, OperatingSystem.UBUNTU])
95+
]
96+
97+
allocation = allocate_laptops(people, laptops)
98+
99+
# Print results
100+
for person, laptop in allocation.items():
101+
print(f"{person.name}: Laptop {laptop.id} ({laptop.operating_system.value}) sadness={sadness(person, laptop)}")
102+
103+
if __name__ == "__main__":
104+
main()

0 commit comments

Comments
 (0)