From 7671cbcb63e4b33ad585c544bf16dd19bd81058d Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:52:49 +0000 Subject: [PATCH 1/7] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3c3629e6..274d0491 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.venv \ No newline at end of file From ffdcea1e5992caca4641c8052f196e1cbc2a913b Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:01:57 +0000 Subject: [PATCH 2/7] Initialise the laptop allocation file --- laptop_allocation/laptop_allocation.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 laptop_allocation/laptop_allocation.py diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py new file mode 100644 index 00000000..713bcd7a --- /dev/null +++ b/laptop_allocation/laptop_allocation.py @@ -0,0 +1,24 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + # Sorted in order of preference, most preferred is first. + preferred_operating_system: List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem \ No newline at end of file From 333ea487f97ef0820438ed47c1fef906ec525fd9 Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:18:08 +0000 Subject: [PATCH 3/7] Add find_preferred_laptops and calculate_sadness helper functions --- laptop_allocation/laptop_allocation.py | 90 +++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py index 713bcd7a..5836d409 100644 --- a/laptop_allocation/laptop_allocation.py +++ b/laptop_allocation/laptop_allocation.py @@ -1,12 +1,19 @@ from dataclasses import dataclass from enum import Enum from typing import List +from typing import Dict +# ============================================================================ +# ENUM DEFINITIONS +# ============================================================================ class OperatingSystem(Enum): MACOS = "macOS" ARCH = "Arch Linux" UBUNTU = "Ubuntu" +# ============================================================================ +# DATA CLASSES +# ============================================================================ @dataclass(frozen=True) class Person: name: str @@ -21,4 +28,85 @@ class Laptop: manufacturer: str model: str screen_size_in_inches: float - operating_system: OperatingSystem \ No newline at end of file + operating_system: OperatingSystem + +# ============================================================================ +# HELPER FUNCTIONS +# ============================================================================ +""" + Calculates how "sad" a person would be with a given laptop allocation. + + Sadness is defined as the position (0-indexed) of the laptop's OS + in the person's preference list. For example: + - If preferences are [UBUNTU, ARCH, MACOS] and they get UBUNTU: sadness = 0 + - If preferences are [UBUNTU, ARCH, MACOS] and they get ARCH: sadness = 1 + - If preferences are [UBUNTU, ARCH, MACOS] and they get MACOS: sadness = 2 + - If they get an OS not in their preferences: sadness = 100 + + Args: + person: The person receiving the laptop + laptop: The laptop being allocated + + Returns: + An integer representing sadness (0 = most happy, 100 = not in preferences) + """ +def find_preferred_laptops(person:Person, laptops: List[Laptop]) -> list[Laptop]: + preferred_laptops = [] + for laptop in laptops: + if laptop.operating_system in person.preferred_operating_system: + preferred_laptops.append(laptop) + return preferred_laptops + +def calculate_sadness(person:Person, laptop:Laptop)-> int: + if laptop.operating_system in person.preferred_operating_system: + # Find the index (position) of this OS in their preference list + sadness = person.preferred_operating_system.index(laptop.operating_system) + return sadness + else: + # OS not in preferences = very sad + return 100 + +# ============================================================================ +# TEST DATA +# ============================================================================ + +laptops = [ + Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, + operating_system=OperatingSystem.ARCH), + Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, + operating_system=OperatingSystem.UBUNTU), + Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, + operating_system=OperatingSystem.UBUNTU), + Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, + operating_system=OperatingSystem.MACOS), + Laptop(id=5, manufacturer="Apple", model="macBook Pro", screen_size_in_inches=16, + operating_system=OperatingSystem.MACOS), + Laptop(id=6, manufacturer="Lenovo", model="ThinkPad", screen_size_in_inches=14, + operating_system=OperatingSystem.UBUNTU), + Laptop(id=7, manufacturer="System76", model="Lemur Pro", screen_size_in_inches=15, + operating_system=OperatingSystem.ARCH), + Laptop(id=8, manufacturer="Framework", model="Framework 13", screen_size_in_inches=13, + operating_system=OperatingSystem.UBUNTU), +] + +people = [ + Person(name="Imran", age=22, preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.MACOS]), + Person(name="Eliza", age=34, preferred_operating_system=[OperatingSystem.ARCH, OperatingSystem.UBUNTU]), + Person(name="Marcus", age=28, preferred_operating_system=[OperatingSystem.MACOS, OperatingSystem.UBUNTU]), + Person(name="Sofia", age=31, preferred_operating_system=[OperatingSystem.UBUNTU]), + Person(name="James", age=25, preferred_operating_system=[OperatingSystem.ARCH, OperatingSystem.MACOS]), + Person(name="Nina", age=29, preferred_operating_system=[OperatingSystem.MACOS, OperatingSystem.ARCH, OperatingSystem.UBUNTU]), +] + + + +# ============================================================================ +# TESTING +# ============================================================================ +# Test the helper functions +for person in people: + print(f"\n{person.name}'s preferences: {[os.value for os in person.preferred_operating_system]}") + for laptop in laptops: + sadness= calculate_sadness(person, laptop) + print(f"Laptop {laptop.id} ({laptop.operating_system.value}): sadness = {sadness}") + \ No newline at end of file From a0b9fcdbe717de73fe535e8c409436ec651da110 Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Fri, 26 Dec 2025 15:31:10 +0000 Subject: [PATCH 4/7] Allocate laptops using greedy algorithm --- laptop_allocation/laptop_allocation.py | 60 +++++++++++++++++--------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py index 5836d409..4327091e 100644 --- a/laptop_allocation/laptop_allocation.py +++ b/laptop_allocation/laptop_allocation.py @@ -19,7 +19,7 @@ class Person: name: str age: int # Sorted in order of preference, most preferred is first. - preferred_operating_system: List[OperatingSystem] + preferred_operating_system: tuple @dataclass(frozen=True) @@ -31,7 +31,7 @@ class Laptop: operating_system: OperatingSystem # ============================================================================ -# HELPER FUNCTIONS +# HELPER FUNCTION # ============================================================================ """ Calculates how "sad" a person would be with a given laptop allocation. @@ -50,12 +50,6 @@ class Laptop: Returns: An integer representing sadness (0 = most happy, 100 = not in preferences) """ -def find_preferred_laptops(person:Person, laptops: List[Laptop]) -> list[Laptop]: - preferred_laptops = [] - for laptop in laptops: - if laptop.operating_system in person.preferred_operating_system: - preferred_laptops.append(laptop) - return preferred_laptops def calculate_sadness(person:Person, laptop:Laptop)-> int: if laptop.operating_system in person.preferred_operating_system: @@ -90,12 +84,12 @@ def calculate_sadness(person:Person, laptop:Laptop)-> int: ] people = [ - Person(name="Imran", age=22, preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.MACOS]), - Person(name="Eliza", age=34, preferred_operating_system=[OperatingSystem.ARCH, OperatingSystem.UBUNTU]), - Person(name="Marcus", age=28, preferred_operating_system=[OperatingSystem.MACOS, OperatingSystem.UBUNTU]), - Person(name="Sofia", age=31, preferred_operating_system=[OperatingSystem.UBUNTU]), - Person(name="James", age=25, preferred_operating_system=[OperatingSystem.ARCH, OperatingSystem.MACOS]), - Person(name="Nina", age=29, preferred_operating_system=[OperatingSystem.MACOS, OperatingSystem.ARCH, OperatingSystem.UBUNTU]), + Person(name="Imran", age=22, preferred_operating_system=(OperatingSystem.UBUNTU, OperatingSystem.MACOS)), + Person(name="Eliza", age=34, preferred_operating_system=(OperatingSystem.ARCH, OperatingSystem.UBUNTU)), + Person(name="Marcus", age=28, preferred_operating_system=(OperatingSystem.MACOS, OperatingSystem.UBUNTU)), + Person(name="Sofia", age=31, preferred_operating_system=(OperatingSystem.UBUNTU,)), + Person(name="James", age=25, preferred_operating_system=(OperatingSystem.ARCH, OperatingSystem.MACOS)), + Person(name="Nina", age=29, preferred_operating_system=(OperatingSystem.MACOS, OperatingSystem.ARCH, OperatingSystem.UBUNTU)), ] @@ -103,10 +97,34 @@ def calculate_sadness(person:Person, laptop:Laptop)-> int: # ============================================================================ # TESTING # ============================================================================ -# Test the helper functions -for person in people: - print(f"\n{person.name}'s preferences: {[os.value for os in person.preferred_operating_system]}") - for laptop in laptops: - sadness= calculate_sadness(person, laptop) - print(f"Laptop {laptop.id} ({laptop.operating_system.value}): sadness = {sadness}") - \ No newline at end of file + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person,Laptop]: + result={} + available_laptops = laptops.copy() + + for person in people: + smallest_sadness = float("inf") + best_laptop = None + + for laptop in available_laptops: + sadness = calculate_sadness(person, laptop) + if sadness < smallest_sadness: + smallest_sadness = sadness + best_laptop = laptop + + result[person]= best_laptop + available_laptops.remove(best_laptop) + + return result + +allocate_laptops(people, laptops) +allocation = allocate_laptops(people, laptops) + +print("\n" + "="*50) +print("FINAL ALLOCATION:") +print("="*50) +for person, laptop in allocation.items(): + print(f"{person.name}: {laptop.manufacturer} {laptop.model} ({laptop.operating_system.value})") + + + From 76f824d1463b5c742860a7072c44bbeefcc73fca Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Fri, 26 Dec 2025 15:46:35 +0000 Subject: [PATCH 5/7] Validate laptop availability before allocation --- laptop_allocation/laptop_allocation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py index 4327091e..06e59b75 100644 --- a/laptop_allocation/laptop_allocation.py +++ b/laptop_allocation/laptop_allocation.py @@ -99,6 +99,9 @@ def calculate_sadness(person:Person, laptop:Laptop)-> int: # ============================================================================ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person,Laptop]: + if len(laptops) < len(people): + raise ValueError("Not enough laptops to allocate one per person") + result={} available_laptops = laptops.copy() From 3cedf09bd3d36e3cd137e0d08b70bec9c3754623 Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:18:34 +0000 Subject: [PATCH 6/7] Optimise: Prioritise users with fewer OS preferences to avoid high sadness scores and improve overall allocation quality --- laptop_allocation/laptop_allocation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py index 06e59b75..f83d17ea 100644 --- a/laptop_allocation/laptop_allocation.py +++ b/laptop_allocation/laptop_allocation.py @@ -99,13 +99,17 @@ def calculate_sadness(person:Person, laptop:Laptop)-> int: # ============================================================================ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person,Laptop]: + if len(laptops) < len(people): raise ValueError("Not enough laptops to allocate one per person") + + + people_sorted = sorted(people, key = lambda p: len(p.preferred_operating_system)) result={} available_laptops = laptops.copy() - for person in people: + for person in people_sorted: smallest_sadness = float("inf") best_laptop = None From 633a08e0fda2086099e0d5098d769cc0cb9000de Mon Sep 17 00:00:00 2001 From: zohrehKazemianpour <129424353+zohrehKazemianpour@users.noreply.github.com> Date: Fri, 16 Jan 2026 12:03:08 +0000 Subject: [PATCH 7/7] refactor: remove redundant call and optimise allocation loop --- laptop_allocation/laptop_allocation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/laptop_allocation/laptop_allocation.py b/laptop_allocation/laptop_allocation.py index f83d17ea..fcd4fb94 100644 --- a/laptop_allocation/laptop_allocation.py +++ b/laptop_allocation/laptop_allocation.py @@ -119,12 +119,16 @@ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person smallest_sadness = sadness best_laptop = laptop + + if smallest_sadness == 0: + break + result[person]= best_laptop available_laptops.remove(best_laptop) return result -allocate_laptops(people, laptops) + allocation = allocate_laptops(people, laptops) print("\n" + "="*50)