1
zhang
2025-09-10 b1e74bb24e7785176e59699cfe8eb4f217c958c8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
package com.algo.service;
 
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.stereotype.Service;
 
import java.util.*;
import java.util.stream.Collectors;
 
/**
 * 任务分配服务类
 */
public class TaskAllocationService {
 
    private Map<String, Map<String, Integer>> pathMapping;
    private Map<String, Object> environmentConfig;
 
    /**
     * 构造函数
     *
     * @param pathMapping       路径映射信息
     * @param environmentConfig 环境配置信息
     */
    public TaskAllocationService(Map<String, Map<String, Integer>> pathMapping,
                                 Map<String, Object> environmentConfig) {
        this.pathMapping = pathMapping;
        this.environmentConfig = environmentConfig;
    }
 
    /**
     * 执行任务分配
     * 根据AGV状态和任务列表进行智能分配
     *
     * @param agvStatusList AGV状态列表
     * @param taskList      任务列表
     * @return 任务分配结果列表
     */
    public List<TaskAssignment> allocateTasks(List<AGVStatus> agvStatusList, List<TaskData> taskList) {
        System.out.println("开始任务分配,AGV数量: " + agvStatusList.size() + ", 任务数量: " + taskList.size());
 
        // 输出环境信息
        System.out.println("环境信息:宽度=" + environmentConfig.get("width") +
                ", 高度=" + environmentConfig.get("height") +
                ", 工作站数量=" + environmentConfig.get("stationCount"));
 
        List<TaskAssignment> assignments = new ArrayList<>();
 
        // 1. 过滤可用的AGV
        List<AGVStatus> 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<TaskData> 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<TaskAssignment> performIntelligentAllocation(List<AGVStatus> availableAgvs, List<TaskData> tasks) {
        List<TaskAssignment> assignments = new ArrayList<>();
 
        // 为每个AGV维护一个工作负载记录
        Map<String, Integer> agvWorkLoad = new HashMap<>();
        Map<String, Integer> agvUsedBackpacks = new HashMap<>();
 
        for (AGVStatus agv : availableAgvs) {
            agvWorkLoad.put(agv.getAgvId(), 0);
            agvUsedBackpacks.put(agv.getAgvId(), 0);
        }
 
        // 按地理位置分组任务(考虑工作站信息)
        Map<String, List<TaskData>> tasksByStartLocation = groupTasksByStartLocation(tasks);
 
        // 为每个位置分组分配AGV
        for (Map.Entry<String, List<TaskData>> entry : tasksByStartLocation.entrySet()) {
            String startLocation = entry.getKey();
            List<TaskData> locationTasks = entry.getValue();
 
            System.out.println("处理起点 " + startLocation + " 的任务,数量: " + locationTasks.size());
 
            // 检查是否为工作站
            if (JsonUtils.isStation(startLocation, environmentConfig)) {
                Map<String, Object> stationInfo = JsonUtils.getStationInfo(startLocation, environmentConfig);
                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<String, List<TaskData>> groupTasksByStartLocation(List<TaskData> tasks) {
        Map<String, List<TaskData>> 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<AGVStatus> availableAgvs, String targetLocation, Map<String, Integer> usedBackpacks) {
        AGVStatus bestAgv = null;
        double minDistance = Double.MAX_VALUE;
 
        int[] targetCoord = JsonUtils.getCoordinate(targetLocation, pathMapping);
        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(), pathMapping);
            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<TaskAssignment> assignments) {
        Map<String, Set<String>> 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<String, Set<String>> entry : agvBackpackUsage.entrySet()) {
            String agvId = entry.getKey();
            Set<String> usedBackpacks = entry.getValue();
 
            System.out.println("AGV " + agvId + " 使用背篓: " + usedBackpacks);
        }
 
        return true;
    }