From 245c483f9e6371a3f73a46e30dc0e0fcd034509f Mon Sep 17 00:00:00 2001 From: Stephen McQuay Date: Wed, 13 Nov 2013 23:45:02 -0800 Subject: [PATCH] added simple game stats --- control.go | 55 +++++++++++++++++++++++++++++++++++++++++++++-------- game.go | 49 +++++++++++++++++++++++++++++------------------ main.go | 3 ++- protocol.go | 6 ++++-- 4 files changed, 84 insertions(+), 29 deletions(-) diff --git a/control.go b/control.go index 432497c..efc0465 100644 --- a/control.go +++ b/control.go @@ -2,6 +2,8 @@ package main import ( "encoding/json" + "errors" + "fmt" "io/ioutil" "log" "net/http" @@ -105,23 +107,49 @@ func listGames(w http.ResponseWriter, req *http.Request) { } } -func stopGame(w http.ResponseWriter, req *http.Request) { - trimmed := strings.Trim(req.URL.Path, "/") - fullPath := strings.Split(trimmed, "/") - log.Println(req.URL.Path) - if len(fullPath) != 3 { +func gameStats(w http.ResponseWriter, req *http.Request) { + key, err := getGameId(req.URL.Path) + if err != nil { http.Error(w, "improperly formed url", http.StatusBadRequest) + } + log.Printf("requested stats for game: %s", key) + games.RLock() + g, ok := games.m[key] + games.RUnlock() + if !ok { + http.NotFound(w, req) return } - key := fullPath[2] + g.winners.RLock() + defer g.winners.RUnlock() + if err := json.NewEncoder(w).Encode(g.winners.m); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func stopGame(w http.ResponseWriter, req *http.Request) { + key, err := getGameId(req.URL.Path) + if err != nil { + http.Error(w, "improperly formed url", http.StatusBadRequest) + } games.Lock() - gameid, ok := games.m[key] + g, ok := games.m[key] defer games.Unlock() if !ok { http.NotFound(w, req) return } - gameid.kill <- true + g.kill <- true + message := struct { + Ok bool `json:"ok"` + Message string `json:"message"` + }{ + Ok: true, + Message: fmt.Sprintf("Successfully stopped game: %s", key), + } + if err := json.NewEncoder(w).Encode(message); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } } func killServer(w http.ResponseWriter, req *http.Request) { @@ -146,3 +174,14 @@ func index(w http.ResponseWriter, req *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) } } + +func getGameId(path string) (string, error) { + var err error + trimmed := strings.Trim(path, "/") + fullPath := strings.Split(trimmed, "/") + if len(fullPath) != 3 { + return "", errors.New("improperly formed url") + } + key := fullPath[2] + return key, err +} diff --git a/game.go b/game.go index 8edb31d..7cf264f 100644 --- a/game.go +++ b/game.go @@ -40,6 +40,11 @@ func (ml *MapLock) add(g *game) { ml.Unlock() } +type WinnerMap struct { + m map[string]int + sync.RWMutex +} + type game struct { id string players map[*player]bool @@ -58,27 +63,30 @@ type game struct { repair_hp int repair_rate float32 tick_duration int + winners WinnerMap } func NewGame(id string, width, height float32, tick int) *game { g := &game{ - id: id, - register: make(chan *player), - unregister: make(chan *player, maxPlayer), - projectiles: make(map[*Projectile]bool), - splosions: make(map[*Splosion]bool), - obstacles: GenerateObstacles(conf.Obstacles, width, height), - players: make(map[*player]bool), - turn: 0, - width: width, - height: height, - spectators: make(map[*Spectator]bool), - sregister: make(chan *Spectator), - sunregister: make(chan *Spectator), - kill: make(chan bool, maxPlayer), - repair_hp: 5, - repair_rate: 3.0, - tick_duration: tick, + id: id, + register: make(chan *player), + unregister: make(chan *player, maxPlayer), + projectiles: make(map[*Projectile]bool), + splosions: make(map[*Splosion]bool), + obstacles: GenerateObstacles(conf.Obstacles, width, height), + players: make(map[*player]bool), + turn: 0, + width: width, + height: height, + spectators: make(map[*Spectator]bool), + sregister: make(chan *Spectator), + sunregister: make(chan *Spectator), + kill: make(chan bool, maxPlayer), + repair_hp: 5, + repair_rate: 3.0, + tick_duration: tick, + players_remaining: 2, + winners: WinnerMap{m: make(map[string]int)}, } return g } @@ -284,16 +292,21 @@ func (g *game) run() { func (g *game) gameOver() (bool, *GameOver) { over := false - stats := NewGameOver() + var stats *GameOver if g.players_remaining <= 1 && len(g.players) > 1 { g.obstacles = GenerateObstacles(conf.Obstacles, g.width, g.height) log.Printf("game %s: game over", g.id) + stats = NewGameOver() for p := range g.players { for _, r := range p.Robots { if r.Health > 0 { log.Printf("Robot %v Survived", r.Id) + g.winners.Lock() + g.winners.m[r.Id] += 1 + g.winners.Unlock() + stats.Winners = append(stats.Winners, r.Id) } r.reset(g) } diff --git a/main.go b/main.go index 58ddeb6..37bbd7c 100644 --- a/main.go +++ b/main.go @@ -63,7 +63,8 @@ func main() { sm.Handle("/ws/", websocket.Handler(addPlayer)) sm.Handle("/game/start/", JsonHandler(startGame)) sm.Handle("/game/list/", JsonHandler(listGames)) - sm.HandleFunc("/game/stop/", stopGame) + sm.Handle("/game/stats/", JsonHandler(gameStats)) + sm.Handle("/game/stop/", JsonHandler(stopGame)) sm.HandleFunc("/fuck/shit/up/", killServer) err = http.ListenAndServe(*addr, sm) diff --git a/protocol.go b/protocol.go index 883578c..00c6b8d 100644 --- a/protocol.go +++ b/protocol.go @@ -128,12 +128,14 @@ func NewBoardstate() *Boardstate { } type GameOver struct { - Type string `json:"type"` + Winners []string `json:"winners"` + Type string `json:"type"` } func NewGameOver() *GameOver { return &GameOver{ - Type: "gameover", + Type: "gameover", + Winners: make([]string, 0), } }