feat(javaTest): plan history tasks from physical endpoints

This commit is contained in:
zgw
2026-07-31 14:07:56 +08:00
parent 5ae50a85e2
commit a4e63ebb9a
4 changed files with 180 additions and 104 deletions

View File

@@ -1,27 +1,16 @@
package com.ft546.wcs.shadow.history.simulation;
import com.ft546.wcs.demo.model.DispatchTask;
import com.ft546.wcs.demo.model.Site;
import com.ft546.wcs.demo.model.VehicleSnapshot;
import com.ft546.wcs.demo.traffic.GridMap;
import com.ft546.wcs.shadow.history.HistoricalMapSite;
import com.ft546.wcs.shadow.history.HistoricalMapCell;
import com.ft546.wcs.shadow.history.HistoricalPath;
import com.ft546.wcs.shadow.history.HistoricalQueueDataset;
import com.ft546.wcs.shadow.history.HistoricalQueueNormalizer;
import com.ft546.wcs.shadow.history.HistoricalQueueRecord;
import com.ft546.wcs.shadow.map.EffectiveTrafficMap;
import com.ft546.wcs.shadow.map.TrafficMapCompiler;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class HistoricalSimulationInputFactory {
public HistoricalSimulationInput create(HistoricalQueueDataset dataset) {
@@ -39,107 +28,52 @@ public final class HistoricalSimulationInputFactory {
List<HistoricalSimulationTask> tasks = new ArrayList<HistoricalSimulationTask>();
List<HistoricalSimulationFailure> failures = new ArrayList<HistoricalSimulationFailure>();
HistoricalGridMapCompiler.CompiledHistoricalMap compiled =
new HistoricalGridMapCompiler().compile(dataset.getFullMapCells());
PhysicalEndpointResolver endpointResolver = new PhysicalEndpointResolver();
int sequence = 0;
for (HistoricalPath path : paths) {
HistoricalQueueRecord record = path.getRecord();
int stableSequence = sequence++;
String id = simulationId(record, stableSequence);
DispatchTask.TaskType type = taskType(record.getTaskType());
if (!path.isReplayable() || type == null) {
failures.add(new HistoricalSimulationFailure(id, record, failureReason(path, type)));
if (type == null) {
failures.add(new HistoricalSimulationFailure(id, record, "INVALID_TASK_TYPE"));
continue;
}
List<String> nodes = path.getNodes();
String source = dataset.getMapSites().contains(record.getStartSite())
? record.getStartSite() : nodes.get(0);
String target = dataset.getMapSites().contains(record.getEndSite())
? record.getEndSite() : nodes.get(nodes.size() - 1);
PhysicalEndpointResolver.ResolvedEndpoints endpoints = endpointResolver.resolve(
record, compiled.getPassableSites());
if (compiled.getComponentId(endpoints.getSource())
!= compiled.getComponentId(endpoints.getTarget())) {
throw new IllegalArgumentException("unreachable physical endpoints for " + id);
}
tasks.add(new HistoricalSimulationTask(id, record, type,
record.getPriority() == null ? Integer.MAX_VALUE : record.getPriority(),
path.getCreatedAt(), path.getFinishedAt(), source, target, nodes, stableSequence));
path.getCreatedAt(), path.getFinishedAt(), endpoints.getSource(),
endpoints.getTarget(), path.getNodes(), stableSequence));
}
GridMap gridMap = buildGridMap(tasks, dataset.getMapSiteDetails());
EffectiveTrafficMap trafficMap = buildTrafficMap(tasks);
List<VehicleSnapshot> vehicles = initialVehicles(tasks, dataset.getMapSiteDetails());
return new HistoricalSimulationInput(tasks, failures, gridMap, trafficMap, vehicles);
List<VehicleSnapshot> vehicles = initialVehicles(compiled);
return new HistoricalSimulationInput(tasks, failures, compiled.getGridMap(),
compiled.getTrafficMap(), vehicles);
}
private GridMap buildGridMap(List<HistoricalSimulationTask> tasks,
Map<String, HistoricalMapSite> details) {
LinkedHashSet<String> nodes = new LinkedHashSet<String>();
LinkedHashSet<String> edges = new LinkedHashSet<String>();
for (HistoricalSimulationTask task : tasks) {
List<String> path = task.getHistoricalNodes();
nodes.addAll(path);
for (int i = 1; i < path.size(); i++) {
edges.add(edgeId(path.get(i - 1), path.get(i)));
}
}
GridMap map = new GridMap();
for (String node : nodes) {
HistoricalMapSite detail = details.get(node);
map.addSite(new Site(node, detail.getZ(), detail.getX(), detail.getY(),
detail.getAxy().isEmpty() ? "OFFLINE" : detail.getAxy()));
}
for (String edge : edges) {
String[] pair = edge.split("\\|", -1);
map.connect(pair[0], pair[1]);
}
return map;
}
private EffectiveTrafficMap buildTrafficMap(List<HistoricalSimulationTask> tasks) {
LinkedHashSet<String> nodes = new LinkedHashSet<String>();
LinkedHashMap<String, TrafficMapCompiler.EdgeDefinition> edges =
new LinkedHashMap<String, TrafficMapCompiler.EdgeDefinition>();
for (HistoricalSimulationTask task : tasks) {
List<String> path = task.getHistoricalNodes();
nodes.addAll(path);
for (int i = 1; i < path.size(); i++) {
String id = edgeId(path.get(i - 1), path.get(i));
String[] pair = id.split("\\|", -1);
edges.put(id, new TrafficMapCompiler.EdgeDefinition(pair[0], pair[1]));
}
}
TrafficMapCompiler.MapDefinition definition = new TrafficMapCompiler.MapDefinition(
"FT546-HISTORY-SIM", 1L, "OFFLINE", true,
"history-snapshot-v1", "history-snapshot-v1", nodes,
new LinkedHashSet<TrafficMapCompiler.EdgeDefinition>(edges.values()),
Collections.emptyMap(), Collections.emptySet(), Collections.emptySet());
return new TrafficMapCompiler().compile(definition);
}
private List<VehicleSnapshot> initialVehicles(List<HistoricalSimulationTask> tasks,
Map<String, HistoricalMapSite> details) {
Map<String, HistoricalSimulationTask> earliest =
new HashMap<String, HistoricalSimulationTask>();
for (HistoricalSimulationTask task : tasks) {
String vehicle = task.getRecord().getAgvId();
if (vehicle != null && (!earliest.containsKey(vehicle)
|| task.getCreatedAt().isBefore(earliest.get(vehicle).getCreatedAt()))) {
earliest.put(vehicle, task);
}
}
List<String> ids = new ArrayList<String>(earliest.keySet());
Collections.sort(ids);
private List<VehicleSnapshot> initialVehicles(
HistoricalGridMapCompiler.CompiledHistoricalMap compiled) {
List<VehicleSnapshot> vehicles = new ArrayList<VehicleSnapshot>();
for (String id : ids) {
String site = earliest.get(id).getPhysicalSource();
vehicles.add(new VehicleSnapshot(id, details.get(site).getZ(), site,
for (int floor = 1; floor <= 3; floor++) {
String id = String.valueOf(floor);
String site = "01070" + floor;
HistoricalMapCell cell = compiled.getPassableSites().get(site);
if (cell == null || cell.getZ() != floor) {
throw new IllegalArgumentException("missing fleet start site " + site);
}
vehicles.add(new VehicleSnapshot(id, floor, site,
5, 1, 100, true, true, false));
}
return vehicles;
}
private String failureReason(HistoricalPath path, DispatchTask.TaskType type) {
if (type == null) return "INVALID_TASK_TYPE";
for (String issue : path.getIssues()) {
if (issue.startsWith("UNKNOWN_MAP_SITE")) return "UNKNOWN_MAP";
}
return "INPUT_REJECTED";
}
private DispatchTask.TaskType taskType(String value) {
if ("1".equals(value)) return DispatchTask.TaskType.INBOUND;
if ("2".equals(value)) return DispatchTask.TaskType.OUTBOUND;
@@ -151,9 +85,5 @@ public final class HistoricalSimulationInputFactory {
return text(record.getTaskNo()) + "@" + text(record.getGuid()) + "#" + stableSequence;
}
private static String edgeId(String left, String right) {
return left.compareTo(right) <= 0 ? left + "|" + right : right + "|" + left;
}
private static String text(String value) { return value == null ? "" : value; }
}

View File

@@ -0,0 +1,56 @@
package com.ft546.wcs.shadow.history.simulation;
import com.ft546.wcs.shadow.history.HistoricalMapCell;
import com.ft546.wcs.shadow.history.HistoricalQueueRecord;
import java.util.Map;
public final class PhysicalEndpointResolver {
public ResolvedEndpoints resolve(HistoricalQueueRecord record,
Map<String, HistoricalMapCell> passableSites) {
if (record == null || passableSites == null) {
throw new IllegalArgumentException("record and passable sites are required");
}
HistoricalMapCell source = passableSites.get(record.getStartSite());
if (source == null) {
throw new IllegalArgumentException("unknown physical source " + record.getStartSite());
}
int floor = source.getZ();
boolean declaredFloorConsistent = true;
if (record.getFloor() != null && !record.getFloor().trim().isEmpty()) {
try {
declaredFloorConsistent = Integer.parseInt(record.getFloor().trim()) == floor;
} catch (NumberFormatException ex) {
declaredFloorConsistent = false;
}
}
String targetId = "tsj".equals(record.getEndSite())
? "07050" + floor : record.getEndSite();
HistoricalMapCell target = passableSites.get(targetId);
if (target == null) {
throw new IllegalArgumentException("unknown physical target " + targetId);
}
return new ResolvedEndpoints(source.getSiteId(), target.getSiteId(), floor,
declaredFloorConsistent);
}
public static final class ResolvedEndpoints {
private final String source;
private final String target;
private final int floor;
private final boolean declaredFloorConsistent;
private ResolvedEndpoints(String source, String target, int floor,
boolean declaredFloorConsistent) {
this.source = source;
this.target = target;
this.floor = floor;
this.declaredFloorConsistent = declaredFloorConsistent;
}
public String getSource() { return source; }
public String getTarget() { return target; }
public int getFloor() { return floor; }
public boolean isDeclaredFloorConsistent() { return declaredFloorConsistent; }
}
}