Bring the floor to life: coffee runs, snack breaks, restroom trips

Idle agents now live a little: after settling in they occasionally walk the
lane graph to the coffee machine, snack counter, or a restroom stall, dwell
there, and stroll back - carrying their coffee or snack to the desk for a
while. Working agents never leave, and an agent woken to work mid-break
abandons the trip and heads straight home. Randomness is injected so the
whole loop - trip, dwell, carry-back, interruption - is deterministic under
unit test, and a settle period keeps the floor calm right after it loads.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-06 22:02:35 -04:00
1 parent e8c8414613
commit 574c7e0ec6
2 files changed
+218 -9

No files matched your search

@@ -1,10 +1,10 @@
import { describe, expect, test } from "vitest";
import { OfficeSimulation, cameraFor, type MoveInput } from "../../src/renderer/src/pages/office/simulation";
import type { OfficeAgentInput } from "../../src/renderer/src/pages/office/office-types";
import type { AgentActivity, OfficeAgentInput } from "../../src/renderer/src/pages/office/office-types";
const IDLE: MoveInput = { up: false, down: false, left: false, right: false };
function agentInput(id: string, roleLevel = "staff"): OfficeAgentInput {
function agentInput(id: string, roleLevel = "staff", activity: AgentActivity = "idle"): OfficeAgentInput {
return {
id,
name: `Agent ${id}`,
@@ -12,7 +12,7 @@ function agentInput(id: string, roleLevel = "staff"): OfficeAgentInput {
title: "Engineer",
department: "Engineering",
roleLevel,
activity: "idle",
activity,
taskTitle: null,
};
}
@@ -94,6 +94,59 @@ describe("office simulation", () => {
expect(diagonal).toBeGreaterThan(straight * 0.7);
});
test("idle agents take a coffee break and carry the cup back to their desk", () => {
const sim = new OfficeSimulation(() => 0);
sim.sync([agentInput("a")]);
const agent = sim.agents[0];
const coffee = sim.plan.amenities.find((spot) => spot.kind === "coffee")!;
let reachedCoffee = false;
let backSeated = false;
for (let i = 0; i < 6000; i++) {
sim.step(16, IDLE);
if (agent.behavior.kind === "dwelling") {
expect(agent.x).toBe(coffee.stand.x);
expect(agent.y).toBe(coffee.stand.y);
reachedCoffee = true;
}
if (reachedCoffee && agent.behavior.kind === "seated") {
backSeated = true;
break;
}
}
expect(reachedCoffee).toBe(true);
expect(backSeated).toBe(true);
expect(agent.x).toBe(agent.seat.x);
expect(agent.y).toBe(agent.seat.y);
expect(agent.carrying).toBe("coffee");
});
test("working agents never leave their desks", () => {
const sim = new OfficeSimulation(() => 0);
sim.sync([agentInput("a", "staff", "active")]);
const agent = sim.agents[0];
for (let i = 0; i < 600; i++) sim.step(16, IDLE);
expect(agent.behavior.kind).toBe("seated");
expect(agent.x).toBe(agent.seat.x);
expect(agent.y).toBe(agent.seat.y);
});
test("an agent called to work abandons the break and returns to their desk", () => {
const sim = new OfficeSimulation(() => 0);
sim.sync([agentInput("a")]);
const agent = sim.agents[0];
for (let i = 0; i < 3000 && agent.behavior.kind === "seated"; i++) sim.step(16, IDLE);
for (let i = 0; i < 30; i++) sim.step(16, IDLE);
expect(agent.behavior.kind).toBe("walking");
expect(agent.x === agent.seat.x && agent.y === agent.seat.y).toBe(false);
sim.sync([agentInput("a", "staff", "active")]);
for (let i = 0; i < 6000 && sim.agents[0].behavior.kind !== "seated"; i++) sim.step(16, IDLE);
expect(sim.agents[0].behavior.kind).toBe("seated");
expect(sim.agents[0].x).toBe(sim.agents[0].seat.x);
expect(sim.agents[0].y).toBe(sim.agents[0].seat.y);
});
test("clicks hit the agent drawn at that spot, frontmost first", () => {
const sim = new OfficeSimulation();
sim.sync([agentInput("a"), agentInput("b")]);