diff --git a/TP_2_3/exo_1_2.py b/TP_2_3/exo_1_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..899cea1dd47051d4e49f5bed69f055e96fd44076
--- /dev/null
+++ b/TP_2_3/exo_1_2.py
@@ -0,0 +1,193 @@
+import random
+import itertools
+
+class Robot:
+    def __init__(self, id, capacity):
+        self.id = id
+        self.capacity = capacity
+    
+    def __repr__(self):
+        return f"Robot({self.id})"
+        
+
+class Zone:
+    def __init__(self, id, dirt):
+        self.id = id
+        self.dirt = dirt
+    
+    def __repr__(self):
+        return f"Zone({self.id})"
+
+class TaskAllocation:
+    def __init__(self, robotliste, zoneliste):
+        self.robotliste = robotliste
+        self.zoneliste = zoneliste
+        # Création d'un dictionnaire d'utilités aléatoires pour chaque paire (robot, zone)
+        self.dictio = {(robot, zone): random.randint(1, 10) for robot, zone in itertools.product(robotliste, zoneliste)}
+
+    def allocation(self, cuf):
+        # On garde votre structure mais on corrige le problème d'assignation
+        best_allocation = None
+        best_utility = float('-inf')  # On commence avec une utilité très basse
+        
+        # On utilise une approche simplifiée pour générer des allocations
+        # On distribue les zones de manière cyclique avec différents points de départ
+        for start in range(len(self.robotliste)):
+            current_allocation = {robot: [] for robot in self.robotliste}
+            for i, zone in enumerate(self.zoneliste):
+                robot_index = (start + i) % len(self.robotliste)
+                current_allocation[self.robotliste[robot_index]].append(zone)
+            
+            utility = cuf.utility(current_allocation)
+            if best_allocation is None or utility > best_utility:
+                best_utility = utility
+                best_allocation = current_allocation
+        
+        return best_allocation
+
+    def dummy_allocation(self, robotliste, zoneliste):
+        # On garde votre fonction exactement comme elle était
+        i = 0
+        dico = {robot: [] for robot in robotliste}
+        for zone in zoneliste:
+            robot = robotliste[i % len(robotliste)]
+            dico[robot].append(zone)
+            i += 1
+        return dico
+
+    def calculate_cleaning_time(self, allocation):
+        # Nouvelle fonction pour calculer le temps de nettoyage
+        robot_times = []
+        
+        for robot, zones in allocation.items():
+            total_dirt = sum(zone.dirt for zone in zones)
+            cleaning_time = total_dirt / robot.capacity
+            robot_times.append(cleaning_time)
+        
+        # Le temps total est le maximum des temps individuels
+        return max(robot_times) if robot_times else 0
+
+    def getdictio(self):
+        return self.dictio
+
+   
+class CollectiveUtilityFunction:
+    def __init__(self, dico, utility):
+        # On garde votre nom de paramètre "utility" au lieu de "utility_type"
+        self.utility = getattr(self, utility)
+        self.dico = dico
+
+    def utilitariste(self, allocation):
+        total_uti = 0
+        for robot, zones in allocation.items():
+            for zone in zones:
+                total_uti += self.dico[(robot, zone)]
+        return total_uti
+
+    def egalitariste(self, allocation):
+        uti_par_robot = {}
+        for robot, zones in allocation.items():
+            robot_utility = 0
+            for zone in zones:
+                robot_utility += self.dico[(robot, zone)]
+            uti_par_robot[robot] = robot_utility
+        
+        # Si aucun robot n'a d'utilité, retourner 0
+        if not uti_par_robot:
+            return 0
+            
+        return min(uti_par_robot.values())
+
+    def elitiste(self, allocation):
+        uti_par_robot = {}
+        for robot, zones in allocation.items():
+            robot_utility = 0
+            for zone in zones:
+                robot_utility += self.dico[(robot, zone)]
+            uti_par_robot[robot] = robot_utility
+            
+        # Si aucun robot n'a d'utilité, retourner 0
+        if not uti_par_robot:
+            return 0
+            
+        return max(uti_par_robot.values())
+
+    def nash(self, allocation):
+        produit_uti = 1
+        for robot, zones in allocation.items():
+            robot_uti = 0
+            for zone in zones:
+                robot_uti += self.dico[(robot, zone)]
+            
+            # Pour éviter de multiplier par 0
+            if robot_uti > 0:
+                produit_uti *= robot_uti
+        
+        return produit_uti
+
+
+# Test avec 3 robots et 6 zones
+if __name__ == "__main__":
+    # Création des robots
+    robot1 = Robot("robot1", 10)
+    robot2 = Robot("robot2", 6)
+    robot3 = Robot("robot3", 4)
+    
+    # Création des zones
+    zone1 = Zone("zone1", 4)
+    zone2 = Zone("zone2", 6)
+    zone3 = Zone("zone3", 1)
+    zone4 = Zone("zone4", 5)
+    zone5 = Zone("zone5", 3)
+    zone6 = Zone("zone6", 2)
+    
+    robotliste = [robot1, robot2, robot3]
+    zoneliste = [zone1, zone2, zone3, zone4, zone5, zone6]
+    
+    # Création de l'allocation de tâches
+    task_allocation = TaskAllocation(robotliste, zoneliste)
+    
+    # Affichage du dictionnaire d'utilités
+    print("Dictionnaire d'utilités:")
+    for (robot, zone), utility in task_allocation.getdictio().items():
+        print(f"{robot} - {zone}: {utility}")
+    
+    print("\n--- Allocation naïve (dummy) ---")
+    dummy_alloc = task_allocation.dummy_allocation(robotliste, zoneliste)
+    for robot, zones in dummy_alloc.items():
+        print(f"{robot}: {zones}")
+    
+    print(f"Temps de nettoyage avec allocation naïve: {task_allocation.calculate_cleaning_time(dummy_alloc):.2f} heures")
+    
+    # Test des différentes fonctions d'utilité collective
+    print("\n--- Allocation avec fonction d'utilité utilitariste ---")
+    cuf_utilitariste = CollectiveUtilityFunction(task_allocation.getdictio(), "utilitariste")
+    alloc_utilitariste = task_allocation.allocation(cuf_utilitariste)
+    for robot, zones in alloc_utilitariste.items():
+        print(f"{robot}: {zones}")
+    print(f"Utilité utilitariste: {cuf_utilitariste.utility(alloc_utilitariste)}")
+    print(f"Temps de nettoyage: {task_allocation.calculate_cleaning_time(alloc_utilitariste):.2f} heures")
+    
+    print("\n--- Allocation avec fonction d'utilité égalitariste ---")
+    cuf_egalitariste = CollectiveUtilityFunction(task_allocation.getdictio(), "egalitariste")
+    alloc_egalitariste = task_allocation.allocation(cuf_egalitariste)
+    for robot, zones in alloc_egalitariste.items():
+        print(f"{robot}: {zones}")
+    print(f"Utilité égalitariste: {cuf_egalitariste.utility(alloc_egalitariste)}")
+    print(f"Temps de nettoyage: {task_allocation.calculate_cleaning_time(alloc_egalitariste):.2f} heures")
+    
+    print("\n--- Allocation avec fonction d'utilité élitiste ---")
+    cuf_elitiste = CollectiveUtilityFunction(task_allocation.getdictio(), "elitiste")
+    alloc_elitiste = task_allocation.allocation(cuf_elitiste)
+    for robot, zones in alloc_elitiste.items():
+        print(f"{robot}: {zones}")
+    print(f"Utilité élitiste: {cuf_elitiste.utility(alloc_elitiste)}")
+    print(f"Temps de nettoyage: {task_allocation.calculate_cleaning_time(alloc_elitiste):.2f} heures")
+    
+    print("\n--- Allocation avec fonction d'utilité de Nash ---")
+    cuf_nash = CollectiveUtilityFunction(task_allocation.getdictio(), "nash")
+    alloc_nash = task_allocation.allocation(cuf_nash)
+    for robot, zones in alloc_nash.items():
+        print(f"{robot}: {zones}")
+    print(f"Utilité de Nash: {cuf_nash.utility(alloc_nash)}")
+    print(f"Temps de nettoyage: {task_allocation.calculate_cleaning_time(alloc_nash):.2f} heures")
\ No newline at end of file