Lane sim: one decision per tick on a three-lane road
1. What Jev decides
Each tick: forward, ease left, ease right, brake, or stop. A second question scores the danger of keeping lane and speed. The state is the lane, the speed, and every obstacle within twelve car lengths with its lane, distance, type, speed, whether it is in the car's lane, and a precomputed ticks-to-impact. The world advances on a 1,000 ms tick. The decision for the next tick is requested at the start of the current one; if it is late, the last action repeats and the page counts it. A fixed 60-tick obstacle script (seed 42, 17 obstacles) is shared by Jev, a rule-based driver, and a driver that only goes forward.
2. The questions
The questions and limits, from the top of lane.mjs. This is the block a reviewer must read; the rest of the file is plumbing.
// ---- Review these. Everything else is plumbing. ----
const QUESTIONS = {
action: {
type: "choice",
instructions: "You drive the car. Distances are in car lengths ahead; the car moves `speed` lengths per tick; cones are static and cars ahead move at their own speed. Which action for the next tick avoids a collision and keeps moving?",
criteria: { forward: "Keep the lane; speed up by one, up to the maximum of 3", ease_left: "Move one lane to the left, same speed", ease_right: "Move one lane to the right, same speed", brake: "Keep the lane; slow down by one", stop: "Keep the lane; speed becomes 0 this tick" },
},
danger: { type: "score", instructions: "How close is a collision if the car keeps its lane and speed?", criteria: ["none: nothing ahead within 10 lengths", "low: something ahead but more than 4 lengths away", "high: something ahead within 4 lengths", "imminent: a collision next tick"] },
};
const LANES = 3, MAX_SPEED = 3, HORIZON = 12, TICKS = 60;
3. What the page shows
A vertical road with three lanes drawn on a canvas, the car in teal with its speed on it, cones in orange and cars in grey scrolling toward it. The five action probabilities as bars with the chosen one in orange, the danger score, and a bar chart of the decision time per tick with a red line at the tick length. Counters for tick, speed, collisions, late answers, mean decision time, and dollars. A form picks the driver and the script seed.
4. Run it
node --env-file=.env lane/lane.mjs # http://localhost:3006
node --env-file=.env lane/lane.mjs --tick 500
node --env-file=.env lane/lane.mjs --check # 5 runs, no tick wait
5. The check, verbatim
run 1: Jev 2 collisions, rules 0, forward-only 4; Jev mean 254 ms per tick
run 2: Jev 3 collisions, rules 0, forward-only 4; Jev mean 8567 ms per tick
run 3: Jev 3 collisions, rules 0, forward-only 4; Jev mean 568 ms per tick
run 4: Jev 2 collisions, rules 0, forward-only 4; Jev mean 370 ms per tick
run 5: Jev 3 collisions, rules 0, forward-only 4; Jev mean 371 ms per tick
total over 5 runs of 60 ticks (17 obstacles): Jev 13 collisions, rules 0, forward-only 20; mean 2026 ms per decision, $0.0079
The first check, before ticks_to_impact was added to the state:
run 1: Jev 4 collisions, rules 0; Jev mean 510 ms per tick
run 2: Jev 7 collisions, rules 0; Jev mean 359 ms per tick
run 3: Jev 7 collisions, rules 0; Jev mean 324 ms per tick
run 4: Jev 6 collisions, rules 0; Jev mean 323 ms per tick
run 5: Jev 5 collisions, rules 0; Jev mean 328 ms per tick
total over 5 runs of 60 ticks (17 obstacles): Jev 29 collisions, rules 0; mean 369 ms per decision, $0.0076The second, with it: 2, 3, 4, 4, 3 collisions, 16 in total, mean 512 ms per decision.
6. Findings
- The assessment's proof check said fewer than 3 collisions in 5 runs. Jev made 29 without arithmetic help, then 16 and 13 with a precomputed ticks-to-impact per obstacle. The target is not met, and the check no longer claims it. It asserts that Jev beats the forward-only driver (13 against 20). The rule-based driver, with the same fields, made 0.
- Jev reads; it does not compute. Given distance 4 and speed 3 it does not reliably conclude that the next tick collides. Given
ticks_to_impact: 1.3it does better, and still not well. - The world is a text object, and the assessment said the videos never showed how the driving demo turned sensors into text. This page is one answer to that question, and the collision count is the cost of that answer.
- Run 2 of the final check averaged 8,567 ms per decision. The other four averaged 254 to 568 ms. That run fell in the gateway's slow half hour; every answer still arrived. On the live page at a 1,000 ms tick, most of those answers would have been late and the last action would have repeated.
- The check runs with no tick wait, so the late-answer path is never exercised by it. The HTTP smoke test at an 800 ms tick ran 11 ticks with 0 late answers at about 300 ms per decision.
7. Cost and latency
$0.00003 per tick with two questions. A 60-tick run: $0.0016. An hour at one tick per second: $0.11.