IndusHomie commited on
Commit
71a3cc0
·
verified ·
1 Parent(s): beb66b1

Publish the first leaderboard: 6 agents, 30 zones, build 1.15.0_99000014

Browse files
app.py CHANGED
@@ -211,7 +211,7 @@ async def play(seed: int):
211
  d = r.structured_content or {}
212
  if d.get("position_x") is not None:
213
  path.append((d["position_x"], d["position_z"]))
214
- sit = {**sit, **{k: v for k, v in d.items() if v is not None}}
215
  feed.append({"name": name, "args": args, "free": False,
216
  "text": (r.content[0].text if r.content else "").strip()})
217
  yield frame()
@@ -284,6 +284,105 @@ policy trained in the environment, included so the model scores have a floor and
284
  comparison.
285
  """
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  # ---------------------------------------------------------------- the page
288
 
289
  CSS = """
@@ -380,7 +479,25 @@ SuperGaming  ·  code, task pack and tests in the Files tab
380
 
381
  with gr.Blocks(title="Prime Rush — a battle royale as an MCP environment") as demo:
382
  gr.HTML(HERO)
383
- with gr.Tab("Demo"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  with gr.Row():
385
  with gr.Column(scale=3):
386
  gr.HTML('<div class="pr-lab">The match</div>')
 
211
  d = r.structured_content or {}
212
  if d.get("position_x") is not None:
213
  path.append((d["position_x"], d["position_z"]))
214
+ sit = _merge(sit, d, False)
215
  feed.append({"name": name, "args": args, "free": False,
216
  "text": (r.content[0].text if r.content else "").strip()})
217
  yield frame()
 
284
  comparison.
285
  """
286
 
287
+
288
+ # ---------------------------------------------------------------- replays
289
+
290
+ REPLAY_DIR = Path(__file__).resolve().parent / "replays"
291
+
292
+ # Only get_situation reports the circle. Movement tools report the agent and a
293
+ # couple of derived fields, so merging everything from every call leaves a
294
+ # stale next-circle sitting beside a fresh current one - which draws a "next"
295
+ # ring larger than the one it is shrinking towards.
296
+ ZONE_FIELDS = ("zone_center_x", "zone_center_z", "zone_radius", "zone_round",
297
+ "next_zone_center_x", "next_zone_center_z", "next_zone_radius")
298
+
299
+
300
+ def _merge(sit: dict | None, result: dict, is_situation: bool) -> dict:
301
+ keep = {k: v for k, v in result.items()
302
+ if v is not None and (is_situation or k not in ZONE_FIELDS)}
303
+ return {**(sit or {}), **keep}
304
+
305
+
306
+ def _replays() -> dict[str, Path]:
307
+ """Recorded episodes, newest naming first. Each file is the trajectory a
308
+ real run wrote: the model, the zone, every tool call and its response."""
309
+ out = {}
310
+ for f in sorted(REPLAY_DIR.glob("*.json")) if REPLAY_DIR.exists() else []:
311
+ try:
312
+ d = json.loads(f.read_text(encoding="utf-8"))
313
+ except ValueError:
314
+ continue
315
+ o = d.get("outcome") or {}
316
+ out[f"{d.get('model', '?')} — zone {d.get('seed', '?')} — "
317
+ f"{o.get('frac_inside_zone', 0)*100:.0f}% inside"] = f
318
+ return out
319
+
320
+
321
+ async def play_replay(label: str):
322
+ """Step through a recorded episode at reading speed.
323
+
324
+ This is a real run against a real game server, not the stand-in: the
325
+ positions and the tool responses are what the model actually got.
326
+ """
327
+ import asyncio
328
+ files = _replays()
329
+ f = files.get(label)
330
+ if f is None:
331
+ yield render_map([], None), render_calls([]), render_stats(None)
332
+ return
333
+ d = json.loads(f.read_text(encoding="utf-8"))
334
+ calls, path, sit, feed = d.get("calls", []), [], None, []
335
+ o = d.get("outcome") or {}
336
+
337
+ for c in calls:
338
+ r = c.get("result") or {}
339
+ if r.get("position_x") is not None:
340
+ path.append((r["position_x"], r["position_z"]))
341
+ sit = _merge(sit, r, c.get("tool") == "get_situation")
342
+ feed.append({"name": c.get("tool", "?"), "args": c.get("input") or {},
343
+ "free": c.get("tool") == "get_situation",
344
+ "text": _summarise(c)})
345
+ if sit and sit.get("zone_center_x") is not None:
346
+ yield render_map(path, sit), render_calls(feed), render_stats({})
347
+ await asyncio.sleep(0.45)
348
+ yield render_map(path, sit), render_calls(feed), render_stats(o)
349
+
350
+
351
+ def _summarise(call: dict) -> str:
352
+ """The transcripts store structured results, not the text block, so
353
+ rebuild a readable line rather than dumping json at the viewer."""
354
+ r = call.get("result") or {}
355
+ bits = []
356
+ if r.get("position_x") is not None:
357
+ bits.append(f"at x={r['position_x']}, z={r['position_z']}")
358
+ if r.get("facing_yaw") is not None:
359
+ bits.append(f"facing {r['facing_yaw']}")
360
+ if r.get("distance_travelled") is not None:
361
+ bits.append(f"moved {r['distance_travelled']} units")
362
+ if r.get("degrees_off") is not None:
363
+ bits.append(f"{r['degrees_off']} off the bearing asked for")
364
+ if r.get("inside_safe_zone") is not None:
365
+ bits.append("inside the circle" if r["inside_safe_zone"] else "outside the circle")
366
+ if r.get("zone_radius") is not None:
367
+ bits.append(f"radius {r['zone_radius']}")
368
+ if r.get("seconds_remaining") is not None:
369
+ bits.append(f"{r['seconds_remaining']}s left")
370
+ return " · ".join(bits) or "(no fields)"
371
+
372
+
373
+ WATCH_INTRO = """
374
+ <div class="pr-lab">Recorded runs</div>
375
+
376
+ Episodes from real matches on a real game server. The positions and the tool responses are
377
+ what the model actually received. Pick one and it plays back a step at a time.
378
+ """
379
+
380
+ NO_REPLAYS = """
381
+ <div class="pr-board-empty"><p>No recordings published yet.</p>
382
+ <p class="pr-dim">Runs against the real game go here. The tab beside this one drives the
383
+ same tools against a stand-in, which needs no game server.</p></div>
384
+ """
385
+
386
  # ---------------------------------------------------------------- the page
387
 
388
  CSS = """
 
479
 
480
  with gr.Blocks(title="Prime Rush — a battle royale as an MCP environment") as demo:
481
  gr.HTML(HERO)
482
+ _reps = _replays()
483
+ with gr.Tab("Watch a model play"):
484
+ gr.Markdown(WATCH_INTRO)
485
+ if _reps:
486
+ with gr.Row():
487
+ with gr.Column(scale=3):
488
+ rmap = gr.HTML(render_map([], None))
489
+ rstats = gr.HTML(render_stats(None))
490
+ with gr.Row():
491
+ pick = gr.Dropdown(list(_reps), value=list(_reps)[0],
492
+ label="Episode", scale=3)
493
+ rgo = gr.Button("Play", variant="primary", scale=0)
494
+ with gr.Column(scale=2):
495
+ gr.HTML('<div class="pr-lab">What the model called</div>')
496
+ rfeed = gr.HTML(render_calls([]))
497
+ rgo.click(play_replay, inputs=[pick], outputs=[rmap, rfeed, rstats])
498
+ else:
499
+ gr.HTML(NO_REPLAYS)
500
+ with gr.Tab("Try the tools"):
501
  with gr.Row():
502
  with gr.Column(scale=3):
503
  gr.HTML('<div class="pr-lab">The match</div>')
replays/claude-opus-5-5-2000.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"seed": 2000, "model": "claude-opus-5-5", "ok": true, "error": null, "fake": false, "pod": "mcpdemo-145034-4191", "boot_s": 25.6, "fingerprint_before": "{'ok': True, 'tick': 165, 'present': True, 'players': 4, 'hash': 'd4be0e60f2835bdc'}", "outcome": {"task": "zone_survival", "finished": true, "finish_reason": "the time budget for this task is used up", "frac_inside_zone": 1.0, "seconds_scored": 100.0, "seconds_budget": 100.0, "tool_calls_that_advanced_time": 20, "alive": true, "health": 1.0, "players_alive": 6, "player_rank": 0, "kills": 0, "damage_dealt": 0, "damage_taken": 0, "wall_clock_seconds": 117.7}, "turns": 19, "tool_calls": 19, "stopped": "the time budget for this task is used up", "calls": [{"tool": "get_situation", "input": {}, "think_s": 50.25, "result": {"position_x": 659.2, "position_z": 831.5, "facing_yaw": 0.0, "health": 1.0, "alive": true, "moving_speed": 0.0, "zone_center_x": 661.5, "zone_center_z": 673.6, "zone_radius": 333.6, "next_zone_center_x": 644.8, "next_zone_center_z": 648.5, "next_zone_radius": 300.0, "inside_safe_zone": true, "zone_round": 3, "seconds_used": 0.0, "seconds_remaining": 100.0, "enemies": [{"distance": 195.3, "offset_x": -2.7, "offset_z": -190.9, "alive": true}, {"distance": 240.5, "offset_x": 127.3, "offset_z": -201.4, "alive": true}], "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 205}, "think_s": 0.75, "result": {"facing_yaw": 205.1, "requested_bearing": 205.0, "degrees_off": 0.1, "seconds_used": 3.0, "seconds_remaining": 97.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 12}, "think_s": 1.55, "result": {"position_x": 659.0, "position_z": 831.4, "distance_travelled": 0.2, "inside_safe_zone": true, "health": 1.0, "seconds_used": 12.0, "seconds_remaining": 85.0, "status": "running"}}, {"tool": "get_situation", "input": {}, "think_s": 0.0, "result": {"position_x": 659.0, "position_z": 831.4, "facing_yaw": 205.1, "health": 1.0, "alive": true, "moving_speed": 1.02, "zone_center_x": 644.8, "zone_center_z": 648.5, "zone_radius": 300.0, "next_zone_center_x": 740.4, "next_zone_center_z": 732.7, "next_zone_radius": 150.0, "inside_safe_zone": true, "zone_round": 4, "seconds_used": 15.0, "seconds_remaining": 85.0, "enemies": [{"distance": 194.8, "offset_x": -10.2, "offset_z": -190.1, "alive": true}, {"distance": 254.4, "offset_x": 125.3, "offset_z": -218.0, "alive": true}], "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 140}, "think_s": 0.49, "result": {"facing_yaw": 140.0, "requested_bearing": 140.0, "degrees_off": 0.0, "seconds_used": 2.0, "seconds_remaining": 83.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 10}, "think_s": 1.14, "result": {"position_x": 667.5, "position_z": 831.2, "distance_travelled": 8.5, "inside_safe_zone": true, "health": 1.0, "seconds_used": 10.0, "seconds_remaining": 73.0, "status": "running"}}, {"tool": "get_situation", "input": {}, "think_s": 0.0, "result": {"position_x": 667.5, "position_z": 831.2, "facing_yaw": 140.0, "health": 1.0, "alive": true, "moving_speed": 0.01, "zone_center_x": 644.8, "zone_center_z": 648.5, "zone_radius": 300.0, "next_zone_center_x": 740.4, "next_zone_center_z": 732.7, "next_zone_radius": 150.0, "inside_safe_zone": true, "zone_round": 4, "seconds_used": 27.0, "seconds_remaining": 73.0, "enemies": [{"distance": 193.0, "offset_x": -7.4, "offset_z": -188.4, "alive": true}, {"distance": 259.7, "offset_x": 118.1, "offset_z": -227.8, "alive": true}], "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 90}, "think_s": 0.26, "result": {"facing_yaw": 90.1, "requested_bearing": 90.0, "degrees_off": 0.1, "seconds_used": 1.0, "seconds_remaining": 72.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 6}, "think_s": 0.83, "result": {"position_x": 667.5, "position_z": 831.6, "distance_travelled": 0.2, "inside_safe_zone": true, "health": 1.0, "seconds_used": 6.0, "seconds_remaining": 66.0, "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 45}, "think_s": 0.22, "result": {"facing_yaw": 45.1, "requested_bearing": 45.0, "degrees_off": 0.1, "seconds_used": 1.0, "seconds_remaining": 65.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 6}, "think_s": 0.93, "result": {"position_x": 667.5, "position_z": 840.0, "distance_travelled": 8.5, "inside_safe_zone": true, "health": 1.0, "seconds_used": 6.0, "seconds_remaining": 59.0, "status": "running"}}, {"tool": "get_situation", "input": {}, "think_s": 0.0, "result": {"position_x": 667.5, "position_z": 840.0, "facing_yaw": 45.1, "health": 1.0, "alive": true, "moving_speed": 0.0, "zone_center_x": 644.8, "zone_center_z": 648.5, "zone_radius": 300.0, "next_zone_center_x": 740.4, "next_zone_center_z": 732.7, "next_zone_radius": 150.0, "inside_safe_zone": true, "zone_round": 4, "seconds_used": 41.0, "seconds_remaining": 59.0, "enemies": [{"distance": 208.7, "offset_x": -18.5, "offset_z": -203.8, "alive": true}, {"distance": 255.6, "offset_x": 107.7, "offset_z": -228.2, "alive": true}], "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 270}, "think_s": 0.8, "result": {"facing_yaw": 270.1, "requested_bearing": 270.0, "degrees_off": 0.1, "seconds_used": 3.0, "seconds_remaining": 56.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 8}, "think_s": 0.98, "result": {"position_x": 664.1, "position_z": 839.7, "distance_travelled": 3.4, "inside_safe_zone": true, "health": 1.0, "seconds_used": 8.0, "seconds_remaining": 48.0, "status": "running"}}, {"tool": "turn_to_bearing", "input": {"bearing": 180}, "think_s": 0.56, "result": {"facing_yaw": 180.1, "requested_bearing": 180.0, "degrees_off": 0.1, "seconds_used": 2.0, "seconds_remaining": 46.0, "inside_safe_zone": true, "status": "running"}}, {"tool": "move", "input": {"forward": 1.0, "run": true, "seconds": 10}, "think_s": 1.2, "result": {"position_x": 664.7, "position_z": 831.4, "distance_travelled": 8.3, "inside_safe_zone": true, "health": 1.0, "seconds_used": 10.0, "seconds_remaining": 36.0, "status": "running"}}, {"tool": "get_situation", "input": {}, "think_s": 0.0, "result": {"position_x": 664.7, "position_z": 831.4, "facing_yaw": 180.1, "health": 1.0, "alive": true, "moving_speed": 0.0, "zone_center_x": 659.0, "zone_center_z": 661.0, "zone_radius": 277.7, "next_zone_center_x": 740.4, "next_zone_center_z": 732.7, "next_zone_radius": 150.0, "inside_safe_zone": true, "zone_round": 4, "seconds_used": 64.0, "seconds_remaining": 36.0, "enemies": [{"distance": 199.3, "offset_x": -5.2, "offset_z": -194.9, "alive": true}, {"distance": 225.8, "offset_x": 116.4, "offset_z": -191.6, "alive": true}], "status": "running"}}, {"tool": "hold_position", "input": {"seconds": 20, "crouch": true}, "think_s": 2.12, "result": {"inside_safe_zone": true, "health": 1.0, "zone_radius": 227.7, "seconds_used": 20.0, "seconds_remaining": 16.0, "status": "running"}}, {"tool": "hold_position", "input": {"seconds": 16, "crouch": true}, "think_s": 1.92, "result": {"inside_safe_zone": true, "health": 1.0, "zone_radius": 187.7, "seconds_used": 16.0, "seconds_remaining": 0.0, "status": "finished"}}], "fingerprint_after": "{'ok': True, 'tick': 6765, 'present': True, 'players': 6, 'hash': 'a0c7881567103b6f'}"}
results/summary.json ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "generated": "2026-11-11 21:36",
3
+ "build": "1.15.0_99000014",
4
+ "task": "zone_survival",
5
+ "task_version": "ff400-next0-win400",
6
+ "scoring": "frac_inside_zone",
7
+ "zones": [
8
+ 2000,
9
+ 2029
10
+ ],
11
+ "ceiling": null,
12
+ "note": "Build 1.15.0_99000014, zones 2000-2029, task ff400-next0-win400. Score is the share of the scored window spent inside the circle the storm is closing to.",
13
+ "rows": [
14
+ {
15
+ "model": "reference:random",
16
+ "reference": true,
17
+ "score": 0.1959,
18
+ "median": 0.1125,
19
+ "reached": "4/30",
20
+ "scored": 30
21
+ },
22
+ {
23
+ "model": "reference:hand-written",
24
+ "reference": true,
25
+ "score": 0.6537,
26
+ "median": 0.765,
27
+ "reached": "22/30",
28
+ "scored": 30
29
+ },
30
+ {
31
+ "model": "anthropic:claude-opus-5-5",
32
+ "score": 0.7697,
33
+ "median": 0.8275,
34
+ "ci95": [
35
+ 0.6861,
36
+ 0.8411
37
+ ],
38
+ "reached": "26/30",
39
+ "tool_calls_mean": 28.8,
40
+ "scored": 30
41
+ },
42
+ {
43
+ "model": "anthropic:claude-sonnet-5-5",
44
+ "score": 0.6791,
45
+ "median": 0.8155,
46
+ "ci95": [
47
+ 0.5647,
48
+ 0.784
49
+ ],
50
+ "reached": "24/30",
51
+ "tool_calls_mean": 36.3,
52
+ "scored": 30
53
+ },
54
+ {
55
+ "model": "hf:Qwen/Qwen3.6-35B-A3B",
56
+ "score": 0.4998,
57
+ "median": 0.5554,
58
+ "ci95": [
59
+ 0.3841,
60
+ 0.6173
61
+ ],
62
+ "reached": "18/30",
63
+ "tool_calls_mean": 23.9,
64
+ "scored": 30
65
+ },
66
+ {
67
+ "model": "hf:deepseek-ai/DeepSeek-V4-Flash",
68
+ "score": 0.6521,
69
+ "median": 0.7159,
70
+ "ci95": [
71
+ 0.5376,
72
+ 0.7637
73
+ ],
74
+ "reached": "22/30",
75
+ "tool_calls_mean": 29.7,
76
+ "scored": 30
77
+ }
78
+ ]
79
+ }
rpreview.html ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><meta charset=utf-8><style>
2
+ .gradio-container { max-width: 1120px !important; }
3
+ #pr-hero { border-bottom: 1px solid var(--border-color-primary); padding-bottom: 18px; }
4
+ #pr-hero h1 { font-size: 30px; line-height: 1.15; margin: 0 0 6px; letter-spacing: -.02em; font-weight: 700; }
5
+ #pr-hero .pr-sub { font-size: 15px; color: var(--body-text-color-subdued); max-width: 64ch; margin: 0 0 14px; }
6
+ #pr-hero .pr-chips { display: flex; flex-wrap: wrap; gap: 8px; }
7
+ #pr-hero .pr-chip { font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
8
+ border: 1px solid var(--border-color-primary); border-radius: 999px; padding: 4px 11px;
9
+ color: var(--body-text-color-subdued); }
10
+ #pr-hero .pr-chip.on { border-color: #2a78d6; color: #2a78d6; font-weight: 600; }
11
+ .pr-lab { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700;
12
+ color: #9a7400; margin: 4px 0 8px; }
13
+ .pr-map svg { width: 100%; height: auto; border: 1px solid var(--border-color-primary);
14
+ border-radius: 12px; display: block; }
15
+ .pr-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 12px; }
16
+ .pr-tile { border: 1px solid var(--border-color-primary); border-radius: 10px; padding: 9px 11px; }
17
+ .pr-tile .k { display: block; font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
18
+ color: var(--body-text-color-subdued); }
19
+ .pr-tile .v { display: block; font-size: 19px; font-variant-numeric: tabular-nums; margin-top: 2px; }
20
+ .pr-feed { height: 522px; overflow-y: auto; border: 1px solid var(--border-color-primary);
21
+ border-radius: 12px; padding: 12px; }
22
+ .pr-call { border-left: 2px solid #2a78d6; padding: 6px 0 6px 10px; margin-bottom: 9px; }
23
+ .pr-call.pr-free { border-left-color: var(--border-color-primary); }
24
+ .pr-name { font-family: ui-monospace, monospace; font-size: 12.5px; font-weight: 600; }
25
+ .pr-args { font-weight: 400; color: var(--body-text-color-subdued); }
26
+ .pr-out { font-size: 12.5px; color: var(--body-text-color-subdued); white-space: pre-wrap;
27
+ margin-top: 3px; line-height: 1.45; }
28
+ .pr-dim { color: var(--body-text-color-subdued); font-size: 13px; }
29
+ table.pr-board { width: 100%; border-collapse: collapse; font-size: 14px; }
30
+ table.pr-board th { text-align: left; font-size: 10.5px; letter-spacing: .08em;
31
+ text-transform: uppercase; color: var(--body-text-color-subdued); font-weight: 700;
32
+ border-bottom: 1px solid var(--border-color-primary); padding: 6px 8px 6px 0; }
33
+ table.pr-board td { padding: 7px 8px 7px 0; border-bottom: 1px solid var(--border-color-primary);
34
+ font-variant-numeric: tabular-nums; }
35
+ table.pr-board .r { text-align: right; }
36
+ table.pr-board tr.pr-ref td { color: var(--body-text-color-subdued); }
37
+ .pr-board-empty { border: 1px solid var(--border-color-primary); border-radius: 12px;
38
+ padding: 18px; max-width: 60ch; }
39
+ .pr-board-empty p { margin: 0 0 8px; }
40
+ #pr-foot { border-top: 1px solid var(--border-color-primary); margin-top: 24px; padding-top: 14px;
41
+ font-size: 13px; color: var(--body-text-color-subdued); }
42
+
43
+ body{font-family:ui-sans-serif,system-ui;margin:0;padding:24px;background:#fff;color:#15161a;
44
+ --border-color-primary:#e4e2dd;--body-text-color-subdued:#6a6d75}
45
+ .wrap{max-width:1120px;margin:0 auto}.cols{display:grid;grid-template-columns:3fr 2fr;gap:22px}
46
+ </style><body><div class=wrap>
47
+ <div class="pr-lab">Recorded runs</div>
48
+ <p style="color:#6a6d75;font-size:14px;max-width:70ch;margin:0 0 14px">Episodes from real matches on a real game server. Pick one and it plays back a step at a time.</p>
49
+ <div class=cols><div><div class="pr-map"><svg viewBox="0 0 420 420" role="img"
50
+ aria-label="top-down view of the agent and the safe circle">
51
+ <defs><mask id="outside">
52
+ <rect width="420" height="420" fill="white"/>
53
+ <circle cx="210.0" cy="210.0" r="173.1" fill="black"/>
54
+ </mask></defs>
55
+ <rect width="420" height="420" fill="#ffffff"/>
56
+ <g stroke="#e8e6e1" stroke-width="1"><line x1="70" y1="0" x2="70" y2="420"/><line x1="0" y1="70" x2="420" y2="70"/><line x1="140" y1="0" x2="140" y2="420"/><line x1="0" y1="140" x2="420" y2="140"/><line x1="210" y1="0" x2="210" y2="420"/><line x1="0" y1="210" x2="420" y2="210"/><line x1="280" y1="0" x2="280" y2="420"/><line x1="0" y1="280" x2="420" y2="280"/><line x1="350" y1="0" x2="350" y2="420"/><line x1="0" y1="350" x2="420" y2="350"/></g>
57
+ <rect width="420" height="420" fill="#eb6834" opacity=".07" mask="url(#outside)"/>
58
+ <circle cx="285.1" cy="143.9" r="138.3"
59
+ fill="none" stroke="#8a8d94" stroke-width="1.2" stroke-dasharray="4 4"/>
60
+ <circle cx="210.0" cy="210.0" r="173.1"
61
+ fill="#2a78d6" fill-opacity=".05" stroke="#eb6834" stroke-width="2"/>
62
+ <circle cx="210.0" cy="210.0" r="3" fill="#eb6834"/>
63
+ <polyline points="210.2,52.8 210.0,52.8 210.0,52.8 217.8,53.0 217.8,53.0 217.8,52.7 217.8,44.9 217.8,44.9 214.7,45.2 215.3,52.8 215.3,52.8" fill="none" stroke="#2a78d6" stroke-width="2"
64
+ stroke-linejoin="round" stroke-linecap="round" opacity=".5"/>
65
+ <circle cx="215.3" cy="52.8" r="6"
66
+ fill="#2a78d6" stroke="#ffffff" stroke-width="2.5"/>
67
+ <g font-family="ui-sans-serif,system-ui" font-size="10" fill="#8a8d94">
68
+ <line x1="14" y1="404" x2="106" y2="404" stroke="#8a8d94" stroke-width="1.5"/>
69
+ <line x1="14" y1="400" x2="14" y2="408" stroke="#8a8d94" stroke-width="1.5"/>
70
+ <line x1="106" y1="400" x2="106" y2="408" stroke="#8a8d94" stroke-width="1.5"/>
71
+ <text x="14" y="396">100 units</text>
72
+ <text x="406" y="20" text-anchor="end">+z &#8593;</text>
73
+ </g>
74
+ <g font-family="ui-sans-serif,system-ui" font-size="11">
75
+ <text x="14" y="22" fill="#15161a" font-weight="600">INSIDE the circle</text>
76
+ <text x="14" y="38" fill="#8a8d94">radius 188 &#183; 0s left &#183; health 100%</text>
77
+ </g>
78
+ </svg></div><div class="pr-tiles"><div class="pr-tile"><span class="k">inside the circle</span><span class="v">100%</span></div><div class="pr-tile"><span class="k">game time scored</span><span class="v">100s</span></div><div class="pr-tile"><span class="k">decisions</span><span class="v">20</span></div><div class="pr-tile"><span class="k">status</span><span class="v">alive</span></div></div></div><div><div class="pr-lab">What the model called</div><div class="pr-feed"><div class="pr-call pr-free"><div class="pr-name">get_situation<span class="pr-args">()</span></div><div class="pr-out">at x=659.0, z=831.4 · facing 205.1 · inside the circle · radius 300.0 · 85.0s left</div></div><div class="pr-call"><div class="pr-name">turn_to_bearing<span class="pr-args">(bearing=140)</span></div><div class="pr-out">facing 140.0 · 0.0 off the bearing asked for · inside the circle · 83.0s left</div></div><div class="pr-call"><div class="pr-name">move<span class="pr-args">(forward=1.0, run=True, seconds=10)</span></div><div class="pr-out">at x=667.5, z=831.2 · moved 8.5 units · inside the circle · 73.0s left</div></div><div class="pr-call pr-free"><div class="pr-name">get_situation<span class="pr-args">()</span></div><div class="pr-out">at x=667.5, z=831.2 · facing 140.0 · inside the circle · radius 300.0 · 73.0s left</div></div><div class="pr-call"><div class="pr-name">turn_to_bearing<span class="pr-args">(bearing=90)</span></div><div class="pr-out">facing 90.1 · 0.1 off the bearing asked for · inside the circle · 72.0s left</div></div><div class="pr-call"><div class="pr-name">move<span class="pr-args">(forward=1.0, run=True, seconds=6)</span></div><div class="pr-out">at x=667.5, z=831.6 · moved 0.2 units · inside the circle · 66.0s left</div></div><div class="pr-call"><div class="pr-name">turn_to_bearing<span class="pr-args">(bearing=45)</span></div><div class="pr-out">facing 45.1 · 0.1 off the bearing asked for · inside the circle · 65.0s left</div></div><div class="pr-call"><div class="pr-name">move<span class="pr-args">(forward=1.0, run=True, seconds=6)</span></div><div class="pr-out">at x=667.5, z=840.0 · moved 8.5 units · inside the circle · 59.0s left</div></div><div class="pr-call pr-free"><div class="pr-name">get_situation<span class="pr-args">()</span></div><div class="pr-out">at x=667.5, z=840.0 · facing 45.1 · inside the circle · radius 300.0 · 59.0s left</div></div><div class="pr-call"><div class="pr-name">turn_to_bearing<span class="pr-args">(bearing=270)</span></div><div class="pr-out">facing 270.1 · 0.1 off the bearing asked for · inside the circle · 56.0s left</div></div><div class="pr-call"><div class="pr-name">move<span class="pr-args">(forward=1.0, run=True, seconds=8)</span></div><div class="pr-out">at x=664.1, z=839.7 · moved 3.4 units · inside the circle · 48.0s left</div></div><div class="pr-call"><div class="pr-name">turn_to_bearing<span class="pr-args">(bearing=180)</span></div><div class="pr-out">facing 180.1 · 0.1 off the bearing asked for · inside the circle · 46.0s left</div></div><div class="pr-call"><div class="pr-name">move<span class="pr-args">(forward=1.0, run=True, seconds=10)</span></div><div class="pr-out">at x=664.7, z=831.4 · moved 8.3 units · inside the circle · 36.0s left</div></div><div class="pr-call pr-free"><div class="pr-name">get_situation<span class="pr-args">()</span></div><div class="pr-out">at x=664.7, z=831.4 · facing 180.1 · inside the circle · radius 277.7 · 36.0s left</div></div><div class="pr-call"><div class="pr-name">hold_position<span class="pr-args">(seconds=20, crouch=True)</span></div><div class="pr-out">inside the circle · radius 227.7 · 16.0s left</div></div><div class="pr-call"><div class="pr-name">hold_position<span class="pr-args">(seconds=16, crouch=True)</span></div><div class="pr-out">inside the circle · radius 187.7 · 0.0s left</div></div></div></div></div>
79
+ </div></body>