From 06e21750213ba3e1d4de15f50499f99ac6bc6fcf Mon Sep 17 00:00:00 2001 From: Steve Date: Mon, 7 Mar 2022 14:47:21 -0500 Subject: [PATCH] session skeleton up --- api.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ api_types.go | 20 +++++++++++++ session.go | 73 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 167 insertions(+), 9 deletions(-) diff --git a/api.go b/api.go index 7a55036..3412246 100644 --- a/api.go +++ b/api.go @@ -53,6 +53,7 @@ func (a *API) GetGame(res http.ResponseWriter, req *http.Request) { respondWithError(res, http.StatusBadRequest, "No such game") return } + //TODO filter based off player info respondWithJSON(res, http.StatusOK, gameResp{s.simulator}) return } @@ -83,3 +84,85 @@ func (a *API) GetGameStatus(res http.ResponseWriter, req *http.Request) { } respondWithJSON(res, http.StatusOK, gameStatusResp{s.simulator.State, s.moveNum}) } + +//PostMove attempts to make a game move +func (a *API) PostMove(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid game ID") + return + } + var gr gameMovePostReq + decoder := json.NewDecoder(req.Body) + if err := decoder.Decode(&gr); err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid resquest payload") + return + } + defer req.Body.Close() + if gr.PlayerID != "red" && gr.PlayerID != "blue" { + respondWithError(res, http.StatusBadRequest, "Bad player ID") + return + } + var p *Player + + s, isset := a.games[id] + if !isset { + respondWithError(res, http.StatusBadRequest, "No such game") + return + } + if gr.PlayerID == "red" { + p = s.redPlayer + } else { + p = s.bluePlayer + } + parsed, err := s.tryMove(p, gr.Move) + if err != nil { + respondWithJSON(res, http.StatusOK, gameMovePostRes{false, false, parsed.String(), err}) + } + +} + +//GetMove returns the move made at turn X +func (a *API) GetMove(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid game ID") + return + } + move, err := strconv.Atoi(vars["move_number"]) + if err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid move number") + return + } + var gr gameMoveReq + decoder := json.NewDecoder(req.Body) + if err := decoder.Decode(&gr); err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid resquest payload") + return + } + defer req.Body.Close() + if gr.PlayerID != "red" && gr.PlayerID != "blue" { + respondWithError(res, http.StatusBadRequest, "Bad player ID") + return + } + var p *Player + + s, isset := a.games[id] + if !isset { + respondWithError(res, http.StatusBadRequest, "No such game") + return + } + if gr.PlayerID == "red" { + p = s.redPlayer + } else { + p = s.bluePlayer + } + moveRes, err := s.getMove(p, move) + if err != nil { + respondWithError(res, http.StatusBadRequest, "No such move") + return + } + respondWithJSON(res, http.StatusOK, gameMoveRes{moveRes}) +} diff --git a/api_types.go b/api_types.go index 6cfe3f6..67b9508 100644 --- a/api_types.go +++ b/api_types.go @@ -25,3 +25,23 @@ type gameStatusResp struct { GameStatus freego.GameState `json:"game_status"` Move int `json:"move"` } + +type gameMovePostReq struct { + PlayerID string `json:"player_id"` + Move string `json:"move"` +} + +type gameMovePostRes struct { + Valid bool `json:"valid"` + Result bool `json:"result"` + Parsed string `json:"parsed"` + Error error `json:"error"` +} + +type gameMoveReq struct { + PlayerID string `json:"player_id"` +} + +type gameMoveRes struct { + Move string `json:"move"` +} diff --git a/session.go b/session.go index c81e2b7..69b2f45 100644 --- a/session.go +++ b/session.go @@ -1,21 +1,76 @@ package main -import "git.saintnet.tech/stryan/freego" +import ( + "errors" + "fmt" + + "git.saintnet.tech/stryan/freego" +) //Session represents an active game type Session struct { - simulator *freego.Game - redReady bool - blueReady bool - moveNum int + simulator *freego.Game + redPlayer *Player + bluePlayer *Player + moveNum int + moveList []freego.ParsedCommand +} + +//Player is a player in a match +type Player struct { + Ready bool + Team freego.Colour +} + +//ID returns player ID +func (p *Player) ID() int { + panic("not implemented") // TODO: Implement +} + +//Colour returns player team +func (p *Player) Colour() freego.Colour { + return p.Team } //NewSession creates a new game session func NewSession() *Session { return &Session{ - simulator: freego.NewGame(), - redReady: false, - blueReady: false, - moveNum: 0, + simulator: freego.NewGame(), + redPlayer: &Player{false, freego.Red}, + bluePlayer: &Player{false, freego.Blue}, + moveNum: 0, + moveList: []freego.ParsedCommand{}, } } + +func (s *Session) tryMove(player *Player, move string) (*freego.ParsedCommand, error) { + raw, err := freego.NewRawCommand(move) + if err != nil { + return nil, err + } + p, err := s.simulator.Parse(player, raw) + if err != nil { + return nil, err + } + return p, nil +} + +func (s *Session) mutate(p *freego.ParsedCommand) error { + success, err := s.simulator.Mutate(p) + if err != nil { + return err + } + if !success { + return errors.New("invalid move") + } + s.moveList[s.moveNum] = *p + s.moveNum++ + return nil +} + +func (s *Session) getMove(p *Player, num int) (string, error) { + if num < 0 || num > s.moveNum { + return "", errors.New("invalid move number") + } + return fmt.Sprintf("%v %v", num, s.moveList[num].String()), nil +}