Simplify codebase and fix Enter key on home page
- Enter key now triggers createGame action on home page - Remove redundant setNickname action from home page - Remove unused code: join channel, Leave(), Stop() methods - Consolidate ID generation into game.GenerateID() - Remove unused CreatedAt field from Game struct
This commit is contained in:
@@ -28,7 +28,7 @@ func NewGameStore() *GameStore {
|
||||
}
|
||||
|
||||
func (gs *GameStore) Create() *GameInstance {
|
||||
id := generateGameID()
|
||||
id := GenerateID(4)
|
||||
gi := NewGameInstance(id)
|
||||
gs.gamesMu.Lock()
|
||||
gs.games[id] = gi
|
||||
@@ -44,8 +44,8 @@ func (gs *GameStore) Get(id string) (*GameInstance, bool) {
|
||||
return gi, ok
|
||||
}
|
||||
|
||||
func generateGameID() string {
|
||||
b := make([]byte, 4)
|
||||
func GenerateID(size int) string {
|
||||
b := make([]byte, size)
|
||||
rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
@@ -55,7 +55,6 @@ type GameInstance struct {
|
||||
gameMu sync.RWMutex
|
||||
players map[PlayerID]Syncable
|
||||
playersMu sync.RWMutex
|
||||
join chan *PlayerSession
|
||||
leave chan PlayerID
|
||||
done chan struct{}
|
||||
dirty bool
|
||||
@@ -65,7 +64,6 @@ func NewGameInstance(id string) *GameInstance {
|
||||
return &GameInstance{
|
||||
game: NewGame(id),
|
||||
players: make(map[PlayerID]Syncable),
|
||||
join: make(chan *PlayerSession, 5),
|
||||
leave: make(chan PlayerID, 5),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
@@ -101,10 +99,6 @@ func (gi *GameInstance) Join(ps *PlayerSession) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (gi *GameInstance) Leave(pid PlayerID) {
|
||||
gi.leave <- pid
|
||||
}
|
||||
|
||||
func (gi *GameInstance) GetGame() *Game {
|
||||
gi.gameMu.RLock()
|
||||
defer gi.gameMu.RUnlock()
|
||||
@@ -186,7 +180,3 @@ func (gi *GameInstance) publish() {
|
||||
sync.Sync()
|
||||
}
|
||||
}
|
||||
|
||||
func (gi *GameInstance) Stop() {
|
||||
close(gi.done)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package game
|
||||
|
||||
import "time"
|
||||
|
||||
type PlayerID string
|
||||
|
||||
type Player struct {
|
||||
@@ -27,7 +25,6 @@ type Game struct {
|
||||
Status GameStatus
|
||||
Winner *Player
|
||||
WinningCells [][2]int // Coordinates of winning 4 cells for highlighting
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
func NewGame(id string) *Game {
|
||||
@@ -36,6 +33,5 @@ func NewGame(id string) *Game {
|
||||
Board: [6][7]int{},
|
||||
CurrentTurn: 1, // Red goes first
|
||||
Status: StatusWaitingForPlayer,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
6
go.mod
6
go.mod
@@ -2,16 +2,12 @@ module github.com/ryanhamamura/c4
|
||||
|
||||
go 1.25.4
|
||||
|
||||
require (
|
||||
github.com/go-via/via-plugin-picocss v0.1.1
|
||||
github.com/ryanhamamura/via v0.2.3
|
||||
)
|
||||
require github.com/ryanhamamura/via v0.2.3
|
||||
|
||||
require (
|
||||
github.com/CAFxX/httpcompression v0.0.9 // indirect
|
||||
github.com/alexedwards/scs/v2 v2.9.0 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/go-via/via v0.1.4 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/starfederation/datastar-go v1.0.3 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -8,10 +8,6 @@ github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUS
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-via/via v0.1.4 h1:Fz9fwaT5+TBqcetiVM33SxkuysAeFDOiiASFu3GW7WY=
|
||||
github.com/go-via/via v0.1.4/go.mod h1:Y8oddRwP6SWX15Xb6UQj4HtLZwxTYI1HbWBmELtB/f8=
|
||||
github.com/go-via/via-plugin-picocss v0.1.1 h1:rbA9wL9eEanT8HOOfX1b4Mr2L2VjaDrsIrUECDxV73k=
|
||||
github.com/go-via/via-plugin-picocss v0.1.1/go.mod h1:npvsvG2FWeIPkzHzSSzW+uBGE0m5gnIAdlePqKcfuAQ=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f h1:jopqB+UTSdJGEJT8tEqYyE29zN91fi2827oLET8tl7k=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
|
||||
61
main.go
61
main.go
@@ -1,9 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
"github.com/ryanhamamura/c4/ui"
|
||||
"github.com/ryanhamamura/via"
|
||||
@@ -29,14 +26,6 @@ func main() {
|
||||
v.Page("/", func(c *via.Context) {
|
||||
nickname := c.Signal("")
|
||||
|
||||
setNickname := c.Action(func() {
|
||||
name := nickname.String()
|
||||
if name != "" {
|
||||
c.Session().Set("nickname", name)
|
||||
c.Sync()
|
||||
}
|
||||
})
|
||||
|
||||
createGame := c.Action(func() {
|
||||
name := nickname.String()
|
||||
if name == "" {
|
||||
@@ -51,7 +40,7 @@ func main() {
|
||||
c.View(func() h.H {
|
||||
return ui.LobbyView(
|
||||
nickname.Bind(),
|
||||
setNickname.OnKeyDown("Enter"),
|
||||
createGame.OnKeyDown("Enter"),
|
||||
createGame.OnClick(),
|
||||
)
|
||||
})
|
||||
@@ -66,8 +55,6 @@ func main() {
|
||||
colSignal := c.Signal(0)
|
||||
|
||||
var gi *game.GameInstance
|
||||
var player *game.Player
|
||||
var playerJoined bool
|
||||
var gameExists bool
|
||||
|
||||
// Look up game (may not exist during warmup or invalid ID)
|
||||
@@ -75,6 +62,13 @@ func main() {
|
||||
gi, gameExists = store.Get(gameID)
|
||||
}
|
||||
|
||||
// Generate a stable player ID for this session
|
||||
playerID := game.PlayerID(c.Session().GetString("player_id"))
|
||||
if playerID == "" {
|
||||
playerID = game.PlayerID(game.GenerateID(8))
|
||||
c.Session().Set("player_id", string(playerID))
|
||||
}
|
||||
|
||||
setNickname := c.Action(func() {
|
||||
if gi == nil {
|
||||
return
|
||||
@@ -85,12 +79,13 @@ func main() {
|
||||
}
|
||||
c.Session().Set("nickname", name)
|
||||
|
||||
if !playerJoined {
|
||||
player = &game.Player{
|
||||
ID: game.PlayerID(generatePlayerID()),
|
||||
// Try to join if not already in game
|
||||
if gi.GetPlayerColor(playerID) == 0 {
|
||||
player := &game.Player{
|
||||
ID: playerID,
|
||||
Nickname: name,
|
||||
}
|
||||
playerJoined = gi.Join(&game.PlayerSession{
|
||||
gi.Join(&game.PlayerSession{
|
||||
Player: player,
|
||||
Sync: c,
|
||||
})
|
||||
@@ -99,20 +94,25 @@ func main() {
|
||||
})
|
||||
|
||||
dropPiece := c.Action(func() {
|
||||
if gi == nil || player == nil {
|
||||
if gi == nil {
|
||||
return
|
||||
}
|
||||
myColor := gi.GetPlayerColor(playerID)
|
||||
if myColor == 0 {
|
||||
return
|
||||
}
|
||||
col := colSignal.Int()
|
||||
gi.DropPiece(col, player.Color)
|
||||
gi.DropPiece(col, myColor)
|
||||
c.Sync()
|
||||
})
|
||||
|
||||
// If nickname exists in session and game exists, join immediately
|
||||
if gameExists && sessionNickname != "" {
|
||||
player = &game.Player{
|
||||
ID: game.PlayerID(generatePlayerID()),
|
||||
if gameExists && sessionNickname != "" && gi.GetPlayerColor(playerID) == 0 {
|
||||
player := &game.Player{
|
||||
ID: playerID,
|
||||
Nickname: sessionNickname,
|
||||
}
|
||||
playerJoined = gi.Join(&game.PlayerSession{
|
||||
gi.Join(&game.PlayerSession{
|
||||
Player: player,
|
||||
Sync: c,
|
||||
})
|
||||
@@ -125,8 +125,10 @@ func main() {
|
||||
return h.Div()
|
||||
}
|
||||
|
||||
// Need nickname first
|
||||
if !playerJoined {
|
||||
myColor := gi.GetPlayerColor(playerID)
|
||||
|
||||
// Need nickname first / not joined yet
|
||||
if myColor == 0 {
|
||||
return ui.NicknamePrompt(
|
||||
nickname.Bind(),
|
||||
setNickname.OnKeyDown("Enter"),
|
||||
@@ -135,7 +137,6 @@ func main() {
|
||||
}
|
||||
|
||||
g := gi.GetGame()
|
||||
myColor := player.Color
|
||||
|
||||
// Create column click function
|
||||
columnClick := func(col int) h.H {
|
||||
@@ -164,12 +165,6 @@ func main() {
|
||||
v.Start()
|
||||
}
|
||||
|
||||
func generatePlayerID() string {
|
||||
b := make([]byte, 8)
|
||||
rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
const gameCSS = `
|
||||
body { margin: 0; }
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/ryanhamamura/via/h"
|
||||
)
|
||||
|
||||
func LobbyView(nicknameBind, setNicknameKeyDown, createGameClick h.H) h.H {
|
||||
func LobbyView(nicknameBind, createGameKeyDown, createGameClick h.H) h.H {
|
||||
return h.Main(h.Class("container"),
|
||||
h.Div(h.Class("lobby"),
|
||||
h.H1(h.Text("Connect 4")),
|
||||
@@ -18,7 +18,7 @@ func LobbyView(nicknameBind, setNicknameKeyDown, createGameClick h.H) h.H {
|
||||
h.Placeholder("Enter your nickname"),
|
||||
nicknameBind,
|
||||
h.Attr("required"),
|
||||
setNicknameKeyDown,
|
||||
createGameKeyDown,
|
||||
),
|
||||
),
|
||||
h.Button(
|
||||
|
||||
Reference in New Issue
Block a user