From 9d0c0a0193628770455fe8b806665b8772fcc63b Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 5 Jul 2026 06:21:06 -0700 Subject: [PATCH] Fix hangman: lowercase r swallowed by restart binding during play (#79) The Update key switch bound "r" to restart, but returned early even when the game was still active, so lowercase r could never be entered as a letter guess (Shift+R worked because "R" didn't match the case). Now r only restarts when dead; otherwise it falls through to the guess logic. Co-authored-by: Claude Opus 4.8 --- plugins/arcade/hangman.go | 3 ++- plugins/arcade/hangman_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/arcade/hangman.go b/plugins/arcade/hangman.go index 508dbbe..534ede2 100644 --- a/plugins/arcade/hangman.go +++ b/plugins/arcade/hangman.go @@ -78,10 +78,11 @@ func (h *hangman) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "q", "esc": return h, back case "r": + // Only "restart" once dead; during play, r is a normal letter guess + // and must fall through to the guessing logic below. if h.dead { return newHangman(h.user, h.ctx), nil } - return h, nil case " ", "enter": if h.won { h.deal() // advance to the next word diff --git a/plugins/arcade/hangman_test.go b/plugins/arcade/hangman_test.go index d9851a7..e8c6b42 100644 --- a/plugins/arcade/hangman_test.go +++ b/plugins/arcade/hangman_test.go @@ -68,6 +68,18 @@ func TestHangmanDeathAfterSixMisses(t *testing.T) { } } +// The "r" restart binding must not swallow r as a letter guess during play. +func TestHangmanLowercaseRIsAGuess(t *testing.T) { + h := newTestHangman("ROUTER") + for _, r := range "router" { + m, _ := h.Update(key(r)) + h = m.(*hangman) + } + if !h.won { + t.Fatalf("lowercase r should count as a guess and solve ROUTER") + } +} + func TestHangmanLowercaseInputAndAdvance(t *testing.T) { h := newTestHangman("CAT") for _, r := range "cat" { // lowercase should still solve