refactor: rename game package to connect4, drop Game prefix from types
Rename game/ -> connect4/ to avoid c4/game stutter. Drop redundant
Game prefix from exported types (GameStore -> Store, GameInstance ->
Instance, GameStatus -> Status). Rename NATS subjects from game.{id}
to connect4.{id}. URL routes unchanged.
This commit is contained in:
@@ -3,11 +3,11 @@ package components
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
"github.com/ryanhamamura/c4/connect4"
|
||||
"github.com/starfederation/datastar-go/datastar"
|
||||
)
|
||||
|
||||
templ Board(g *game.Game, myColor int) {
|
||||
templ Board(g *connect4.Game, myColor int) {
|
||||
<div id="c4-board" class="board">
|
||||
for col := 0; col < 7; col++ {
|
||||
@column(g, col, myColor)
|
||||
@@ -15,8 +15,8 @@ templ Board(g *game.Game, myColor int) {
|
||||
</div>
|
||||
}
|
||||
|
||||
templ column(g *game.Game, colIdx int, myColor int) {
|
||||
if g.Status == game.StatusInProgress && myColor == g.CurrentTurn {
|
||||
templ column(g *connect4.Game, colIdx int, myColor int) {
|
||||
if g.Status == connect4.StatusInProgress && myColor == g.CurrentTurn {
|
||||
<div
|
||||
class="column clickable"
|
||||
data-on:click={ datastar.PostSSE("/games/%s/drop?col=%d", g.ID, colIdx) }
|
||||
@@ -34,14 +34,14 @@ templ column(g *game.Game, colIdx int, myColor int) {
|
||||
}
|
||||
}
|
||||
|
||||
templ cell(g *game.Game, row int, col int) {
|
||||
templ cell(g *connect4.Game, row int, col int) {
|
||||
<div class={ cellClass(g, row, col) }></div>
|
||||
}
|
||||
|
||||
func cellClass(g *game.Game, row, col int) string {
|
||||
func cellClass(g *connect4.Game, row, col int) string {
|
||||
color := g.Board[row][col]
|
||||
activeTurn := 0
|
||||
if g.Status == game.StatusInProgress {
|
||||
if g.Status == connect4.StatusInProgress {
|
||||
activeTurn = g.CurrentTurn
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ package components
|
||||
|
||||
import (
|
||||
"github.com/ryanhamamura/c4/config"
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
"github.com/ryanhamamura/c4/connect4"
|
||||
"github.com/starfederation/datastar-go/datastar"
|
||||
)
|
||||
|
||||
templ StatusBanner(g *game.Game, myColor int) {
|
||||
templ StatusBanner(g *connect4.Game, myColor int) {
|
||||
<div id="c4-status" class={ statusClass(g, myColor) }>
|
||||
{ statusMessage(g, myColor) }
|
||||
if g.IsFinished() {
|
||||
@@ -30,7 +30,7 @@ templ StatusBanner(g *game.Game, myColor int) {
|
||||
</div>
|
||||
}
|
||||
|
||||
templ PlayerInfo(g *game.Game, myColor int) {
|
||||
templ PlayerInfo(g *connect4.Game, myColor int) {
|
||||
<div id="c4-players" class="flex gap-8 mb-2">
|
||||
for _, info := range playerInfoPairs(g, myColor) {
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -61,36 +61,36 @@ script copyToClipboard(url string) {
|
||||
navigator.clipboard.writeText(url)
|
||||
}
|
||||
|
||||
func statusClass(g *game.Game, myColor int) string {
|
||||
func statusClass(g *connect4.Game, myColor int) string {
|
||||
switch g.Status {
|
||||
case game.StatusWaitingForPlayer:
|
||||
case connect4.StatusWaitingForPlayer:
|
||||
return "alert bg-base-200 text-xl font-bold"
|
||||
case game.StatusInProgress:
|
||||
case connect4.StatusInProgress:
|
||||
if g.CurrentTurn == myColor {
|
||||
return "alert alert-success text-xl font-bold"
|
||||
}
|
||||
return "alert bg-base-200 text-xl font-bold"
|
||||
case game.StatusWon:
|
||||
case connect4.StatusWon:
|
||||
if g.Winner != nil && g.Winner.Color == myColor {
|
||||
return "alert alert-success text-xl font-bold"
|
||||
}
|
||||
return "alert alert-error text-xl font-bold"
|
||||
case game.StatusDraw:
|
||||
case connect4.StatusDraw:
|
||||
return "alert alert-warning text-xl font-bold"
|
||||
}
|
||||
return "alert bg-base-200 text-xl font-bold"
|
||||
}
|
||||
|
||||
func statusMessage(g *game.Game, myColor int) string {
|
||||
func statusMessage(g *connect4.Game, myColor int) string {
|
||||
switch g.Status {
|
||||
case game.StatusWaitingForPlayer:
|
||||
case connect4.StatusWaitingForPlayer:
|
||||
return "Waiting for opponent..."
|
||||
case game.StatusInProgress:
|
||||
case connect4.StatusInProgress:
|
||||
if g.CurrentTurn == myColor {
|
||||
return "Your turn!"
|
||||
}
|
||||
return opponentName(g, myColor) + "'s turn"
|
||||
case game.StatusWon:
|
||||
case connect4.StatusWon:
|
||||
if g.Winner != nil && g.Winner.Color == myColor {
|
||||
return "You win!"
|
||||
}
|
||||
@@ -98,13 +98,13 @@ func statusMessage(g *game.Game, myColor int) string {
|
||||
return g.Winner.Nickname + " wins!"
|
||||
}
|
||||
return "Game over"
|
||||
case game.StatusDraw:
|
||||
case connect4.StatusDraw:
|
||||
return "It's a draw!"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func opponentName(g *game.Game, myColor int) string {
|
||||
func opponentName(g *connect4.Game, myColor int) string {
|
||||
for _, p := range g.Players {
|
||||
if p != nil && p.Color != myColor {
|
||||
return p.Nickname
|
||||
@@ -118,7 +118,7 @@ type playerInfoData struct {
|
||||
Label string
|
||||
}
|
||||
|
||||
func playerInfoPairs(g *game.Game, myColor int) []playerInfoData {
|
||||
func playerInfoPairs(g *connect4.Game, myColor int) []playerInfoData {
|
||||
var result []playerInfoData
|
||||
|
||||
var myName, oppName string
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
|
||||
"github.com/ryanhamamura/c4/chat"
|
||||
chatcomponents "github.com/ryanhamamura/c4/chat/components"
|
||||
"github.com/ryanhamamura/c4/connect4"
|
||||
"github.com/ryanhamamura/c4/db/repository"
|
||||
"github.com/ryanhamamura/c4/features/c4game/components"
|
||||
"github.com/ryanhamamura/c4/features/c4game/pages"
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
"github.com/ryanhamamura/c4/sessions"
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ func c4ChatConfig(gameID string) chatcomponents.Config {
|
||||
}
|
||||
}
|
||||
|
||||
func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
func HandleGamePage(store *connect4.Store, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -57,14 +57,14 @@ func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repo
|
||||
|
||||
// Auto-join if player has a nickname but isn't in the game yet
|
||||
if nickname != "" && gi.GetPlayerColor(playerID) == 0 {
|
||||
p := &game.Player{
|
||||
p := &connect4.Player{
|
||||
ID: playerID,
|
||||
Nickname: nickname,
|
||||
}
|
||||
if userID != "" {
|
||||
p.UserID = &userID
|
||||
}
|
||||
gi.Join(&game.PlayerSession{Player: p})
|
||||
gi.Join(&connect4.PlayerSession{Player: p})
|
||||
}
|
||||
|
||||
myColor := gi.GetPlayerColor(playerID)
|
||||
@@ -93,7 +93,7 @@ func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repo
|
||||
}
|
||||
}
|
||||
|
||||
func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
func HandleGameEvents(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -111,14 +111,14 @@ func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManag
|
||||
))
|
||||
|
||||
chatCfg := c4ChatConfig(gameID)
|
||||
room := chat.NewRoom(nc, "game.chat."+gameID, chat.LoadMessages(queries, gameID))
|
||||
room := chat.NewRoom(nc, "connect4.chat."+gameID, chat.LoadMessages(queries, gameID))
|
||||
|
||||
// Send initial render
|
||||
sendGameComponents(sse, gi, myColor, room, chatCfg)
|
||||
|
||||
// Subscribe to game state updates
|
||||
gameCh := make(chan *nats.Msg, 64)
|
||||
gameSub, err := nc.ChanSubscribe("game."+gameID, gameCh)
|
||||
gameSub, err := nc.ChanSubscribe("connect4."+gameID, gameCh)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManag
|
||||
}
|
||||
}
|
||||
|
||||
func HandleDropPiece(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
|
||||
func HandleDropPiece(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -181,7 +181,7 @@ func HandleDropPiece(store *game.GameStore, sm *scs.SessionManager) http.Handler
|
||||
}
|
||||
}
|
||||
|
||||
func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
func HandleSendChat(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -230,7 +230,7 @@ func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager
|
||||
}
|
||||
chat.SaveMessage(queries, gameID, msg)
|
||||
|
||||
room := chat.NewRoom(nc, "game.chat."+gameID, nil)
|
||||
room := chat.NewRoom(nc, "connect4.chat."+gameID, nil)
|
||||
room.Send(msg)
|
||||
|
||||
sse := datastar.NewSSE(w, r)
|
||||
@@ -238,7 +238,7 @@ func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager
|
||||
}
|
||||
}
|
||||
|
||||
func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
|
||||
func HandleSetNickname(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -269,14 +269,14 @@ func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.Handl
|
||||
userID := sessions.GetUserID(sm, r)
|
||||
|
||||
if gi.GetPlayerColor(playerID) == 0 {
|
||||
p := &game.Player{
|
||||
p := &connect4.Player{
|
||||
ID: playerID,
|
||||
Nickname: signals.Nickname,
|
||||
}
|
||||
if userID != "" {
|
||||
p.UserID = &userID
|
||||
}
|
||||
gi.Join(&game.PlayerSession{Player: p})
|
||||
gi.Join(&connect4.PlayerSession{Player: p})
|
||||
}
|
||||
|
||||
sse := datastar.NewSSE(w, r)
|
||||
@@ -284,7 +284,7 @@ func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.Handl
|
||||
}
|
||||
}
|
||||
|
||||
func HandleRematch(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
|
||||
func HandleRematch(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
gameID := chi.URLParam(r, "id")
|
||||
|
||||
@@ -304,7 +304,7 @@ func HandleRematch(store *game.GameStore, sm *scs.SessionManager) http.HandlerFu
|
||||
}
|
||||
|
||||
// sendGameComponents patches all game-related SSE components.
|
||||
func sendGameComponents(sse *datastar.ServerSentEventGenerator, gi *game.GameInstance, myColor int, room *chat.Room, chatCfg chatcomponents.Config) {
|
||||
func sendGameComponents(sse *datastar.ServerSentEventGenerator, gi *connect4.Instance, myColor int, room *chat.Room, chatCfg chatcomponents.Config) {
|
||||
g := gi.GetGame()
|
||||
|
||||
sse.PatchElementTempl(components.Board(g, myColor), datastar.WithSelectorID("c4-board")) //nolint:errcheck
|
||||
|
||||
@@ -3,14 +3,14 @@ package pages
|
||||
import (
|
||||
"github.com/ryanhamamura/c4/chat"
|
||||
chatcomponents "github.com/ryanhamamura/c4/chat/components"
|
||||
"github.com/ryanhamamura/c4/connect4"
|
||||
"github.com/ryanhamamura/c4/features/c4game/components"
|
||||
sharedcomponents "github.com/ryanhamamura/c4/features/common/components"
|
||||
"github.com/ryanhamamura/c4/features/common/layouts"
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
"github.com/starfederation/datastar-go/datastar"
|
||||
)
|
||||
|
||||
templ GamePage(g *game.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
|
||||
templ GamePage(g *connect4.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
|
||||
@layouts.Base("Connect 4") {
|
||||
<main
|
||||
class="flex flex-col items-center gap-4 p-4"
|
||||
@@ -25,7 +25,7 @@ templ GamePage(g *game.Game, myColor int, messages []chat.Message, chatCfg chatc
|
||||
@components.Board(g, myColor)
|
||||
@chatcomponents.Chat(messages, chatCfg)
|
||||
</div>
|
||||
if g.Status == game.StatusWaitingForPlayer {
|
||||
if g.Status == connect4.StatusWaitingForPlayer {
|
||||
@components.InviteLink(g.ID)
|
||||
}
|
||||
</main>
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"github.com/ryanhamamura/c4/connect4"
|
||||
"github.com/ryanhamamura/c4/db/repository"
|
||||
"github.com/ryanhamamura/c4/game"
|
||||
)
|
||||
|
||||
func SetupRoutes(
|
||||
router chi.Router,
|
||||
store *game.GameStore,
|
||||
store *connect4.Store,
|
||||
nc *nats.Conn,
|
||||
sessions *scs.SessionManager,
|
||||
queries *repository.Queries,
|
||||
|
||||
Reference in New Issue
Block a user