feat: add executable wcs dispatch simulation

This commit is contained in:
zgw
2026-07-30 11:28:59 +08:00
parent 3860e3f014
commit ae338b7e35
3 changed files with 189 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
package com.ft546.wcs.demo;
import com.ft546.wcs.demo.center.CycleResult;
import com.ft546.wcs.demo.center.LegacyDispatchCenter;
import com.ft546.wcs.demo.center.QueueAdmissionService;
import com.ft546.wcs.demo.center.VehicleAssignmentService;
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.repository.InMemoryWcsState;
import com.ft546.wcs.demo.simulation.SimulatedProtocolAdapter;
import com.ft546.wcs.demo.traffic.GridMap;
import com.ft546.wcs.demo.traffic.GridPathPlanner;
import com.ft546.wcs.demo.traffic.TrafficController;
import java.io.PrintStream;
public final class DemoApplication {
private DemoApplication() {
}
public static void main(String[] args) {
runScenario(System.out);
}
public static void runScenario(PrintStream out) {
if (out == null) {
throw new IllegalArgumentException("output must not be null");
}
GridMap map = createMap();
InMemoryWcsState state = new InMemoryWcsState();
state.addVehicle(vehicle("3", "V3"));
state.addVehicle(vehicle("2", "B"));
state.addVehicle(vehicle("1", "A"));
state.addTask(new DispatchTask(
"TASK-OUT-1",
DispatchTask.TaskType.OUTBOUND,
"A",
"TARGET",
1,
2
));
QueueAdmissionService admission = new QueueAdmissionService(
new VehicleAssignmentService(),
map
);
SimulatedProtocolAdapter protocol = new SimulatedProtocolAdapter();
protocol.failNextSend("simulated first PLC rejection");
LegacyDispatchCenter center = new LegacyDispatchCenter(
state,
admission,
new TrafficController(map, new GridPathPlanner()),
protocol
);
out.println("FT546 WCS LEGACY DISPATCH AND TRAFFIC DEMO");
out.println("MODE LEGACY / IO DISABLED / IN-MEMORY ONLY");
for (int cycle = 0; cycle < 6; cycle++) {
printCycle(out, center.runCycle());
}
state.addTask(new DispatchTask(
"TASK-NO-PATH",
DispatchTask.TaskType.RELOCATION,
"TARGET",
"ISOLATED",
1,
1
));
printCycle(out, center.runCycle());
out.println(
"SUMMARY cycles=" + state.getCycleNumber()
+ " activeQueues=" + state.getActiveQueues().size()
+ " history=" + state.getHistory().size()
+ " protocolAttempts=" + protocol.getAttemptedQueueIds().size()
);
}
private static void printCycle(PrintStream out, CycleResult result) {
for (String event : result.getEvents()) {
out.println(event);
}
}
private static GridMap createMap() {
GridMap map = new GridMap();
map.addSite(new Site("A", 1, 0, 0, "START"));
map.addSite(new Site("B", 1, 1, 0, "AISLE-1"));
map.addSite(new Site("TARGET", 1, 2, 0, "AISLE-1"));
map.addSite(new Site("CACHE", 1, 1, 1, "CACHE"));
map.addSite(new Site("V3", 1, 0, 1, "V3-CHANNEL"));
map.addSite(new Site("ISOLATED", 1, 9, 9, "ISLAND"));
map.connect("A", "B");
map.connect("B", "TARGET");
map.connect("B", "CACHE");
map.connect("A", "V3");
map.setCacheSite("AISLE-1", "CACHE");
return map;
}
private static VehicleSnapshot vehicle(String id, String site) {
return new VehicleSnapshot(id, 1, site, 5, 1, 80, true, true, false);
}
}

View File

@@ -0,0 +1,32 @@
package com.ft546.wcs.demo;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertTrue;
class DemoScenarioTest {
@Test
void executableScenarioShowsAssignmentAvoidanceRetryCompletionAndNoPathHold()
throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
DemoApplication.runScenario(new PrintStream(output, true, "UTF-8"));
String text = new String(output.toByteArray(), StandardCharsets.UTF_8);
assertTrue(text.contains("CYCLE"));
assertTrue(text.contains("ASSIGN"));
assertTrue(text.contains("PATH"));
assertTrue(text.contains("AVOID"));
assertTrue(text.contains("HOLD HOLD_PROTOCOL_FAILURE"));
assertTrue(text.contains("HOLD HOLD_CHANNEL_BLOCKED"));
assertTrue(text.contains("HOLD HOLD_NO_PATH"));
assertTrue(text.contains("SEND"));
assertTrue(text.contains("COMPLETE"));
assertTrue(text.contains("SUMMARY cycles=7 activeQueues=1 history=2"));
}
}