Surn commited on
Commit
226477a
·
1 Parent(s): 99bf0ab

Ron Notes 9/29/2025

Browse files
battlewords/logic.py CHANGED
@@ -48,7 +48,7 @@ def guess_word(state: GameState, guess_text: str) -> Tuple[bool, int]:
48
  break
49
 
50
  if target is None:
51
- state.last_action = f"'{guess}' is not in the puzzle."
52
  state.can_guess = False
53
  return False, 0
54
 
 
48
  break
49
 
50
  if target is None:
51
+ state.last_action = f"Try Again! '{guess}' is not in the puzzle."
52
  state.can_guess = False
53
  return False, 0
54
 
battlewords/ui.py CHANGED
@@ -82,11 +82,16 @@ def inject_styles() -> None:
82
  .bw-final-score { color: #1ca41c !important; font-weight: 800; }
83
 
84
  /* Make grid buttons square and fill their column */
 
 
 
 
85
  div[data-testid="stButton"] button {
86
- width: 100%;
 
87
  aspect-ratio: 1 / 1;
88
  border-radius: 0;
89
- border: 1px solid #1d64c8;
90
  background: #1d64c8;
91
  color: #ffffff;
92
  font-weight: 700;
@@ -220,7 +225,7 @@ def _init_session() -> None:
220
  # Ensure a default selection exists before creating the puzzle
221
  files = get_wordlist_files()
222
  if "selected_wordlist" not in st.session_state and files:
223
- st.session_state.selected_wordlist = "wordlist.txt"
224
  if "game_mode" not in st.session_state:
225
  st.session_state.game_mode = "standard"
226
 
@@ -292,12 +297,7 @@ def _render_header():
292
 
293
  def _render_sidebar():
294
  with st.sidebar:
295
- st.header("Controls")
296
- st.button("New Game", width="stretch", on_click=_new_game)
297
- st.markdown(
298
- "- Radar pulses show the last letter position of each hidden word.\n"
299
- "- After each reveal, you may submit one word guess below.\n"
300
- "- Scoring: length + unrevealed letters of that word at guess time.")
301
 
302
  st.header("Game Mode")
303
  game_modes = ["standard", "easy"]
@@ -332,7 +332,7 @@ def _render_sidebar():
332
  on_change=_new_game, # immediately start a new game with the selected list
333
  )
334
 
335
- if st.button("Sort Wordlist"):
336
  _sort_wordlist(st.session_state.selected_wordlist)
337
  else:
338
  st.info("No word lists found in words/ directory. Using built-in fallback.")
@@ -542,6 +542,18 @@ def _render_grid(state: GameState, letter_map):
542
  max-width:300px !important;
543
  margin: 0 auto !important;
544
  }
 
 
 
 
 
 
 
 
 
 
 
 
545
  </style>
