11from dataclasses import dataclass
22from enum import Enum
33from typing import Dict , List
4- import sys
54import numpy as np #to build and mnaiplate our sadness grid
65from scipy .optimize import linear_sum_assignment #to find optimal laptop allocaation to minimize sadness across all users
76
@@ -15,7 +14,7 @@ class Person:
1514 name : str
1615 age : int
1716 # Sorted in order of preference, most preferred is first.
18- preferred_operating_systems : List [OperatingSystem ]
17+ preferred_operating_systems : tuple [OperatingSystem ]
1918
2019
2120@dataclass (frozen = True )
@@ -27,7 +26,7 @@ class Laptop:
2726 operating_system : OperatingSystem
2827
2928#library of laptops
30- laptop = [
29+ laptops = [
3130 Laptop (id = 1 , manufacturer = "Dell" , model = "XPS" , screen_size_in_inches = 13 , operating_system = OperatingSystem .ARCH ),
3231 Laptop (id = 2 , manufacturer = "Dell" , model = "XPS" , screen_size_in_inches = 15 , operating_system = OperatingSystem .UBUNTU ),
3332 Laptop (id = 3 , manufacturer = "Dell" , model = "XPS" , screen_size_in_inches = 15 , operating_system = OperatingSystem .UBUNTU ),
@@ -39,28 +38,42 @@ class Laptop:
3938]
4039# Preset dataset of people
4140people = [
42- Person (name = "Sara" , age = 31 , preferred_operating_systems = [ OperatingSystem .ARCH ,OperatingSystem .UBUNTU ] ),
43- Person (name = "Shabs" , age = 40 , preferred_operating_systems = [ OperatingSystem .ARCH ,OperatingSystem .MACOS ,OperatingSystem .UBUNTU ] ),
44- Person (name = "Jawad" , age = 36 , preferred_operating_systems = [ OperatingSystem .MACOS ,OperatingSystem .UBUNTU ,OperatingSystem .ARCH ] ),
45- Person (name = "Mike" , age = 35 , preferred_operating_systems = [ OperatingSystem .MACOS ,OperatingSystem .ARCH ] ),
46- Person (name = "Mawra" , age = 28 , preferred_operating_systems = [ OperatingSystem .MACOS ]),
47- Person (name = "Fatma" , age = 22 , preferred_operating_systems = [ OperatingSystem .UBUNTU ,OperatingSystem .ARCH ] ),
48- Person (name = "Muhib" , age = 19 , preferred_operating_systems = [ OperatingSystem .MACOS ,OperatingSystem .UBUNTU ] ),
41+ Person (name = "Sara" , age = 31 , preferred_operating_systems = ( OperatingSystem .ARCH ,OperatingSystem .UBUNTU ) ),
42+ Person (name = "Shabs" , age = 40 , preferred_operating_systems = ( OperatingSystem .ARCH ,OperatingSystem .MACOS ,OperatingSystem .UBUNTU ) ),
43+ Person (name = "Jawad" , age = 36 , preferred_operating_systems = ( OperatingSystem .MACOS ,OperatingSystem .UBUNTU ,OperatingSystem .ARCH ) ),
44+ Person (name = "Mike" , age = 35 , preferred_operating_systems = ( OperatingSystem .MACOS ,OperatingSystem .ARCH ) ),
45+ Person (name = "Mawra" , age = 28 , preferred_operating_systems = ( OperatingSystem .MACOS ,)), #adding a comma for one item tuple
46+ Person (name = "Fatma" , age = 22 , preferred_operating_systems = ( OperatingSystem .UBUNTU ,OperatingSystem .ARCH ) ),
47+ Person (name = "Muhib" , age = 19 , preferred_operating_systems = ( OperatingSystem .MACOS ,OperatingSystem .UBUNTU ) ),
4948
5049]
5150
51+
52+ # Updated based on feedback:
53+ # Instead of hard‑coding sadness scores (0, 1, 2), this version uses the
54+ # position of the laptop’s OS in the person’s preference list to decide the sadness value.
55+ # I check for membership first (so no exceptions), then
56+ # use the index as the rank. Only the top MAX_HAPPY_RANK preferences count;
57+ # anything lower or not listed gets a high penalty.
58+
59+ MAX_HAPPY_RANK = 3
60+ TERRIBLE_SADNESS = 100
5261def sadness (person : Person , laptop : Laptop ) -> int :
53- if laptop .operating_system == person .preferred_operating_systems [0 ]:
54- return 0
55- elif len (person .preferred_operating_systems ) > 1 and laptop .operating_system == person .preferred_operating_systems [1 ]:
56- return 1
57- elif len (person .preferred_operating_systems ) > 2 and laptop .operating_system == person .preferred_operating_systems [2 ]:
58- return 2
59- else :
60- return 100
61-
62- #I have chose to use Hungarian Algorithm Approach to solve the problem.
62+ prefs = person .preferred_operating_systems
63+
64+ if laptop .operating_system not in prefs :
65+ return TERRIBLE_SADNESS
6366
67+ rank = prefs .index (laptop .operating_system )
68+
69+ return rank if rank < MAX_HAPPY_RANK else TERRIBLE_SADNESS
70+
71+ #Allocate laptops to people in a way that minimises total sadness.
72+ #Builds a cost matrix using the sadness() function and applies the
73+ #Hungarian algorithm (linear_sum_assignment) to find the optimal
74+ #one‑to‑one assignment between people and laptops.
75+
76+
6477def allocate_laptops (people : List [Person ], laptops : List [Laptop ]) -> Dict [Person , Laptop ]:
6578 n_people = len (people ) #length of people []
6679 n_laptops = len (laptops ) #length of laptops []
@@ -73,15 +86,15 @@ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person
7386 # Hungarian algorithm to run on our sadness matrix
7487 row_indices , col_indices = linear_sum_assignment (sadness_matrix ) #which person which laptop
7588 # Map people to laptops
76- allocation = {}
89+ allocation : Dict [ Person , Laptop ] = {}
7790 for i , j in zip (row_indices , col_indices ):#it pairs up results (person indices and laptop indices). The loop then uses those pairs to build the final allocation dictionary
78- allocation [people [i ]. name ] = laptops [j ]
91+ allocation [people [i ]] = laptops [j ]
7992 return allocation
8093
8194
8295def print_allocation (allocation : Dict [Person , Laptop ]):
83- for name , lap in allocation .items ():
84- print (f"{ name } gets Laptop { lap .id } ({ lap .operating_system .value } )" )
96+ for person , lap in allocation .items ():
97+ print (f"{ person . name } gets Laptop { lap .id } ({ lap .operating_system .value } )" )
8598
86- allocation = allocate_laptops (people , laptop )
99+ allocation = allocate_laptops (people , laptops )
87100print_allocation (allocation )
0 commit comments