package plays import ( "fmt" "net/url" "sync" "gitea.konchin.com/ytshih/inp2025/game/server/wordle" "gitea.konchin.com/ytshih/inp2025/game/types" tea "github.com/charmbracelet/bubbletea" "github.com/gorilla/websocket" "github.com/vmihailenco/msgpack/v5" ) type Game struct { *Base server url.URL mutex sync.RWMutex state types.WordleState input string } func (m *Game) GetState() { c, _, err := websocket.DefaultDialer.Dial(m.server.String(), nil) if err != nil { panic(fmt.Errorf("failed to dial, %w", err)) } defer c.Close() for { _, b, err := c.ReadMessage() switch err.(type) { case nil: var state types.WordleState if err := msgpack.Unmarshal(b, &state); err != nil { panic(fmt.Errorf("failed to unmarshal state, %w", err)) } m.mutex.Lock() m.state = state m.mutex.Unlock() case *websocket.CloseError: return default: panic(fmt.Errorf("failed to read message, %w", err)) } } } func NewGame(base *Base, server url.URL) *Game { m := &Game{ Base: base, server: server, state: types.NewWordleState(), input: "", } go m.GetState() return m } func (m *Game) Init() tea.Cmd { return tea.Batch(tea.ClearScreen) } func (m *Game) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if _, cmd := m.Base.Update(msg); cmd != nil { return m, cmd } switch msg := msg.(type) { case tea.KeyMsg: switch msg.Type { case tea.KeyBackspace: if len(m.input) > 0 { m.input = m.input[:len(m.input)-1] } case tea.KeyEnter: if len(m.input) == types.MaxLength { return m, tea.Quit } case tea.KeyRunes: if len(m.input) < types.MaxLength { m.input = m.input + string(msg.Runes) } } } return m, nil } func (m *Game) View() string { m.mutex.RLock() ret := m.state.View() m.mutex.RUnlock() return ret } func (m *Game) Next(queue *[]*tea.Program) error { if len(m.input) == types.MaxLength { b, err := msgpack.Marshal(wordle.Operation{ Type: wordle.OperationTypeGuess, Username: m.username, }) if err != nil { return err } _, err = m.Base.client.R(). SetBody(b). Post("/api/guess") if err != nil { return err } *queue = append(*queue, tea.NewProgram(NewGame(m.Base, m.server))) } return nil }