546
  """,
547
  unsafe_allow_html=True,
@@ -623,13 +635,50 @@ def _render_hit_miss(state: GameState):
623
  )
624
 
625
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  def _render_guess_form(state: GameState):
627
  with st.form("guess_form"):
628
  guess_text = st.text_input("Your guess", value="", max_chars=12)
629
  submitted = st.form_submit_button("OK", disabled=not state.can_guess, width="stretch")
630
  if submitted:
631
  correct, _ = guess_word(state, guess_text)
632
- _sync_back(state)
 
633
 
634
 
635
  def _render_score_panel(state: GameState):
@@ -642,10 +691,20 @@ def _render_score_panel(state: GameState):
642
  _render_game_over(state)
643
  else:
644
  with st.expander("Game summary", expanded=True):
 
 
 
 
645
  for w in state.puzzle.words:
646
  pts = state.points_by_word.get(w.text, 0)
647
  if pts > 0 or state.game_mode=="easy":
648
- st.markdown(f"- {w.text} ({len(w.text)}): +{pts} points")
 
 
 
 
 
 
649
  st.markdown(f"**Total**: {state.score}")
650
 
651
 
@@ -659,9 +718,19 @@ def _render_game_over(state: GameState):
659
  )
660
 
661
  with st.expander("Game summary", expanded=True):
 
 
 
 
662
  for w in state.puzzle.words:
663
  pts = state.points_by_word.get(w.text, 0)
664
- st.markdown(f"- {w.text} ({len(w.text)}): +{pts} points")
 
 
 
 
 
 
665
  st.markdown(f"**Total**: {state.score}")
666
 
667
  st.stop()
@@ -699,15 +768,17 @@ def run_app():
699
  left, right = st.columns([2, 2], gap="medium")
700
  with left:
701
  _render_grid(state, st.session_state.letter_map)
 
702
 
703
  with right:
704
- one, two = st.columns([1, 5], gap="small")
 
705
  with one:
706
- _render_hit_miss(state)
707
- with two:
708
- _render_radar(state.puzzle, size=state.grid_size, r_max=1.6, max_frames=60, sinusoid_expand=False, stagger_radar=True)
709
- #st.divider()
710
- _render_guess_form(state)
711
  _render_score_panel(state)
712
 
713
 
 
82
  .bw-final-score { color: #1ca41c !important; font-weight: 800; }
83
 
84
  /* Make grid buttons square and fill their column */
85
+ div[data-testid="stButton"]{
86
+ margin: 0 auto;
87
+ text-align: center;
88
+ }
89
  div[data-testid="stButton"] button {
90
+ max-width: 100%;
91
+ width: auto;
92
  aspect-ratio: 1 / 1;
93
  border-radius: 0;
94
+ #border: 1px solid #1d64c8;
95
  background: #1d64c8;
96
  color: #ffffff;
97
  font-weight: 700;
 
225
  # Ensure a default selection exists before creating the puzzle
226
  files = get_wordlist_files()
227
  if "selected_wordlist" not in st.session_state and files:
228
+ st.session_state.selected_wordlist = "classic.txt"
229
  if "game_mode" not in st.session_state:
230
  st.session_state.game_mode = "standard"
231
 
 
297
 
298
  def _render_sidebar():
299
  with st.sidebar:
300
+ st.header("SETTINGS")
 
 
 
 
 
301
 
302
  st.header("Game Mode")
303
  game_modes = ["standard", "easy"]
 
332
  on_change=_new_game, # immediately start a new game with the selected list
333
  )
334
 
335
+ if st.button("Sort Wordlist", width="content"):
336
  _sort_wordlist(st.session_state.selected_wordlist)
337
  else:
338
  st.info("No word lists found in words/ directory. Using built-in fallback.")
 
542
  max-width:300px !important;
543
  margin: 0 auto !important;
544
  }
545
+ .st-emotion-cache-ig7yu6 {
546
+ width: calc(30% - 1rem);
547
+ flex: 1 1 calc(20% - 1rem);
548
+ }
549
+ @media (max-width: 640px) {
550
+ .st-emotion-cache-1s1xxaz {
551
+ min-width: calc(33% - 1.5rem);
552
+ }
553
+ .st-emotion-cache-ig7yu6 {
554
+ min-width: calc(30% - 1.5rem);
555
+ }
556
+ }
557
  </style>
558
  """,
559
  unsafe_allow_html=True,
 
635
  )
636
 
637
 
638
+ def _render_correct_try_again(state: GameState):
639
+ # Determine last guess outcome from last_action string
640
+ action = (state.last_action or "").strip()
641
+ is_correct = action.startswith("Correct!")
642
+ is_try_again = action.startswith("Try Again!")
643
+
644
+ st.markdown(
645
+ """
646
+ <style>
647
+ .bw-radio-caption.inactive { display: none !important; }
648
+ </style>
649
+ """,
650
+ unsafe_allow_html=True,
651
+ )
652
+
653
+ st.markdown(
654
+ f"""
655
+ <div class="bw-radio-group" role="radiogroup" aria-label="Correct or Try Again">
656
+ <div class="bw-radio-item">
657
+ <div class="bw-radio-circle {'active hit' if is_correct else ''}" role="radio" aria-checked="{'true' if is_correct else 'false'}" aria-label="Correct">
658
+ <span class="dot"></span>
659
+ </div>
660
+ <div class="bw-radio-caption{' inactive' if not is_correct else ''}">CORRECT!</div>
661
+ </div>
662
+ <div class="bw-radio-item">
663
+ <div class="bw-radio-circle {'active miss' if is_try_again else ''}" role="radio" aria-checked="{'true' if is_try_again else 'false'}" aria-label="Try Again">
664
+ <span class="dot"></span>
665
+ </div>
666
+ <div class="bw-radio-caption{' inactive' if not is_try_again else ''}">TRY AGAIN</div>
667
+ </div>
668
+ </div>
669
+ """,
670
+ unsafe_allow_html=True,
671
+ )
672
+
673
+
674
  def _render_guess_form(state: GameState):
