games: UNO becomes a table you sit at, and the pot that pays whoever goes out first
Phase D backend: UNO is now a session like hold'em, not a single stake. You sit
with a buy-in stack, ante into a pot each hand, and leave with what's in front of
you. The engine lost its `You` constant and its measured multiples: ApplyMove
takes the acting seat, New takes a seat list, a Tier carries an ante instead of a
Base, and a hand settles by moving the pot to the winner (less rake, and never
when a bot takes it) rather than paying a multiple. A mercy kill puts a seat out
of the hand, not out of the game — the last one standing takes the pot.
The redaction moved to the web layer, where hold'em's already lives: the engine
now stamps every seat's hand onto its events, and viewUno/viewUnoEvents strip
everything that isn't the viewer's own. TestUnoViewNeverLeaksAnotherSeatsCards is
the wall. unoTable implements tableGame; /uno/{sit,move,leave,tables,stream,chat,
say} mirror hold'em, with stream/chat/say now shared game-agnostic handlers.
The frontend is not done: uno.js still calls the retired solo endpoint, so the
page renders but is not yet playable. All engine and web tests are green.
Claude-Session: https://claude.ai/code/session_013M5nD7PgUboJXoDcYHzpuJ
This commit is contained in:
@@ -19,17 +19,25 @@ import (
|
||||
|
||||
// ---- the lobby -------------------------------------------------------------
|
||||
|
||||
// handleHoldemLobby lists the hold'em tables with a seat going spare. A table
|
||||
// with every chair taken is not shown, because a lobby you cannot join from is
|
||||
// just a list; bots keep every open table populated, so there is always
|
||||
// something to sit down at.
|
||||
// handleHoldemLobby and handleUnoLobby list the tables of their game with a seat
|
||||
// going spare. A table with every chair taken is not shown, because a lobby you
|
||||
// cannot join from is just a list; bots keep every open table populated, so there
|
||||
// is always something to sit down at.
|
||||
func (s *Server) handleHoldemLobby(w http.ResponseWriter, r *http.Request) {
|
||||
s.lobby(w, r, gameHoldem)
|
||||
}
|
||||
|
||||
func (s *Server) handleUnoLobby(w http.ResponseWriter, r *http.Request) {
|
||||
s.lobby(w, r, gameUno)
|
||||
}
|
||||
|
||||
func (s *Server) lobby(w http.ResponseWriter, r *http.Request, game string) {
|
||||
if _, ok := s.player(w, r); !ok {
|
||||
return
|
||||
}
|
||||
tables, err := storage.LobbyTables(gameHoldem, 50)
|
||||
tables, err := storage.LobbyTables(game, 50)
|
||||
if err != nil {
|
||||
slog.Error("games: holdem lobby", "err", err)
|
||||
slog.Error("games: lobby", "game", game, "err", err)
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -58,7 +66,7 @@ const streamPing = 25 * time.Second
|
||||
// table the player is at. After that it only ever reads its channel. Holding a
|
||||
// query open for the life of a stream would hold the single pooled connection for
|
||||
// the life of a stream, and one idle subscriber would take the whole site down.
|
||||
func (s *Server) handleHoldemStream(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleTableStream(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := s.player(w, r)
|
||||
if !ok {
|
||||
return
|
||||
@@ -117,7 +125,7 @@ func (s *Server) handleHoldemStream(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// handleHoldemChat reads the recent rail of a player's table, oldest first, with
|
||||
// their own lines flagged so the felt can lay them out on the right.
|
||||
func (s *Server) handleHoldemChat(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleTableChat(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := s.player(w, r)
|
||||
if !ok {
|
||||
return
|
||||
@@ -152,7 +160,7 @@ func (s *Server) handleHoldemChat(w http.ResponseWriter, r *http.Request) {
|
||||
// stamped with the hand it was said during — the one question chat at a money
|
||||
// table ever really raises — and pushed to every open stream so it lands on the
|
||||
// rail in real time.
|
||||
func (s *Server) handleHoldemSay(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleTableSay(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := s.player(w, r)
|
||||
if !ok {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user