mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
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 <noreply@anthropic.com>
98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
package arcade
|
|
|
|
import (
|
|
"testing"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"github.com/profullstack/agentbbs/internal/auth"
|
|
"github.com/profullstack/agentbbs/internal/plugin"
|
|
)
|
|
|
|
// key builds a single-rune key press the way bubbletea delivers it.
|
|
func key(r rune) tea.KeyMsg { return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{r}} }
|
|
|
|
// guest avoids the store path (only members persist), so ctx.Store can be nil.
|
|
func newTestHangman(word string) *hangman {
|
|
h := newHangman(auth.User{Kind: auth.Guest}, plugin.Context{})
|
|
h.word = word
|
|
h.guessed = make(map[byte]bool)
|
|
h.wrong = 0
|
|
h.won = false
|
|
return h
|
|
}
|
|
|
|
func TestHangmanSolveScores(t *testing.T) {
|
|
h := newTestHangman("CAT")
|
|
for _, r := range "CAT" {
|
|
m, _ := h.Update(key(r))
|
|
h = m.(*hangman)
|
|
}
|
|
if !h.won {
|
|
t.Fatalf("expected won after guessing every letter")
|
|
}
|
|
if h.solved != 1 {
|
|
t.Fatalf("solved = %d, want 1", h.solved)
|
|
}
|
|
// len 3 *10 + (6-0)*5 = 60.
|
|
if h.score != 60 {
|
|
t.Fatalf("score = %d, want 60", h.score)
|
|
}
|
|
if h.dead {
|
|
t.Fatalf("should not be dead after a solve")
|
|
}
|
|
}
|
|
|
|
func TestHangmanWrongGuessIsCountedOnce(t *testing.T) {
|
|
h := newTestHangman("CAT")
|
|
for i := 0; i < 3; i++ { // repeat the same wrong letter
|
|
m, _ := h.Update(key('Z'))
|
|
h = m.(*hangman)
|
|
}
|
|
if h.wrong != 1 {
|
|
t.Fatalf("wrong = %d, want 1 (repeat guesses must not stack)", h.wrong)
|
|
}
|
|
}
|
|
|
|
func TestHangmanDeathAfterSixMisses(t *testing.T) {
|
|
h := newTestHangman("CAT")
|
|
for _, r := range "BDEFGH" { // six letters absent from CAT
|
|
m, _ := h.Update(key(r))
|
|
h = m.(*hangman)
|
|
}
|
|
if h.wrong != hangmanMaxWrong {
|
|
t.Fatalf("wrong = %d, want %d", h.wrong, hangmanMaxWrong)
|
|
}
|
|
if !h.dead {
|
|
t.Fatalf("expected dead after %d misses", hangmanMaxWrong)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
m, _ := h.Update(key(r))
|
|
h = m.(*hangman)
|
|
}
|
|
if !h.won {
|
|
t.Fatalf("lowercase input should solve the word")
|
|
}
|
|
// space deals a fresh word and clears the round flags.
|
|
m, _ := h.Update(tea.KeyMsg{Type: tea.KeySpace})
|
|
h = m.(*hangman)
|
|
if h.won || h.wrong != 0 || len(h.guessed) != 0 {
|
|
t.Fatalf("space should deal a fresh round: won=%v wrong=%d guessed=%d", h.won, h.wrong, len(h.guessed))
|
|
}
|
|
}
|