package com.algo.service; import com.algo.config.EnvDataConfig; import com.algo.model.AGVStatus; import com.algo.model.BackpackData; import com.algo.model.TaskAssignment; import com.algo.model.TaskData; import com.algo.util.JsonUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * 任务分配服务类 */ @Service public class TaskAllocationService { @Autowired private EnvDataConfig envDataConfig; /** * 执行任务分配 * 根据AGV状态和任务列表进行智能分配 * * @param agvStatusList AGV状态列表 * @param taskList 任务列表 * @return 任务分配结果列表 */ public List allocateTasks(List agvStatusList, List taskList) { System.out.println("开始任务分配,AGV数量: " + agvStatusList.size() + ", 任务数量: " + taskList.size()); // 输出环境信息 System.out.println("环境信息:宽度=" + envDataConfig.getEnvironmentConfig().get("width") + ", 高度=" + envDataConfig.getEnvironmentConfig().get("height") + ", 工作站数量=" + envDataConfig.getEnvironmentConfig().get("stationCount")); List assignments = new ArrayList<>(); // 1. 过滤可用的AGV List availableAgvs = agvStatusList.stream() .filter(agv -> agv.isAvailable() && agv.getAvailableBackpackCount() > 0) .collect(Collectors.toList()); System.out.println("可用AGV数量: " + availableAgvs.size()); if (availableAgvs.isEmpty()) { System.out.println("没有可用的AGV,任务分配结束"); return assignments; } // 2. 过滤需要分配的任务(排除已指定AGV的任务) List unassignedTasks = taskList.stream() .filter(task -> !task.isAssignedToAgv() && task.isTransportTask()) .collect(Collectors.toList()); System.out.println("需要分配的运输任务数量: " + unassignedTasks.size()); // 3. 按优先级排序任务 unassignedTasks.sort((t1, t2) -> Integer.compare(t2.getPriority(), t1.getPriority())); // 4. 使用智能分配策略(考虑工作站信息) assignments.addAll(performIntelligentAllocation(availableAgvs, unassignedTasks)); System.out.println("任务分配完成,生成分配结果数量: " + assignments.size()); return assignments; } /** * 执行智能分配策略 * 考虑AGV位置、任务位置、背篓容量、工作站容量等因素 * * @param availableAgvs 可用AGV列表 * @param tasks 待分配任务列表 * @return 分配结果列表 */ private List performIntelligentAllocation(List availableAgvs, List tasks) { List assignments = new ArrayList<>(); // 为每个AGV维护一个工作负载记录 Map agvWorkLoad = new HashMap<>(); Map agvUsedBackpacks = new HashMap<>(); for (AGVStatus agv : availableAgvs) { agvWorkLoad.put(agv.getAgvId(), 0); agvUsedBackpacks.put(agv.getAgvId(), 0); } // 按地理位置分组任务(考虑工作站信息) Map> tasksByStartLocation = groupTasksByStartLocation(tasks); // 为每个位置分组分配AGV for (Map.Entry> entry : tasksByStartLocation.entrySet()) { String startLocation = entry.getKey(); List locationTasks = entry.getValue(); System.out.println("处理起点 " + startLocation + " 的任务,数量: " + locationTasks.size()); // 检查是否为工作站 if (JsonUtils.isStation(startLocation, envDataConfig.getEnvironmentConfig())) { Map stationInfo = JsonUtils.getStationInfo(startLocation, envDataConfig.getEnvironmentConfig()); if (stationInfo != null) { Integer capacity = (Integer) stationInfo.get("capacity"); System.out.println("工作站 " + startLocation + " 容量: " + capacity); // 限制同时分配给该工作站的任务数量(不超过容量) locationTasks = locationTasks.subList(0, Math.min(locationTasks.size(), capacity)); } } // 找到距离该位置最近的AGV AGVStatus bestAgv = findNearestAvailableAgv(availableAgvs, startLocation, agvUsedBackpacks); if (bestAgv != null) { // 为该AGV分配尽可能多的任务(考虑背篓容量) int availableBackpacks = bestAgv.getAvailableBackpackCount() - agvUsedBackpacks.get(bestAgv.getAgvId()); int tasksToAssign = Math.min(locationTasks.size(), availableBackpacks); for (int i = 0; i < tasksToAssign; i++) { TaskData task = locationTasks.get(i); // 查找可用的背篓位置 int backpackIndex = findAvailableBackpackIndex(bestAgv, agvUsedBackpacks.get(bestAgv.getAgvId())); if (backpackIndex != -1) { // 创建取货任务分配 TaskAssignment takeAssignment = new TaskAssignment( task.getTaskId(), bestAgv.getAgvId(), TaskAssignment.generateSegId(task.getTaskId(), bestAgv.getAgvId(), 1), String.valueOf(backpackIndex), TaskAssignment.TYPE_TAKE ); assignments.add(takeAssignment); // 创建放货任务分配 TaskAssignment putAssignment = new TaskAssignment( task.getTaskId(), bestAgv.getAgvId(), TaskAssignment.generateSegId(task.getTaskId(), bestAgv.getAgvId(), 2), String.valueOf(backpackIndex), TaskAssignment.TYPE_PUT ); assignments.add(putAssignment); // 更新AGV工作负载 agvWorkLoad.put(bestAgv.getAgvId(), agvWorkLoad.get(bestAgv.getAgvId()) + 1); agvUsedBackpacks.put(bestAgv.getAgvId(), agvUsedBackpacks.get(bestAgv.getAgvId()) + 1); System.out.println("分配任务 " + task.getTaskId() + " 给AGV " + bestAgv.getAgvId() + " 背篓 " + backpackIndex + " (起点: " + startLocation + ")"); } else { System.out.println("AGV " + bestAgv.getAgvId() + " 没有可用的背篓位置"); break; } } } else { System.out.println("未找到可用的AGV处理起点 " + startLocation + " 的任务"); } } return assignments; } /** * 按起点位置分组任务 * * @param tasks 任务列表 * @return 按起点分组的任务Map */ private Map> groupTasksByStartLocation(List tasks) { Map> grouped = new HashMap<>(); for (TaskData task : tasks) { String startLocation = task.getStart(); grouped.computeIfAbsent(startLocation, k -> new ArrayList<>()).add(task); } return grouped; } /** * 查找距离指定位置最近的可用AGV * * @param availableAgvs 可用AGV列表 * @param targetLocation 目标位置 * @param usedBackpacks 已使用背篓数量统计 * @return 最近的可用AGV */ private AGVStatus findNearestAvailableAgv(List availableAgvs, String targetLocation, Map usedBackpacks) { AGVStatus bestAgv = null; double minDistance = Double.MAX_VALUE; int[] targetCoord = JsonUtils.getCoordinate(targetLocation, envDataConfig.getPathMapping()); if (targetCoord == null) { System.out.println("无法获取目标位置 " + targetLocation + " 的坐标"); return availableAgvs.isEmpty() ? null : availableAgvs.get(0); } for (AGVStatus agv : availableAgvs) { // 检查AGV是否还有可用背篓 int availableBackpacks = agv.getAvailableBackpackCount() - usedBackpacks.get(agv.getAgvId()); if (availableBackpacks <= 0) { continue; } int[] agvCoord = JsonUtils.getCoordinate(agv.getPosition(), envDataConfig.getPathMapping()); if (agvCoord != null) { double distance = JsonUtils.calculateManhattanDistance(agvCoord, targetCoord); // 考虑AGV的工作负载(距离越近且负载越轻越好) double adjustedDistance = distance + usedBackpacks.get(agv.getAgvId()) * 2.0; if (adjustedDistance < minDistance) { minDistance = adjustedDistance; bestAgv = agv; } } } return bestAgv; } /** * 查找AGV的可用背篓位置 * * @param agv AGV状态 * @param usedCount 已使用的背篓数量 * @return 可用背篓索引,如果没有可用则返回-1 */ private int findAvailableBackpackIndex(AGVStatus agv, int usedCount) { if (agv.getBackpack() == null || agv.getBackpack().isEmpty()) { return usedCount == 0 ? 0 : -1; } int availableCount = 0; for (BackpackData backpack : agv.getBackpack()) { if (backpack.isAvailable()) { if (availableCount >= usedCount) { return backpack.getIndex(); } availableCount++; } } return -1; } /** * 验证任务分配结果 * * @param assignments 分配结果列表 * @return 验证是否通过 */ public boolean validateAssignments(List assignments) { Map> agvBackpackUsage = new HashMap<>(); for (TaskAssignment assignment : assignments) { if (!assignment.isValid()) { System.out.println("发现无效的任务分配: " + assignment); return false; } String agvId = assignment.getAgvId(); String backpackId = assignment.getLev(); agvBackpackUsage.computeIfAbsent(agvId, k -> new HashSet<>()).add(backpackId); } // 检查背篓使用冲突 for (Map.Entry> entry : agvBackpackUsage.entrySet()) { String agvId = entry.getKey(); Set usedBackpacks = entry.getValue(); System.out.println("AGV " + agvId + " 使用背篓: " + usedBackpacks); } return true; } }