Spaces:
Sleeping
Sleeping
Phase 2: Play tab — larger minimap + bigger coordinate labels
Browse filesFrom play-testing feedback: the minimap was too small and the grid
coordinate numbers too small to read.
- Minimap moved to its own full-width row (was sharing a row at half
width with the briefing) and the gr.Image height raised 420 -> 620.
- Upscale raised 3x -> 5x (_PLAY_UPSCALE) for a crisp large display.
- Coordinate labels now use a real 34px TrueType font with a 3px
black outline (bright yellow fill) instead of PIL's tiny default
bitmap font — readable over any terrain.
- Click-to-cell math and grid spacing track _PLAY_UPSCALE.
app.py
CHANGED
|
@@ -1033,6 +1033,29 @@ Then run `evaluate.py --agent custom` with your agent integrated.
|
|
| 1033 |
# human's run is scored by the identical rules as a model's.
|
| 1034 |
|
| 1035 |
_PLAY_LEVELS = ["easy", "medium", "hard"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1036 |
|
| 1037 |
|
| 1038 |
def _play_scenarios() -> list[str]:
|
|
@@ -1065,10 +1088,11 @@ def _md_escape(text: str) -> str:
|
|
| 1065 |
|
| 1066 |
|
| 1067 |
def _play_minimap(render_state: dict):
|
| 1068 |
-
"""PIL minimap image — the same view an LLM agent is shown,
|
| 1069 |
-
|
| 1070 |
-
with a coordinate grid + axis labels every
|
| 1071 |
-
|
|
|
|
| 1072 |
try:
|
| 1073 |
import base64
|
| 1074 |
import io
|
|
@@ -1082,27 +1106,35 @@ def _play_minimap(render_state: dict):
|
|
| 1082 |
return None
|
| 1083 |
img = Image.open(io.BytesIO(base64.b64decode(b64))).convert("RGB")
|
| 1084 |
bw, bh = img.size
|
| 1085 |
-
|
|
|
|
| 1086 |
iw, ih = img.size
|
| 1087 |
-
cell_px =
|
| 1088 |
rows = [r for r in (render_state.get("minimap") or "").split("\n")
|
| 1089 |
if r]
|
| 1090 |
cols = max((len(r) for r in rows), default=bw // 6)
|
| 1091 |
nrows = len(rows) or bh // 6
|
| 1092 |
draw = ImageDraw.Draw(img)
|
| 1093 |
-
grid = (
|
| 1094 |
-
label = (
|
|
|
|
| 1095 |
step = 10
|
| 1096 |
for cx in range(0, cols + 1, step):
|
| 1097 |
x = min(iw - 1, cx * cell_px)
|
| 1098 |
-
draw.line([(x, 0), (x, ih)], fill=grid, width=
|
| 1099 |
if cx < cols:
|
| 1100 |
-
draw.text(
|
|
|
|
|
|
|
|
|
|
| 1101 |
for cy in range(0, nrows + 1, step):
|
| 1102 |
y = min(ih - 1, cy * cell_px)
|
| 1103 |
-
draw.line([(0, y), (iw, y)], fill=grid, width=
|
| 1104 |
if cy < nrows:
|
| 1105 |
-
draw.text(
|
|
|
|
|
|
|
|
|
|
| 1106 |
return img
|
| 1107 |
except Exception: # noqa: BLE001
|
| 1108 |
return None
|
|
@@ -1244,10 +1276,10 @@ def _play_click(sess, sel, queue, mode, evt: gr.SelectData):
|
|
| 1244 |
)
|
| 1245 |
h = len(rows)
|
| 1246 |
w = max(len(r) for r in rows)
|
| 1247 |
-
# _play_minimap renders at CELL(6) and upscales
|
| 1248 |
-
# the
|
| 1249 |
-
|
| 1250 |
-
|
| 1251 |
cx, cy = minimap_click_to_cell(px, py, img_w, img_h, w, h)
|
| 1252 |
note = f"🖱 Clicked cell **({cx}, {cy})**"
|
| 1253 |
if mode == "Move here" and sel:
|
|
@@ -1513,12 +1545,12 @@ def build_app() -> gr.Blocks:
|
|
| 1513 |
play_start = gr.Button("▶ Start", scale=1)
|
| 1514 |
play_objective = gr.Markdown()
|
| 1515 |
play_status = gr.Markdown(_play_status_md(None))
|
| 1516 |
-
|
| 1517 |
-
|
| 1518 |
-
|
| 1519 |
-
|
| 1520 |
-
|
| 1521 |
-
|
| 1522 |
play_units = gr.Dataframe(
|
| 1523 |
label="Your units (✓ = selected)",
|
| 1524 |
headers=["sel", "id", "type", "x", "y", "hp%",
|
|
|
|
| 1033 |
# human's run is scored by the identical rules as a model's.
|
| 1034 |
|
| 1035 |
_PLAY_LEVELS = ["easy", "medium", "hard"]
|
| 1036 |
+
_PLAY_UPSCALE = 5 # nearest-neighbour minimap upscale for the Play tab
|
| 1037 |
+
|
| 1038 |
+
|
| 1039 |
+
def _play_grid_font(size: int):
|
| 1040 |
+
"""A large legible font for the minimap coordinate labels — tries
|
| 1041 |
+
real TrueType fonts, falls back to a scaled default."""
|
| 1042 |
+
from PIL import ImageFont
|
| 1043 |
+
|
| 1044 |
+
for path in (
|
| 1045 |
+
"/System/Library/Fonts/Supplemental/Arial Bold.ttf",
|
| 1046 |
+
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
| 1047 |
+
"/System/Library/Fonts/Helvetica.ttc",
|
| 1048 |
+
"/Library/Fonts/Arial.ttf",
|
| 1049 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
| 1050 |
+
):
|
| 1051 |
+
try:
|
| 1052 |
+
return ImageFont.truetype(path, size)
|
| 1053 |
+
except Exception: # noqa: BLE001
|
| 1054 |
+
continue
|
| 1055 |
+
try:
|
| 1056 |
+
return ImageFont.load_default(size=size) # Pillow >= 10.1
|
| 1057 |
+
except Exception: # noqa: BLE001
|
| 1058 |
+
return ImageFont.load_default()
|
| 1059 |
|
| 1060 |
|
| 1061 |
def _play_scenarios() -> list[str]:
|
|
|
|
| 1088 |
|
| 1089 |
|
| 1090 |
def _play_minimap(render_state: dict):
|
| 1091 |
+
"""PIL minimap image — the same view an LLM agent is shown, upscaled
|
| 1092 |
+
`_PLAY_UPSCALE`x (nearest-neighbour) so individual units stay
|
| 1093 |
+
distinct, with a coordinate grid + large outlined axis labels every
|
| 1094 |
+
10 cells so a human can read off the cell coordinates the objective
|
| 1095 |
+
refers to."""
|
| 1096 |
try:
|
| 1097 |
import base64
|
| 1098 |
import io
|
|
|
|
| 1106 |
return None
|
| 1107 |
img = Image.open(io.BytesIO(base64.b64decode(b64))).convert("RGB")
|
| 1108 |
bw, bh = img.size
|
| 1109 |
+
scale = _PLAY_UPSCALE
|
| 1110 |
+
img = img.resize((bw * scale, bh * scale), Image.NEAREST)
|
| 1111 |
iw, ih = img.size
|
| 1112 |
+
cell_px = 6 * scale # minimap CELL(6) * upscale
|
| 1113 |
rows = [r for r in (render_state.get("minimap") or "").split("\n")
|
| 1114 |
if r]
|
| 1115 |
cols = max((len(r) for r in rows), default=bw // 6)
|
| 1116 |
nrows = len(rows) or bh // 6
|
| 1117 |
draw = ImageDraw.Draw(img)
|
| 1118 |
+
grid = (120, 123, 135)
|
| 1119 |
+
label = (255, 246, 120) # bright yellow, readable over terrain
|
| 1120 |
+
font = _play_grid_font(34)
|
| 1121 |
step = 10
|
| 1122 |
for cx in range(0, cols + 1, step):
|
| 1123 |
x = min(iw - 1, cx * cell_px)
|
| 1124 |
+
draw.line([(x, 0), (x, ih)], fill=grid, width=2)
|
| 1125 |
if cx < cols:
|
| 1126 |
+
draw.text(
|
| 1127 |
+
(x + 4, 2), str(cx), fill=label, font=font,
|
| 1128 |
+
stroke_width=3, stroke_fill=(0, 0, 0),
|
| 1129 |
+
)
|
| 1130 |
for cy in range(0, nrows + 1, step):
|
| 1131 |
y = min(ih - 1, cy * cell_px)
|
| 1132 |
+
draw.line([(0, y), (iw, y)], fill=grid, width=2)
|
| 1133 |
if cy < nrows:
|
| 1134 |
+
draw.text(
|
| 1135 |
+
(4, y + 2), str(cy), fill=label, font=font,
|
| 1136 |
+
stroke_width=3, stroke_fill=(0, 0, 0),
|
| 1137 |
+
)
|
| 1138 |
return img
|
| 1139 |
except Exception: # noqa: BLE001
|
| 1140 |
return None
|
|
|
|
| 1276 |
)
|
| 1277 |
h = len(rows)
|
| 1278 |
w = max(len(r) for r in rows)
|
| 1279 |
+
# _play_minimap renders at CELL(6) and upscales _PLAY_UPSCALE x →
|
| 1280 |
+
# map the click back at that resolution, not the base CELL one.
|
| 1281 |
+
img_w = w * 6 * _PLAY_UPSCALE
|
| 1282 |
+
img_h = h * 6 * _PLAY_UPSCALE
|
| 1283 |
cx, cy = minimap_click_to_cell(px, py, img_w, img_h, w, h)
|
| 1284 |
note = f"🖱 Clicked cell **({cx}, {cy})**"
|
| 1285 |
if mode == "Move here" and sel:
|
|
|
|
| 1545 |
play_start = gr.Button("▶ Start", scale=1)
|
| 1546 |
play_objective = gr.Markdown()
|
| 1547 |
play_status = gr.Markdown(_play_status_md(None))
|
| 1548 |
+
# Minimap on its own full-width row so it renders large.
|
| 1549 |
+
play_img = gr.Image(
|
| 1550 |
+
label="Minimap — click to select units / give orders",
|
| 1551 |
+
height=620, interactive=False, show_label=True,
|
| 1552 |
+
)
|
| 1553 |
+
play_brief = gr.Markdown()
|
| 1554 |
play_units = gr.Dataframe(
|
| 1555 |
label="Your units (✓ = selected)",
|
| 1556 |
headers=["sel", "id", "type", "x", "y", "hp%",
|