From 2fa19599467263dcf582bb12906e03328e03b4a4 Mon Sep 17 00:00:00 2001
From: zhang <zc857179121@qq.com>
Date: 星期三, 02 七月 2025 13:12:26 +0800
Subject: [PATCH] 初版提交

---
 algorithm_system/algorithms/task_allocation.py |  687 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 687 insertions(+), 0 deletions(-)

diff --git a/algorithm_system/algorithms/task_allocation.py b/algorithm_system/algorithms/task_allocation.py
new file mode 100644
index 0000000..883ed50
--- /dev/null
+++ b/algorithm_system/algorithms/task_allocation.py
@@ -0,0 +1,687 @@
+"""
+浠诲姟鍒嗛厤绠楁硶
+"""
+import time
+import random
+import logging
+from typing import Dict, List, Tuple, Optional, Set, Any
+from collections import defaultdict
+from abc import ABC, abstractmethod
+
+from common.data_models import TaskData, AGVStatus, TaskAssignment, BackpackData
+from algorithm_system.models.agv_model import AGVModel, AGVModelManager
+from common.utils import get_coordinate_from_path_id, calculate_distance, calculate_manhattan_distance
+from dataclasses import dataclass
+
+
+class TaskAllocation(ABC):
+    """浠诲姟鍒嗛厤绠楁硶鍩虹被"""
+    
+    def __init__(self, agv_manager: AGVModelManager):
+        """
+        鍒濆鍖栦换鍔″垎閰嶇畻娉�
+        
+        Args:
+            agv_manager: AGV妯″瀷绠$悊鍣�
+        """
+        self.agv_manager = agv_manager
+        self.logger = logging.getLogger(__name__)
+    
+    @abstractmethod
+    def allocate_tasks(self, tasks: List[TaskData]) -> List[TaskAssignment]:
+        """
+        鍒嗛厤浠诲姟缁橝GV
+        
+        Args:
+            tasks: 寰呭垎閰嶇殑浠诲姟鍒楄〃
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉鍒楄〃
+        """
+        pass
+    
+    def find_available_backpack_slot(self, agv_status: AGVStatus) -> Optional[int]:
+        """
+        鏌ユ壘AGV鐨勫彲鐢ㄨ儗绡撲綅缃�
+        
+        Args:
+            agv_status: AGV鐘舵�佷俊鎭�
+            
+        Returns:
+            Optional[int]: 鍙敤鐨勮儗绡撲綅缃紪鍙凤紝濡傛灉娌℃湁鍙敤浣嶇疆鍒欒繑鍥濶one
+        """
+        if not agv_status.backpack:
+            # 濡傛灉娌℃湁鑳岀瘬淇℃伅锛屽亣璁句粠绗竴涓綅缃紑濮�
+            self.logger.warning(f"AGV {agv_status.agvId} 娌℃湁鑳岀瘬淇℃伅锛屽垎閰嶅埌浣嶇疆0")
+            return 0
+        
+        # 鏌ユ壘绌洪棽涓旀湭鎵ц浠诲姟鐨勮儗绡撲綅缃�
+        for backpack_item in agv_status.backpack:
+            if not backpack_item.loaded and not backpack_item.execute and not backpack_item.taskId:
+                self.logger.debug(f"AGV {agv_status.agvId} 鎵惧埌鍙敤鑳岀瘬浣嶇疆: {backpack_item.index}")
+                return backpack_item.index
+        
+        # 濡傛灉鎵�鏈変綅缃兘琚崰鐢紝杩斿洖None
+        self.logger.debug(f"AGV {agv_status.agvId} 娌℃湁鍙敤鐨勮儗绡撲綅缃�")
+        return None
+    
+    def get_agv_available_capacity(self, agv_status: AGVStatus) -> int:
+        """
+        鑾峰彇AGV鐨勫彲鐢ㄨ儗绡撳閲�
+        
+        Args:
+            agv_status: AGV鐘舵�佷俊鎭�
+            
+        Returns:
+            int: 鍙敤鑳岀瘬鏁伴噺
+        """
+        if not agv_status.backpack:
+            return 1  # 鍋囪鑷冲皯鏈変竴涓儗绡撲綅缃�
+        
+        available_count = 0
+        for backpack_item in agv_status.backpack:
+            if not backpack_item.loaded and not backpack_item.execute and not backpack_item.taskId:
+                available_count += 1
+        
+        return available_count
+    
+    def assign_task_with_backpack(self, agv_model, task: TaskData, lev_id: int) -> bool:
+        """
+        灏嗕换鍔″垎閰嶇粰AGV鐨勬寚瀹氳儗绡撲綅缃�
+        
+        Args:
+            agv_model: AGV妯″瀷
+            task: 浠诲姟鏁版嵁
+            lev_id: 鑳岀瘬浣嶇疆缂栧彿
+            
+        Returns:
+            bool: 鍒嗛厤鏄惁鎴愬姛
+        """
+        try:
+            # 浣跨敤AGV妯″瀷鐨刟ssign_task鏂规硶
+            success = agv_model.assign_task(
+                task_id=task.taskId,
+                priority=task.priority,
+                start_code=task.start,
+                end_code=task.end
+            )
+            
+            if success:
+                self.logger.info(f"浠诲姟 {task.taskId} 鎴愬姛鍒嗛厤缁橝GV {agv_model.agvId} 鐨勮儗绡撲綅缃� {lev_id}")
+                return True
+            else:
+                self.logger.warning(f"浠诲姟 {task.taskId} 鍒嗛厤缁橝GV {agv_model.agvId} 澶辫触")
+                return False
+                
+        except Exception as e:
+            self.logger.error(f"鍒嗛厤浠诲姟鏃跺彂鐢熷紓甯�: {e}")
+            return False
+
+
+class NearestFirstAllocation(TaskAllocation):
+    """鏈�杩戜紭鍏堝垎閰嶇畻娉�"""
+    
+    def allocate_tasks(self, tasks: List[TaskData]) -> List[TaskAssignment]:
+        """
+        浣跨敤鏈�杩戜紭鍏堢瓥鐣ュ垎閰嶄换鍔�
+        
+        Args:
+            tasks: 寰呭垎閰嶇殑浠诲姟鍒楄〃
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉鍒楄〃
+        """
+        if not tasks:
+            return []
+        
+        # 鑾峰彇鍙敤鐨凙GV
+        available_agvs = self.agv_manager.get_available_agvs()
+        
+        if not available_agvs:
+            self.logger.warning("娌℃湁鍙敤鐨凙GV杩涜浠诲姟鍒嗛厤")
+            return []
+        
+        # 1. 棣栧厛妫�鏌ヤ换鍔℃槸鍚﹀凡缁忓垎閰嶏紝閬垮厤閲嶅鍒嗛厤
+        already_assigned_tasks = set()
+        all_agvs = self.agv_manager.get_all_agvs()
+        for agv in all_agvs:
+            if agv.backpack:
+                for backpack_item in agv.backpack:
+                    if backpack_item.taskId:
+                        already_assigned_tasks.add(backpack_item.taskId)
+                        self.logger.info(f"浠诲姟 {backpack_item.taskId} 宸插垎閰嶇粰 AGV {agv.agvId}锛岃烦杩囬噸澶嶅垎閰�")
+        
+        # 2. 杩囨护鎺夊凡鍒嗛厤鐨勪换鍔�
+        unassigned_tasks = [task for task in tasks if task.taskId not in already_assigned_tasks]
+        
+        if not unassigned_tasks:
+            self.logger.info("鎵�鏈変换鍔¢兘宸插垎閰嶏紝鏃犻渶閲嶆柊鍒嗛厤")
+            return []
+        
+        self.logger.info(f"鎬讳换鍔℃暟: {len(tasks)}, 宸插垎閰�: {len(already_assigned_tasks)}, 寰呭垎閰�: {len(unassigned_tasks)}")
+        
+        assignments = []
+        path_mapping = self.agv_manager.path_mapping
+        
+        # 瀵规瘡涓换鍔℃壘鍒版渶杩戠殑AGV
+        for task in unassigned_tasks:
+            if not available_agvs:
+                break
+                
+            # 鑾峰彇浠诲姟璧风偣鍧愭爣
+            task_start_coord = get_coordinate_from_path_id(task.start, path_mapping)
+            if not task_start_coord:
+                self.logger.warning(f"鏃犳硶鑾峰彇浠诲姟 {task.taskId} 璧风偣 {task.start} 鐨勫潗鏍�")
+                continue
+            
+            # 鎵惧埌璺濈鏈�杩戠殑AGV
+            nearest_agv = None
+            min_distance = float('inf')
+            
+            for agv in available_agvs:
+                if agv.coordinates:
+                    distance = calculate_manhattan_distance(agv.coordinates, task_start_coord)
+                    
+                    # 濡傛灉AGV宸叉湁浠诲姟锛岃绠楀畬鎴愬綋鍓嶄换鍔″悗鍒版柊浠诲姟璧风偣鐨勮窛绂�
+                    if agv.current_task_count > 0:
+                        # 绠�鍖栵細鍋囪AGV闇�瑕侀澶栨椂闂村畬鎴愬綋鍓嶄换鍔�
+                        distance += agv.current_task_count * 10
+                    
+                    if distance < min_distance:
+                        min_distance = distance
+                        nearest_agv = agv
+            
+            if nearest_agv and nearest_agv.can_accept_task(task.priority):
+                # 鑾峰彇AGV鐨勫師濮嬬姸鎬佹暟鎹潵鏌ユ壘鍙敤鑳岀瘬浣嶇疆
+                agv_status = None
+                for agv_state in self.agv_manager.get_all_agv_status():
+                    if agv_state.agvId == nearest_agv.agvId:
+                        agv_status = agv_state
+                        break
+                
+                if agv_status:
+                    # 鏌ユ壘鍙敤鐨勮儗绡撲綅缃�
+                    available_lev_id = self.find_available_backpack_slot(agv_status)
+                    
+                    if available_lev_id is not None:
+                        # 鍒嗛厤浠诲姟鍒版寚瀹氳儗绡撲綅缃�
+                        success = self.assign_task_with_backpack(nearest_agv, task, available_lev_id)
+                        if success:
+                            assignments.append(TaskAssignment(
+                                taskId=task.taskId,
+                                agvId=nearest_agv.agvId,
+                                lev_id=available_lev_id
+                            ))
+                            
+                            self.logger.info(f"浠诲姟 {task.taskId} 鍒嗛厤缁欐渶杩戠殑AGV {nearest_agv.agvId}锛岃儗绡撲綅缃�: {available_lev_id}锛岃窛绂�: {min_distance}")
+                            
+                            # 妫�鏌GV鏄惁杩樻湁鍙敤鑳岀瘬浣嶇疆
+                            remaining_capacity = self.get_agv_available_capacity(agv_status) - 1
+                            if remaining_capacity <= 0:
+                                available_agvs.remove(nearest_agv)
+                        else:
+                            self.logger.warning(f"浠诲姟 {task.taskId} 鍒嗛厤缁橝GV {nearest_agv.agvId} 澶辫触")
+                    else:
+                        self.logger.warning(f"AGV {nearest_agv.agvId} 娌℃湁鍙敤鐨勮儗绡撲綅缃�")
+                        available_agvs.remove(nearest_agv)
+                else:
+                    self.logger.warning(f"鏃犳硶鑾峰彇AGV {nearest_agv.agvId} 鐨勭姸鎬佷俊鎭�")
+        
+        return assignments
+
+
+class LoadBalancedAllocation(TaskAllocation):
+    """璐熻浇鍧囪 鍒嗛厤绠楁硶"""
+    
+    def allocate_tasks(self, tasks: List[TaskData]) -> List[TaskAssignment]:
+        """
+        浣跨敤璐熻浇鍧囪 绛栫暐鍒嗛厤浠诲姟
+        
+        Args:
+            tasks: 寰呭垎閰嶇殑浠诲姟鍒楄〃
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉鍒楄〃
+        """
+        if not tasks:
+            return []
+        
+        # 鑾峰彇鎵�鏈堿GV
+        all_agvs = self.agv_manager.get_all_agvs()
+        
+        if not all_agvs:
+            self.logger.warning("娌℃湁AGV杩涜浠诲姟鍒嗛厤")
+            return []
+        
+        # 1. 棣栧厛妫�鏌ヤ换鍔℃槸鍚﹀凡缁忓垎閰嶏紝閬垮厤閲嶅鍒嗛厤
+        already_assigned_tasks = set()
+        for agv in all_agvs:
+            if agv.backpack:
+                for backpack_item in agv.backpack:
+                    if backpack_item.taskId:
+                        already_assigned_tasks.add(backpack_item.taskId)
+                        self.logger.info(f"浠诲姟 {backpack_item.taskId} 宸插垎閰嶇粰 AGV {agv.agvId}锛岃烦杩囬噸澶嶅垎閰�")
+        
+        # 2. 杩囨护鎺夊凡鍒嗛厤鐨勪换鍔�
+        unassigned_tasks = [task for task in tasks if task.taskId not in already_assigned_tasks]
+        
+        if not unassigned_tasks:
+            self.logger.info("鎵�鏈変换鍔¢兘宸插垎閰嶏紝鏃犻渶閲嶆柊鍒嗛厤")
+            return []
+        
+        self.logger.info(f"鎬讳换鍔℃暟: {len(tasks)}, 宸插垎閰�: {len(already_assigned_tasks)}, 寰呭垎閰�: {len(unassigned_tasks)}")
+        
+        assignments = []
+        path_mapping = self.agv_manager.path_mapping
+        
+        # 鎸変紭鍏堢骇鎺掑簭浠诲姟
+        sorted_tasks = sorted(unassigned_tasks, key=lambda t: t.priority, reverse=True)
+        
+        # 瀵规瘡涓换鍔″垎閰嶇粰璐熻浇鏈�浣庣殑AGV
+        for task in sorted_tasks:
+            # 鑾峰彇浠诲姟璧风偣鍧愭爣
+            task_start_coord = get_coordinate_from_path_id(task.start, path_mapping)
+            if not task_start_coord:
+                self.logger.warning(f"鏃犳硶鑾峰彇浠诲姟 {task.taskId} 璧风偣 {task.start} 鐨勫潗鏍�")
+                continue
+            
+            # 鎸夎礋杞藉拰璺濈鎺掑簭AGV
+            agv_scores = []
+            for agv in all_agvs:
+                if not agv.can_accept_task(task.priority):
+                    continue
+                    
+                # 璁$畻璐熻浇寰楀垎锛堣礋杞借秺浣庡緱鍒嗚秺楂橈級
+                load_score = 1.0 - agv.get_workload_ratio()
+                
+                # 璁$畻璺濈寰楀垎锛堣窛绂昏秺杩戝緱鍒嗚秺楂橈級
+                distance_score = 0.0
+                if agv.coordinates and task_start_coord:
+                    distance = calculate_manhattan_distance(agv.coordinates, task_start_coord)
+                    distance_score = 1.0 / (1.0 + distance / 100.0)  # 褰掍竴鍖栬窛绂诲緱鍒�
+                
+                # 璁$畻鏁堢巼寰楀垎
+                efficiency_score = agv.calculate_efficiency_score(path_mapping)
+                
+                # 缁煎悎寰楀垎
+                total_score = 0.4 * load_score + 0.3 * distance_score + 0.3 * efficiency_score
+                agv_scores.append((agv, total_score))
+            
+            if not agv_scores:
+                # 璇︾粏鍒嗘瀽涓轰粈涔堟病鏈堿GV鍙互鎺ュ彈浠诲姟
+                total_agvs = len(all_agvs)
+                busy_count = 0
+                low_battery_count = 0
+                overloaded_count = 0
+                status_invalid_count = 0
+                
+                for agv in all_agvs:
+                    if agv.is_overloaded():
+                        overloaded_count += 1
+                    elif str(agv.status) not in ["0", "1", "2"]:
+                        status_invalid_count += 1
+                    elif agv.need_charging():
+                        low_battery_count += 1
+                    else:
+                        busy_count += 1
+                
+                self.logger.warning(f"娌℃湁AGV鍙互鎺ュ彈浠诲姟 {task.taskId} - 璇︾粏鍒嗘瀽:")
+                self.logger.warning(f"  鎬籄GV鏁�: {total_agvs}")
+                self.logger.warning(f"  浠诲姟婊¤浇: {overloaded_count}")
+                self.logger.warning(f"  鐘舵�佸紓甯�: {status_invalid_count}") 
+                self.logger.warning(f"  鐢甸噺杩囦綆: {low_battery_count}")
+                self.logger.warning(f"  鍏朵粬鍘熷洜: {busy_count}")
+                self.logger.warning(f"  浠诲姟浼樺厛绾�: {task.priority}")
+                continue
+            
+            # 閫夋嫨寰楀垎鏈�楂樼殑AGV
+            agv_scores.sort(key=lambda x: x[1], reverse=True)
+            best_agv = agv_scores[0][0]
+            
+            # 鑾峰彇AGV鐨勫師濮嬬姸鎬佹暟鎹潵鏌ユ壘鍙敤鑳岀瘬浣嶇疆
+            agv_status = self.agv_manager.get_agv_status(best_agv.agvId)
+            
+            if agv_status:
+                # 鏌ユ壘鍙敤鐨勮儗绡撲綅缃�
+                available_lev_id = self.find_available_backpack_slot(agv_status)
+                
+                if available_lev_id is not None:
+                    # 鍒嗛厤浠诲姟鍒版寚瀹氳儗绡撲綅缃�
+                    success = self.assign_task_with_backpack(best_agv, task, available_lev_id)
+                    if success:
+                        assignments.append(TaskAssignment(
+                            taskId=task.taskId,
+                            agvId=best_agv.agvId,
+                            lev_id=available_lev_id
+                        ))
+                        
+                        self.logger.info(f"浠诲姟 {task.taskId} 鍒嗛厤缁欒礋杞藉潎琛$殑AGV {best_agv.agvId}锛岃儗绡撲綅缃�: {available_lev_id}锛屽緱鍒�: {agv_scores[0][1]:.3f}")
+                    else:
+                        self.logger.warning(f"浠诲姟 {task.taskId} 鍒嗛厤缁橝GV {best_agv.agvId} 澶辫触")
+                else:
+                    self.logger.warning(f"AGV {best_agv.agvId} 娌℃湁鍙敤鐨勮儗绡撲綅缃�")
+            else:
+                self.logger.warning(f"鏃犳硶鑾峰彇AGV {best_agv.agvId} 鐨勭姸鎬佷俊鎭�")
+        
+        return assignments
+
+
+class PriorityFirstAllocation(TaskAllocation):
+    """浼樺厛绾т紭鍏堝垎閰嶇畻娉�"""
+    
+    def allocate_tasks(self, tasks: List[TaskData]) -> List[TaskAssignment]:
+        """
+        浣跨敤浼樺厛绾т紭鍏堢瓥鐣ュ垎閰嶄换鍔�
+        
+        Args:
+            tasks: 寰呭垎閰嶇殑浠诲姟鍒楄〃
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉鍒楄〃
+        """
+        if not tasks:
+            return []
+        
+        # 鑾峰彇鍙敤鐨凙GV
+        available_agvs = self.agv_manager.get_available_agvs()
+        
+        if not available_agvs:
+            self.logger.warning("娌℃湁鍙敤鐨凙GV杩涜浠诲姟鍒嗛厤")
+            return []
+        
+        # 1. 棣栧厛妫�鏌ヤ换鍔℃槸鍚﹀凡缁忓垎閰嶏紝閬垮厤閲嶅鍒嗛厤
+        already_assigned_tasks = set()
+        all_agvs = self.agv_manager.get_all_agvs()
+        for agv in all_agvs:
+            if agv.backpack:
+                for backpack_item in agv.backpack:
+                    if backpack_item.taskId:
+                        already_assigned_tasks.add(backpack_item.taskId)
+                        self.logger.info(f"浠诲姟 {backpack_item.taskId} 宸插垎閰嶇粰 AGV {agv.agvId}锛岃烦杩囬噸澶嶅垎閰�")
+        
+        # 2. 杩囨护鎺夊凡鍒嗛厤鐨勪换鍔�
+        unassigned_tasks = [task for task in tasks if task.taskId not in already_assigned_tasks]
+        
+        if not unassigned_tasks:
+            self.logger.info("鎵�鏈変换鍔¢兘宸插垎閰嶏紝鏃犻渶閲嶆柊鍒嗛厤")
+            return []
+        
+        self.logger.info(f"鎬讳换鍔℃暟: {len(tasks)}, 宸插垎閰�: {len(already_assigned_tasks)}, 寰呭垎閰�: {len(unassigned_tasks)}")
+        
+        # 鎸変紭鍏堢骇鎺掑簭浠诲姟锛堥珮浼樺厛绾у湪鍓嶏級
+        sorted_tasks = sorted(unassigned_tasks, key=lambda t: t.priority, reverse=True)
+        
+        assignments = []
+        path_mapping = self.agv_manager.path_mapping
+        
+        # 浼樺厛鍒嗛厤楂樹紭鍏堢骇浠诲姟
+        for task in sorted_tasks:
+            if not available_agvs:
+                break
+                
+            # 鑾峰彇浠诲姟璧风偣鍧愭爣
+            task_start_coord = get_coordinate_from_path_id(task.start, path_mapping)
+            if not task_start_coord:
+                self.logger.warning(f"鏃犳硶鑾峰彇浠诲姟 {task.taskId} 璧风偣 {task.start} 鐨勫潗鏍�")
+                continue
+            
+            # 涓洪珮浼樺厛绾т换鍔¢�夋嫨鏈�浣矨GV
+            best_agv = None
+            best_score = -1
+            
+            for agv in available_agvs:
+                if not agv.can_accept_task(task.priority):
+                    continue
+                
+                # 璁$畻缁煎悎寰楀垎
+                distance_score = 0.0
+                if agv.coordinates and task_start_coord:
+                    distance = calculate_manhattan_distance(agv.coordinates, task_start_coord)
+                    distance_score = 1.0 / (1.0 + distance / 50.0)
+                
+                efficiency_score = agv.calculate_efficiency_score(path_mapping)
+                capacity_score = agv.get_task_capacity() / agv.max_capacity
+                
+                # 楂樹紭鍏堢骇浠诲姟鏇存敞閲嶆晥鐜囧拰璺濈
+                total_score = 0.5 * distance_score + 0.3 * efficiency_score + 0.2 * capacity_score
+                
+                if total_score > best_score:
+                    best_score = total_score
+                    best_agv = agv
+            
+            if best_agv:
+                # 鑾峰彇AGV鐨勫師濮嬬姸鎬佹暟鎹潵鏌ユ壘鍙敤鑳岀瘬浣嶇疆
+                agv_status = self.agv_manager.get_agv_status(best_agv.agvId)
+                
+                if agv_status:
+                    # 鏌ユ壘鍙敤鐨勮儗绡撲綅缃�
+                    available_lev_id = self.find_available_backpack_slot(agv_status)
+                    
+                    if available_lev_id is not None:
+                        # 鍒嗛厤浠诲姟鍒版寚瀹氳儗绡撲綅缃�
+                        success = self.assign_task_with_backpack(best_agv, task, available_lev_id)
+                        if success:
+                            assignments.append(TaskAssignment(
+                                taskId=task.taskId,
+                                agvId=best_agv.agvId,
+                                lev_id=available_lev_id
+                            ))
+                            
+                            self.logger.info(f"楂樹紭鍏堢骇浠诲姟 {task.taskId} (浼樺厛绾�: {task.priority}) 鍒嗛厤缁橝GV {best_agv.agvId}锛岃儗绡撲綅缃�: {available_lev_id}")
+                            
+                            # 妫�鏌GV鏄惁杩樻湁鍙敤鑳岀瘬浣嶇疆
+                            remaining_capacity = self.get_agv_available_capacity(agv_status) - 1
+                            if remaining_capacity <= 0:
+                                available_agvs.remove(best_agv)
+                        else:
+                            self.logger.warning(f"浠诲姟 {task.taskId} 鍒嗛厤缁橝GV {best_agv.agvId} 澶辫触")
+                    else:
+                        self.logger.warning(f"AGV {best_agv.agvId} 娌℃湁鍙敤鐨勮儗绡撲綅缃�")
+                        available_agvs.remove(best_agv)
+                else:
+                    self.logger.warning(f"鏃犳硶鑾峰彇AGV {best_agv.agvId} 鐨勭姸鎬佷俊鎭�")
+        
+        return assignments
+
+
+class MultiObjectiveAllocation(TaskAllocation):
+    """澶氱洰鏍囦紭鍖栧垎閰嶇畻娉�"""
+    
+    def __init__(self, agv_manager: AGVModelManager, 
+                 distance_weight: float = 0.4, 
+                 load_weight: float = 0.3, 
+                 efficiency_weight: float = 0.3):
+        """
+        鍒濆鍖栧鐩爣浼樺寲鍒嗛厤绠楁硶
+        
+        Args:
+            agv_manager: AGV妯″瀷绠$悊鍣�
+            distance_weight: 璺濈鏉冮噸
+            load_weight: 璐熻浇鏉冮噸
+            efficiency_weight: 鏁堢巼鏉冮噸
+        """
+        super().__init__(agv_manager)
+        self.distance_weight = distance_weight
+        self.load_weight = load_weight
+        self.efficiency_weight = efficiency_weight
+    
+    def allocate_tasks(self, tasks: List[TaskData]) -> List[TaskAssignment]:
+        """
+        浣跨敤澶氱洰鏍囦紭鍖栫瓥鐣ュ垎閰嶄换鍔�
+        
+        Args:
+            tasks: 寰呭垎閰嶇殑浠诲姟鍒楄〃
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉鍒楄〃
+        """
+        if not tasks:
+            return []
+        
+        # 鑾峰彇鎵�鏈堿GV
+        all_agvs = self.agv_manager.get_all_agvs()
+        
+        if not all_agvs:
+            self.logger.warning("娌℃湁AGV杩涜浠诲姟鍒嗛厤")
+            return []
+        
+        # 1. 棣栧厛妫�鏌ヤ换鍔℃槸鍚﹀凡缁忓垎閰嶏紝閬垮厤閲嶅鍒嗛厤
+        already_assigned_tasks = set()
+        for agv in all_agvs:
+            if agv.backpack:
+                for backpack_item in agv.backpack:
+                    if backpack_item.taskId:
+                        already_assigned_tasks.add(backpack_item.taskId)
+                        self.logger.info(f"浠诲姟 {backpack_item.taskId} 宸插垎閰嶇粰 AGV {agv.agvId}锛岃烦杩囬噸澶嶅垎閰�")
+        
+        # 2. 杩囨护鎺夊凡鍒嗛厤鐨勪换鍔�
+        unassigned_tasks = [task for task in tasks if task.taskId not in already_assigned_tasks]
+        
+        if not unassigned_tasks:
+            self.logger.info("鎵�鏈変换鍔¢兘宸插垎閰嶏紝鏃犻渶閲嶆柊鍒嗛厤")
+            return []
+        
+        self.logger.info(f"鎬讳换鍔℃暟: {len(tasks)}, 宸插垎閰�: {len(already_assigned_tasks)}, 寰呭垎閰�: {len(unassigned_tasks)}")
+        
+        assignments = []
+        path_mapping = self.agv_manager.path_mapping
+        
+        # 瀵规瘡涓换鍔�-AGV瀵硅绠楀緱鍒�
+        task_agv_scores = {}
+        
+        for task in unassigned_tasks:
+            task_start_coord = get_coordinate_from_path_id(task.start, path_mapping)
+            if not task_start_coord:
+                continue
+                
+            for agv in all_agvs:
+                if not agv.can_accept_task(task.priority):
+                    continue
+                
+                # 璺濈寰楀垎
+                distance_score = 0.0
+                if agv.coordinates:
+                    distance = calculate_manhattan_distance(agv.coordinates, task_start_coord)
+                    distance_score = 1.0 / (1.0 + distance / 100.0)
+                
+                # 璐熻浇寰楀垎
+                load_score = 1.0 - agv.get_workload_ratio()
+                
+                # 鏁堢巼寰楀垎
+                efficiency_score = agv.calculate_efficiency_score(path_mapping)
+                
+                # 璁$畻缁煎悎寰楀垎
+                total_score = (
+                    self.distance_weight * distance_score +
+                    self.load_weight * load_score +
+                    self.efficiency_weight * efficiency_score
+                )
+                
+                task_agv_scores[(task.taskId, agv.agvId)] = total_score
+        
+        # 浣跨敤璐績绠楁硶杩涜鍖归厤
+        assignments = self._greedy_matching(unassigned_tasks, all_agvs, task_agv_scores)
+        
+        return assignments
+    
+    def _greedy_matching(self, tasks: List[TaskData], agvs: List[AGVModel], 
+                        scores: Dict[Tuple[str, str], float]) -> List[TaskAssignment]:
+        """
+        浣跨敤璐績绠楁硶杩涜浠诲姟-AGV鍖归厤
+        
+        Args:
+            tasks: 浠诲姟鍒楄〃
+            agvs: AGV鍒楄〃
+            scores: 浠诲姟-AGV瀵圭殑寰楀垎
+            
+        Returns:
+            List[TaskAssignment]: 鍒嗛厤缁撴灉
+        """
+        assignments = []
+        remaining_tasks = [task.taskId for task in tasks]
+        
+        # 閲嶅鍒嗛厤鐩村埌娌℃湁浠诲姟鎴栨病鏈夊彲鐢ˋGV
+        while remaining_tasks:
+            # 鎵惧埌寰楀垎鏈�楂樼殑浠诲姟-AGV瀵�
+            best_score = -1
+            best_task_id = None
+            best_agv = None
+            
+            for task_id in remaining_tasks:
+                for agv in agvs:
+                    if agv.is_overloaded():
+                        continue
+                        
+                    score = scores.get((task_id, agv.agvId), 0.0)
+                    if score > best_score:
+                        best_score = score
+                        best_task_id = task_id
+                        best_agv = agv
+            
+            if best_task_id and best_agv:
+                # 鑾峰彇AGV鐨勫師濮嬬姸鎬佹暟鎹潵鏌ユ壘鍙敤鑳岀瘬浣嶇疆
+                agv_status = self.agv_manager.get_agv_status(best_agv.agvId)
+                
+                if agv_status:
+                    # 鏌ユ壘鍙敤鐨勮儗绡撲綅缃�
+                    available_lev_id = self.find_available_backpack_slot(agv_status)
+                    
+                    if available_lev_id is not None:
+                        # 鎵惧埌瀵瑰簲鐨勪换鍔″璞�
+                        task = next((t for t in tasks if t.taskId == best_task_id), None)
+                        if task:
+                            # 鍒嗛厤浠诲姟鍒版寚瀹氳儗绡撲綅缃�
+                            success = self.assign_task_with_backpack(best_agv, task, available_lev_id)
+                            if success:
+                                assignments.append(TaskAssignment(
+                                    taskId=best_task_id,
+                                    agvId=best_agv.agvId,
+                                    lev_id=available_lev_id
+                                ))
+                                
+                                remaining_tasks.remove(best_task_id)
+                                self.logger.info(f"澶氱洰鏍囦紭鍖栵細浠诲姟 {best_task_id} 鍒嗛厤缁橝GV {best_agv.agvId}锛岃儗绡撲綅缃�: {available_lev_id}锛屽緱鍒�: {best_score:.3f}")
+                            else:
+                                self.logger.warning(f"浠诲姟 {best_task_id} 鍒嗛厤缁橝GV {best_agv.agvId} 澶辫触")
+                                break
+                        else:
+                            self.logger.error(f"鎵句笉鍒颁换鍔� {best_task_id} 鐨勮缁嗕俊鎭�")
+                            break
+                    else:
+                        self.logger.debug(f"AGV {best_agv.agvId} 娌℃湁鍙敤鐨勮儗绡撲綅缃紝璺宠繃")
+                        break
+                else:
+                    self.logger.warning(f"鏃犳硶鑾峰彇AGV {best_agv.agvId} 鐨勭姸鎬佷俊鎭�")
+                    break
+            else:
+                break
+        
+        return assignments
+
+
+class TaskAllocationFactory:
+    """浠诲姟鍒嗛厤绠楁硶宸ュ巶绫�"""
+    
+    @staticmethod
+    def create_allocator(algorithm_type: str, agv_manager: AGVModelManager) -> TaskAllocation:
+        """
+        鍒涘缓浠诲姟鍒嗛厤绠楁硶
+        
+        Args:
+            algorithm_type: 绠楁硶绫诲瀷
+            agv_manager: AGV妯″瀷绠$悊鍣�
+            
+        Returns:
+            TaskAllocation: 浠诲姟鍒嗛厤绠楁硶瀵硅薄
+        """
+        if algorithm_type == "NEAREST_FIRST":
+            return NearestFirstAllocation(agv_manager)
+        elif algorithm_type == "LOAD_BALANCED":
+            return LoadBalancedAllocation(agv_manager)
+        elif algorithm_type == "PRIORITY_FIRST":
+            return PriorityFirstAllocation(agv_manager)
+        elif algorithm_type == "MULTI_OBJECTIVE":
+            return MultiObjectiveAllocation(agv_manager)
+        else:
+            # 榛樿浣跨敤璐熻浇鍧囪 绠楁硶
+            return LoadBalancedAllocation(agv_manager) 
\ No newline at end of file

--
Gitblit v1.9.1