Spaces:
Running
Running
Phase 2: Play tab — fix hp, reorder panel, cleaner units table
Browse filesFrom play-testing feedback:
- hp showed '1.0': the engine reports hp as a 0-1 fraction, not a
percent. Now displayed as '100%'.
- Turn briefing reordered: 'Selected units' + 'Queued this turn' now
come FIRST, then the turn briefing (the exact text the model sees).
- Units table made readable: columns sel/unit/type/cell/hp/status
(x,y merged into one 'cell' column), selected units marked '▶' and
sorted to the top so the current selection is unmistakable.
- app.py +37 -22
- tests/test_app.py +5 -4
app.py
CHANGED
|
@@ -1089,34 +1089,47 @@ def _play_objective_md(sess) -> str:
|
|
| 1089 |
return f"### 🎯 Objective\n{_md_escape(obj)}"
|
| 1090 |
|
| 1091 |
|
|
|
|
|
|
|
|
|
|
| 1092 |
def _play_units_df(sess, sel):
|
| 1093 |
-
"""Table of the human's own units
|
| 1094 |
-
|
| 1095 |
-
|
| 1096 |
-
cols = ["sel", "id", "type", "x", "y", "hp%", "activity"]
|
| 1097 |
if sess is None:
|
| 1098 |
-
return pd.DataFrame(columns=
|
| 1099 |
try:
|
| 1100 |
rs = sess.render_state()
|
| 1101 |
except Exception: # noqa: BLE001
|
| 1102 |
-
return pd.DataFrame(columns=
|
| 1103 |
selset = {str(s) for s in (sel or [])}
|
| 1104 |
rows = []
|
| 1105 |
for u in rs.get("units_summary", []) or []:
|
| 1106 |
if not isinstance(u, dict):
|
| 1107 |
continue
|
| 1108 |
uid = str(u.get("id", ""))
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
u.get("
|
| 1118 |
-
|
| 1119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1120 |
|
| 1121 |
|
| 1122 |
def _play_status_md(sess) -> str:
|
|
@@ -1130,6 +1143,8 @@ def _play_status_md(sess) -> str:
|
|
| 1130 |
|
| 1131 |
|
| 1132 |
def _play_briefing_md(sess, sel, queue, note: str = "") -> str:
|
|
|
|
|
|
|
| 1133 |
if sess is None:
|
| 1134 |
return ""
|
| 1135 |
try:
|
|
@@ -1143,9 +1158,10 @@ def _play_briefing_md(sess, sel, queue, note: str = "") -> str:
|
|
| 1143 |
head = f"{note}\n\n" if note else ""
|
| 1144 |
return (
|
| 1145 |
f"{head}"
|
| 1146 |
-
f"```\n{brief}\n```\n\n"
|
| 1147 |
f"**Selected units:** {sel_txt} \n"
|
| 1148 |
-
f"**Queued this turn:** {q_txt}"
|
|
|
|
|
|
|
| 1149 |
)
|
| 1150 |
|
| 1151 |
|
|
@@ -1491,9 +1507,8 @@ def build_app() -> gr.Blocks:
|
|
| 1491 |
)
|
| 1492 |
play_brief = gr.Markdown()
|
| 1493 |
play_units = gr.Dataframe(
|
| 1494 |
-
label="Your units (
|
| 1495 |
-
headers=
|
| 1496 |
-
"activity"],
|
| 1497 |
interactive=False, wrap=True,
|
| 1498 |
)
|
| 1499 |
with gr.Row():
|
|
|
|
| 1089 |
return f"### 🎯 Objective\n{_md_escape(obj)}"
|
| 1090 |
|
| 1091 |
|
| 1092 |
+
_PLAY_UNIT_COLS = ["sel", "unit", "type", "cell", "hp", "status"]
|
| 1093 |
+
|
| 1094 |
+
|
| 1095 |
def _play_units_df(sess, sel):
|
| 1096 |
+
"""Table of the human's own units. Selected units are marked '▶' and
|
| 1097 |
+
sorted to the top so the current selection is obvious. `hp` is the
|
| 1098 |
+
0-1 fraction the engine reports, shown as a percentage."""
|
|
|
|
| 1099 |
if sess is None:
|
| 1100 |
+
return pd.DataFrame(columns=_PLAY_UNIT_COLS)
|
| 1101 |
try:
|
| 1102 |
rs = sess.render_state()
|
| 1103 |
except Exception: # noqa: BLE001
|
| 1104 |
+
return pd.DataFrame(columns=_PLAY_UNIT_COLS)
|
| 1105 |
selset = {str(s) for s in (sel or [])}
|
| 1106 |
rows = []
|
| 1107 |
for u in rs.get("units_summary", []) or []:
|
| 1108 |
if not isinstance(u, dict):
|
| 1109 |
continue
|
| 1110 |
uid = str(u.get("id", ""))
|
| 1111 |
+
try:
|
| 1112 |
+
hp_txt = f"{int(round(float(u.get('hp', 1.0)) * 100))}%"
|
| 1113 |
+
except (TypeError, ValueError):
|
| 1114 |
+
hp_txt = "?"
|
| 1115 |
+
is_sel = uid in selset
|
| 1116 |
+
rows.append({
|
| 1117 |
+
"sel": "▶" if is_sel else "",
|
| 1118 |
+
"unit": uid,
|
| 1119 |
+
"type": u.get("type") or u.get("actor_type") or "?",
|
| 1120 |
+
"cell": f"({u.get('cell_x')}, {u.get('cell_y')})",
|
| 1121 |
+
"hp": hp_txt,
|
| 1122 |
+
"status": u.get("activity", "") or "idle",
|
| 1123 |
+
"_sel": is_sel,
|
| 1124 |
+
})
|
| 1125 |
+
df = pd.DataFrame(rows, columns=_PLAY_UNIT_COLS + ["_sel"])
|
| 1126 |
+
# Selected units float to the top so the selection is unmistakable.
|
| 1127 |
+
df = (
|
| 1128 |
+
df.sort_values("_sel", ascending=False, kind="stable")
|
| 1129 |
+
.drop(columns="_sel")
|
| 1130 |
+
.reset_index(drop=True)
|
| 1131 |
+
)
|
| 1132 |
+
return df
|
| 1133 |
|
| 1134 |
|
| 1135 |
def _play_status_md(sess) -> str:
|
|
|
|
| 1143 |
|
| 1144 |
|
| 1145 |
def _play_briefing_md(sess, sel, queue, note: str = "") -> str:
|
| 1146 |
+
"""The turn panel: current selection + queued orders FIRST, then the
|
| 1147 |
+
exact text briefing the model is given for this turn."""
|
| 1148 |
if sess is None:
|
| 1149 |
return ""
|
| 1150 |
try:
|
|
|
|
| 1158 |
head = f"{note}\n\n" if note else ""
|
| 1159 |
return (
|
| 1160 |
f"{head}"
|
|
|
|
| 1161 |
f"**Selected units:** {sel_txt} \n"
|
| 1162 |
+
f"**Queued this turn:** {q_txt}\n\n"
|
| 1163 |
+
f"**Turn briefing — exactly what the model sees:**\n"
|
| 1164 |
+
f"```\n{brief}\n```"
|
| 1165 |
)
|
| 1166 |
|
| 1167 |
|
|
|
|
| 1507 |
)
|
| 1508 |
play_brief = gr.Markdown()
|
| 1509 |
play_units = gr.Dataframe(
|
| 1510 |
+
label="Your units (▶ = selected, shown at top)",
|
| 1511 |
+
headers=_PLAY_UNIT_COLS,
|
|
|
|
| 1512 |
interactive=False, wrap=True,
|
| 1513 |
)
|
| 1514 |
with gr.Row():
|
tests/test_app.py
CHANGED
|
@@ -1333,10 +1333,11 @@ class TestPlayTab:
|
|
| 1333 |
assert _play_objective_md(None) == ""
|
| 1334 |
|
| 1335 |
def test_play_units_df_empty_without_session(self):
|
| 1336 |
-
from app import _play_units_df
|
| 1337 |
|
| 1338 |
df = _play_units_df(None, [])
|
| 1339 |
-
assert list(df.columns) ==
|
| 1340 |
-
"sel", "id", "type", "x", "y", "hp%", "activity"
|
| 1341 |
-
]
|
| 1342 |
assert len(df) == 0
|
|
|
|
|
|
|
|
|
|
|
|
| 1333 |
assert _play_objective_md(None) == ""
|
| 1334 |
|
| 1335 |
def test_play_units_df_empty_without_session(self):
|
| 1336 |
+
from app import _PLAY_UNIT_COLS, _play_units_df
|
| 1337 |
|
| 1338 |
df = _play_units_df(None, [])
|
| 1339 |
+
assert list(df.columns) == _PLAY_UNIT_COLS
|
|
|
|
|
|
|
| 1340 |
assert len(df) == 0
|
| 1341 |
+
assert _PLAY_UNIT_COLS == [
|
| 1342 |
+
"sel", "unit", "type", "cell", "hp", "status"
|
| 1343 |
+
]
|