675
  with st.form("guess_form"):
676
  guess_text = st.text_input("Your guess", value="", max_chars=12)
677
  submitted = st.form_submit_button("OK", disabled=not state.can_guess, width="stretch")
678
  if submitted:
679
  correct, _ = guess_word(state, guess_text)
680
+ _sync_back(state)
681
+ st.rerun() # Immediately rerun to reflect guess result in UI
682
 
683
 
684
  def _render_score_panel(state: GameState):
 
691
  _render_game_over(state)
692
  else:
693
  with st.expander("Game summary", expanded=True):
694
+ header_cols = st.columns([1, 1, 1])
695
+ header_cols[0].markdown("**Word**")
696
+ header_cols[1].markdown("**Letters**")
697
+ header_cols[2].markdown("**Extra**")
698
  for w in state.puzzle.words:
699
  pts = state.points_by_word.get(w.text, 0)
700
  if pts > 0 or state.game_mode=="easy":
701
+ word_display = w.text
702
+ letters_display = str(len(w.text))
703
+ extra_display = f"+{pts} points"
704
+ row_cols = st.columns([1, 1, 1])
705
+ row_cols[0].markdown(f"{word_display}")
706
+ row_cols[1].markdown(f"{letters_display}")
707
+ row_cols[2].markdown(f"{extra_display}")
708
  st.markdown(f"**Total**: {state.score}")
709
 
710
 
 
718
  )
719
 
720
  with st.expander("Game summary", expanded=True):
721
+ header_cols = st.columns([2, 1, 2])
722
+ header_cols[0].markdown("**Word**")
723
+ header_cols[1].markdown("**Letters**")
724
+ header_cols[2].markdown("**Extra**")
725
  for w in state.puzzle.words:
726
  pts = state.points_by_word.get(w.text, 0)
727
+ word_display = w.text
728
+ letters_display = str(len(w.text))
729
+ extra_display = f"+{pts} points"
730
+ row_cols = st.columns([1, 1, 1])
731
+ row_cols[0].markdown(f"{word_display}")
732
+ row_cols[1].markdown(f"{letters_display}")
733
+ row_cols[2].markdown(f"{extra_display}")
734
  st.markdown(f"**Total**: {state.score}")
735
 
736
  st.stop()
 
768
  left, right = st.columns([2, 2], gap="medium")
769
  with left:
770
  _render_grid(state, st.session_state.letter_map)
771
+ st.button("New Game", width="content", on_click=_new_game)
772
 
773
  with right:
774
+ _render_radar(state.puzzle, size=state.grid_size, r_max=1.6, max_frames=60, sinusoid_expand=False, stagger_radar=True)
775
+ one, two = st.columns([1, 5], gap="medium")
776
  with one:
777
+ _render_correct_try_again(state)
778
+ #_render_hit_miss(state)
779
+ with two:
780
+ _render_guess_form(state)
781
+ #st.divider()
782
  _render_score_panel(state)
783
 
784
 
battlewords/words/classic.txt CHANGED
@@ -266,6 +266,7 @@ WORD
266
  YARD
267
  YELL
268
  ZONE
 
269
  ABOVE
270
  AGAIN
271
  AGREE
 
266
  YARD
267
  YELL
268
  ZONE
269
+ ABOUT
270
  ABOVE
271
  AGAIN
272
  AGREE