aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/game/game.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/game/game.go')
-rw-r--r--backend/game/game.go385
1 files changed, 0 insertions, 385 deletions
diff --git a/backend/game/game.go b/backend/game/game.go
deleted file mode 100644
index 9e63a1e..0000000
--- a/backend/game/game.go
+++ /dev/null
@@ -1,385 +0,0 @@
-package game
-
-import (
- "context"
- "log"
- "time"
-
- "github.com/gorilla/websocket"
-
- "github.com/nsfisis/iosdc-2024-albatross/backend/api"
- "github.com/nsfisis/iosdc-2024-albatross/backend/db"
-)
-
-type gameState = api.GameState
-
-const (
- gameStateClosed gameState = api.Closed
- gameStateWaitingEntries gameState = api.WaitingEntries
- gameStateWaitingStart gameState = api.WaitingStart
- gameStatePrepare gameState = api.Prepare
- gameStateStarting gameState = api.Starting
- gameStateGaming gameState = api.Gaming
- gameStateFinished gameState = api.Finished
-)
-
-type game struct {
- gameID int
- state string
- displayName string
- durationSeconds int
- startedAt *time.Time
- problem *problem
-}
-
-type problem struct {
- problemID int
- title string
- description string
-}
-
-// func startGame(game *Game) {
-// if gameHubs[game.GameID] != nil {
-// return
-// }
-// gameHubs[game.GameID] = NewGameHub(game)
-// go gameHubs[game.GameID].Run()
-// }
-
-/*
-func handleGolfPost(w http.ResponseWriter, r *http.Request) {
- var yourTeam string
- waitingGolfGames := []Game{}
- err := db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting)
- if err != nil {
- http.Error(w, "Error getting games", http.StatusInternalServerError)
- return
- }
- if len(waitingGolfGames) == 0 {
- _, err = db.Exec("INSERT INTO games (type, state) VALUES ($1, $2)", gameTypeGolf, gameStateWaiting)
- if err != nil {
- http.Error(w, "Error creating game", http.StatusInternalServerError)
- return
- }
- waitingGolfGames = []Game{}
- err = db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting)
- if err != nil {
- http.Error(w, "Error getting games", http.StatusInternalServerError)
- return
- }
- yourTeam = "a"
- startGame(&waitingGolfGames[0])
- } else {
- yourTeam = "b"
- db.Exec("UPDATE games SET state = $1 WHERE game_id = $2", gameStateReady, waitingGolfGames[0].GameID)
- }
- waitingGame := waitingGolfGames[0]
-
- http.Redirect(w, r, fmt.Sprintf("/golf/%d/%s/", waitingGame.GameID, yourTeam), http.StatusSeeOther)
-}
-*/
-
-type GameHub struct {
- game *game
- clients map[*GameClient]bool
- receive chan *MessageWithClient
- register chan *GameClient
- unregister chan *GameClient
- watchers map[*GameWatcher]bool
- registerWatcher chan *GameWatcher
- unregisterWatcher chan *GameWatcher
- state int
- finishTime time.Time
-}
-
-func NewGameHub(game *game) *GameHub {
- return &GameHub{
- game: game,
- clients: make(map[*GameClient]bool),
- receive: make(chan *MessageWithClient),
- register: make(chan *GameClient),
- unregister: make(chan *GameClient),
- watchers: make(map[*GameWatcher]bool),
- registerWatcher: make(chan *GameWatcher),
- unregisterWatcher: make(chan *GameWatcher),
- state: 0,
- }
-}
-
-func (h *GameHub) Run() {
- ticker := time.NewTicker(10 * time.Second)
- defer func() {
- ticker.Stop()
- }()
-
- for {
- select {
- case client := <-h.register:
- h.clients[client] = true
- log.Printf("client registered: %d", len(h.clients))
- case client := <-h.unregister:
- if _, ok := h.clients[client]; ok {
- h.closeClient(client)
- }
- log.Printf("client unregistered: %d", len(h.clients))
- if len(h.clients) == 0 {
- h.Close()
- return
- }
- case watcher := <-h.registerWatcher:
- h.watchers[watcher] = true
- log.Printf("watcher registered: %d", len(h.watchers))
- case watcher := <-h.unregisterWatcher:
- if _, ok := h.watchers[watcher]; ok {
- h.closeWatcher(watcher)
- }
- log.Printf("watcher unregistered: %d", len(h.watchers))
- case message := <-h.receive:
- log.Printf("received message: %s", message.Message.Type)
- switch message.Message.Type {
- case "connect":
- if h.state == 0 {
- h.state = 1
- } else if h.state == 1 {
- h.state = 2
- for client := range h.clients {
- client.send <- &Message{Type: "prepare", Data: MessageDataPrepare{Problem: "1 から 100 までの FizzBuzz を実装せよ (終端を含む)。"}}
- }
- } else {
- log.Printf("invalid state: %d", h.state)
- h.closeClient(message.Client)
- }
- case "ready":
- if h.state == 2 {
- h.state = 3
- } else if h.state == 3 {
- h.state = 4
- for client := range h.clients {
- client.send <- &Message{Type: "start", Data: MessageDataStart{StartTime: time.Now().Add(10 * time.Second).UTC().Format(time.RFC3339)}}
- }
- h.finishTime = time.Now().Add(3 * time.Minute)
- } else {
- log.Printf("invalid state: %d", h.state)
- h.closeClient(message.Client)
- }
- case "code":
- if h.state == 4 {
- code := message.Message.Data.(MessageDataCode).Code
- message.Client.code = code
- message.Client.send <- &Message{Type: "score", Data: MessageDataScore{Score: 100}}
- if message.Client.score == nil {
- message.Client.score = new(int)
- }
- *message.Client.score = 100
-
- var scoreA, scoreB *int
- var codeA, codeB string
- for client := range h.clients {
- if client.team == "a" {
- scoreA = client.score
- codeA = client.code
- } else {
- scoreB = client.score
- codeB = client.code
- }
- }
- for watcher := range h.watchers {
- watcher.send <- &Message{
- Type: "watch",
- Data: MessageDataWatch{
- Problem: "1 から 100 までの FizzBuzz を実装せよ (終端を含む)。",
- ScoreA: scoreA,
- CodeA: codeA,
- ScoreB: scoreB,
- CodeB: codeB,
- },
- }
- }
- } else {
- log.Printf("invalid state: %d", h.state)
- h.closeClient(message.Client)
- }
- default:
- log.Printf("unknown message type: %s", message.Message.Type)
- h.closeClient(message.Client)
- }
- case <-ticker.C:
- log.Printf("state: %d", h.state)
- if h.state == 4 {
- if time.Now().After(h.finishTime) {
- h.state = 5
- clientAndScores := make(map[*GameClient]*int)
- for client := range h.clients {
- clientAndScores[client] = client.score
- }
- for client, score := range clientAndScores {
- var opponentScore *int
- for c2, s2 := range clientAndScores {
- if c2 != client {
- opponentScore = s2
- break
- }
- }
- client.send <- &Message{Type: "finish", Data: MessageDataFinish{YourScore: score, OpponentScore: opponentScore}}
- }
- }
- }
- }
- }
-}
-
-func (h *GameHub) Close() {
- for client := range h.clients {
- h.closeClient(client)
- }
- close(h.receive)
- close(h.register)
- close(h.unregister)
- for watcher := range h.watchers {
- h.closeWatcher(watcher)
- }
- close(h.registerWatcher)
- close(h.unregisterWatcher)
-}
-
-func (h *GameHub) closeClient(client *GameClient) {
- delete(h.clients, client)
- close(client.send)
-}
-
-func (h *GameHub) closeWatcher(watcher *GameWatcher) {
- delete(h.watchers, watcher)
- close(watcher.send)
-}
-
-type GameClient struct {
- hub *GameHub
- conn *websocket.Conn
- send chan *Message
- score *int
- code string
- team string
-}
-
-type GameWatcher struct {
- hub *GameHub
- conn *websocket.Conn
- send chan *Message
-}
-
-// Receives messages from the client and sends them to the hub.
-func (c *GameClient) readPump() {
- defer func() {
- log.Printf("closing client")
- c.hub.unregister <- c
- c.conn.Close()
- }()
- c.conn.SetReadLimit(maxMessageSize)
- c.conn.SetReadDeadline(time.Now().Add(pongWait))
- c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
- for {
- var message Message
- err := c.conn.ReadJSON(&message)
- if err != nil {
- log.Printf("error: %v", err)
- return
- }
- c.hub.receive <- &MessageWithClient{c, &message}
- }
-}
-
-// Receives messages from the hub and sends them to the client.
-func (c *GameClient) writePump() {
- ticker := time.NewTicker(pingPeriod)
- defer func() {
- ticker.Stop()
- c.conn.Close()
- }()
- for {
- select {
- case message, ok := <-c.send:
- c.conn.SetWriteDeadline(time.Now().Add(writeWait))
- if !ok {
- c.conn.WriteMessage(websocket.CloseMessage, []byte{})
- return
- }
-
- err := c.conn.WriteJSON(message)
- if err != nil {
- return
- }
- case <-ticker.C:
- c.conn.SetWriteDeadline(time.Now().Add(writeWait))
- if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
- return
- }
- }
- }
-}
-
-// Receives messages from the client and sends them to the hub.
-func (c *GameWatcher) readPump() {
- c.conn.SetReadLimit(maxMessageSize)
- c.conn.SetReadDeadline(time.Now().Add(pongWait))
- c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
-}
-
-// Receives messages from the hub and sends them to the client.
-func (c *GameWatcher) writePump() {
- ticker := time.NewTicker(pingPeriod)
- defer func() {
- ticker.Stop()
- c.conn.Close()
- log.Printf("closing watcher")
- c.hub.unregisterWatcher <- c
- }()
- for {
- select {
- case message, ok := <-c.send:
- c.conn.SetWriteDeadline(time.Now().Add(writeWait))
- if !ok {
- c.conn.WriteMessage(websocket.CloseMessage, []byte{})
- return
- }
-
- err := c.conn.WriteJSON(message)
- if err != nil {
- return
- }
- case <-ticker.C:
- c.conn.SetWriteDeadline(time.Now().Add(writeWait))
- if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
- return
- }
- }
- }
-}
-
-type GameHubs struct {
- hubs map[int]*GameHub
-}
-
-func NewGameHubs() *GameHubs {
- return &GameHubs{
- hubs: make(map[int]*GameHub),
- }
-}
-
-func (hubs *GameHubs) Close() {
- for _, hub := range hubs.hubs {
- hub.Close()
- }
-}
-
-func (hubs *GameHubs) RestoreFromDB(ctx context.Context, q *db.Queries) error {
- games, err := q.ListGames(ctx)
- if err != nil {
- return err
- }
- _ = games
- return nil
-}
-
-func (hubs *GameHubs) SockHandler() *sockHandler {
- return newSockHandler(hubs)
-}