Surn commited on
Commit
02e2dcd
·
1 Parent(s): def73e2

Layout Update

Browse files
Files changed (2) hide show
  1. battlewords/ui.py +83 -0
  2. pyproject.toml +1 -1
battlewords/ui.py CHANGED
@@ -10,6 +10,88 @@ from .logic import build_letter_map, reveal_cell, guess_word, is_game_over, comp
10
  from .models import Coord, GameState, Puzzle
11
 
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def _init_session() -> None:
14
  if "initialized" in st.session_state and st.session_state.initialized:
15
  return
@@ -63,6 +145,7 @@ def _render_header():
63
  "- Grid is 12×12 with 6 words (two 4-letter, two 5-letter, two 6-letter).\n"
64
  "- After each reveal, you may submit one guess.\n"
65
  "- Scoring: length + unrevealed letters of that word at guess time.")
 
66
 
67
 
68
  def _render_sidebar():
 
10
  from .models import Coord, GameState, Puzzle
11
 
12
 
13
+ CoordLike = Tuple[int, int]
14
+
15
+
16
+ def _coord_to_xy(c) -> CoordLike:
17
+ # Supports dataclass Coord(x, y) or a 2-tuple/list.
18
+ if hasattr(c, "x") and hasattr(c, "y"):
19
+ return int(c.x), int(c.y)
20
+ if isinstance(c, (tuple, list)) and len(c) == 2:
21
+ return int(c[0]), int(c[1])
22
+ raise TypeError(f"Unsupported Coord type: {type(c)!r}")
23
+
24
+
25
+ def _normalize_revealed(revealed: Iterable) -> set[CoordLike]:
26
+ return {(_coord_to_xy(c) if not (isinstance(c, tuple) and len(c) == 2 and isinstance(c[0], int)) else c) for c in revealed}
27
+
28
+
29
+ def _build_letter_map(puzzle) -> dict[CoordLike, str]:
30
+ letters: dict[CoordLike, str] = {}
31
+ for w in getattr(puzzle, "words", []):
32
+ text = getattr(w, "text", "")
33
+ cells = getattr(w, "cells", [])
34
+ for i, c in enumerate(cells):
35
+ xy = _coord_to_xy(c)
36
+ if 0 <= i < len(text):
37
+ letters[xy] = text[i]
38
+ return letters
39
+
40
+
41
+ def inject_styles() -> None:
42
+ st.markdown(
43
+ """
44
+ <style>
45
+ .bw-row { display: flex; gap: 4px; flex-wrap: nowrap; }
46
+ .bw-cell {
47
+ width: 100%;
48
+ aspect-ratio: 1 / 1;
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ border: 1px solid #3a3a3a;
53
+ border-radius: 4px;
54
+ font-weight: 700;
55
+ user-select: none;
56
+ }
57
+ .bw-cell.letter { background: #1e1e1e; color: #eaeaea; }
58
+ .bw-cell.empty { background: #0f0f0f; }
59
+ div[data-testid="stButton"] button {
60
+ width: 100%;
61
+ aspect-ratio: 1 / 1;
62
+ border-radius: 4px;
63
+ border: 1px solid #3a3a3a;
64
+ }
65
+ /* Mobile styles */
66
+ @media (max-width: 640px) {
67
+ /* stColumns: force 100% width and column-reverse for radar */
68
+ div[data-testid="stHorizontalBlock"] {
69
+ # flex-direction: column-reverse !important;
70
+ width: 100% !important;
71
+ max-width: 100vw !important;
72
+ }
73
+ div[data-testid="column"] {
74
+ width: 100% !important;
75
+ min-width: 100% !important;
76
+ max-width: 100vw !important;
77
+ flex: 1 1 100% !important;
78
+ }
79
+ div[data-testid="stLayoutWrapper"] .stHorizontalBlock div[data-testid="stColumn"]:first-child {
80
+ min-width: calc(8.33333% - 1rem) !important;
81
+ }
82
+ /* Prevent grid from wrapping */
83
+ .bw-row {
84
+ flex-wrap: nowrap !important;
85
+ width: 100vw !important;
86
+ overflow-x: auto;
87
+ }
88
+ }
89
+ </style>
90
+ """,
91
+ unsafe_allow_html=True,
92
+ )
93
+
94
+
95
  def _init_session() -> None:
96
  if "initialized" in st.session_state and st.session_state.initialized:
97
  return
 
145
  "- Grid is 12×12 with 6 words (two 4-letter, two 5-letter, two 6-letter).\n"
146
  "- After each reveal, you may submit one guess.\n"
147
  "- Scoring: length + unrevealed letters of that word at guess time.")
148
+ inject_styles()
149
 
150
 
151
  def _render_sidebar():
pyproject.toml CHANGED
@@ -1,7 +1,7 @@
1
  [project]
2
  name = "battlewords"
3
  version = "0.1.0"
4
- description = "Add your description here"
5
  readme = "README.md"
6
  requires-python = ">=3.13"
7
  dependencies = [
 
1
  [project]
2
  name = "battlewords"
3
  version = "0.1.0"
4
+ description = "BattleWords vocabulary game"
5
  readme = "README.md"
6
  requires-python = ">=3.13"
7
  dependencies = [