yxc20098 commited on
Commit
d8da7e4
·
1 Parent(s): 7bbfa7a

Phase 2: Play tab — fix hp, reorder panel, cleaner units table

Browse files

From 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.

Files changed (2) hide show
  1. app.py +37 -22
  2. 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 id, type, cell, hp, activity —
1094
- with a on the currently-selected ones. Disambiguates units that
1095
- overlap into a single dot on the minimap."""
1096
- cols = ["sel", "id", "type", "x", "y", "hp%", "activity"]
1097
  if sess is None:
1098
- return pd.DataFrame(columns=cols)
1099
  try:
1100
  rs = sess.render_state()
1101
  except Exception: # noqa: BLE001
1102
- return pd.DataFrame(columns=cols)
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
- hp = u.get("hp", u.get("hp_pct", ""))
1110
- rows.append([
1111
- "✓" if uid in selset else "",
1112
- uid,
1113
- u.get("actor_type") or u.get("type") or "?",
1114
- u.get("cell_x"),
1115
- u.get("cell_y"),
1116
- hp,
1117
- u.get("activity", ""),
1118
- ])
1119
- return pd.DataFrame(rows, columns=cols)
 
 
 
 
 
 
 
 
 
 
 
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 ( = selected)",
1495
- headers=["sel", "id", "type", "x", "y", "hp%",
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
+ ]