2022-03-03 13:28:00 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2022-03-07 15:04:13 -05:00
|
|
|
"log"
|
2022-03-03 13:28:00 -05:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
|
|
|
//API represents the api
|
|
|
|
type API struct {
|
|
|
|
games map[int]*Session
|
|
|
|
nextInt int
|
|
|
|
}
|
|
|
|
|
|
|
|
//NewAPI creates new API instance
|
|
|
|
func NewAPI() *API {
|
|
|
|
return &API{
|
|
|
|
games: make(map[int]*Session),
|
|
|
|
nextInt: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-07 14:47:35 -05:00
|
|
|
//NewGame takes a POST and creates a new game or returns an open one
|
2022-03-03 13:28:00 -05:00
|
|
|
func (a *API) NewGame(res http.ResponseWriter, req *http.Request) {
|
2022-03-07 14:47:35 -05:00
|
|
|
for i, g := range a.games {
|
|
|
|
if !g.redPlayer.Ready {
|
2022-03-07 15:04:13 -05:00
|
|
|
log.Println("red player somehow not ready")
|
2022-03-07 14:47:35 -05:00
|
|
|
g.redPlayer.Ready = true
|
|
|
|
if g.bluePlayer.Ready {
|
|
|
|
g.simulator.Setup()
|
|
|
|
initDummy(g.simulator)
|
2022-03-07 15:21:37 -05:00
|
|
|
log.Println("dummy game started")
|
2022-03-07 14:47:35 -05:00
|
|
|
}
|
|
|
|
respondWithJSON(res, http.StatusOK, newGameResp{i, "red"})
|
2022-03-07 14:49:02 -05:00
|
|
|
return
|
2022-03-07 14:47:35 -05:00
|
|
|
}
|
|
|
|
if !g.bluePlayer.Ready {
|
|
|
|
g.bluePlayer.Ready = true
|
|
|
|
if g.redPlayer.Ready {
|
|
|
|
g.simulator.Setup()
|
|
|
|
initDummy(g.simulator)
|
2022-03-07 15:21:37 -05:00
|
|
|
log.Println("dummy game started")
|
2022-03-07 14:47:35 -05:00
|
|
|
}
|
|
|
|
respondWithJSON(res, http.StatusOK, newGameResp{i, "blue"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2022-03-07 15:04:13 -05:00
|
|
|
log.Printf("creating new game %v", a.nextInt)
|
2022-03-03 13:28:00 -05:00
|
|
|
a.games[a.nextInt] = NewSession()
|
2022-03-07 15:04:13 -05:00
|
|
|
a.games[a.nextInt].redPlayer.Ready = true
|
2022-03-03 13:28:00 -05:00
|
|
|
respondWithJSON(res, http.StatusOK, newGameResp{a.nextInt, "red"})
|
|
|
|
a.nextInt = a.nextInt + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
//GetGame returns current state of game, filtered accordingly
|
|
|
|
func (a *API) GetGame(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 gameReq
|
|
|
|
decoder := json.NewDecoder(req.Body)
|
|
|
|
if err := decoder.Decode(&gr); err != nil {
|
2022-03-07 15:04:13 -05:00
|
|
|
log.Println(err)
|
|
|
|
respondWithError(res, http.StatusBadRequest, "Invalid request payload")
|
2022-03-03 13:28:00 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
defer req.Body.Close()
|
|
|
|
if gr.PlayerID != "red" && gr.PlayerID != "blue" {
|
|
|
|
respondWithError(res, http.StatusBadRequest, "Bad player ID")
|
|
|
|
return
|
|
|
|
}
|
2022-03-07 16:14:30 -05:00
|
|
|
var p *Player
|
|
|
|
|
2022-03-03 13:28:00 -05:00
|
|
|
s, isset := a.games[id]
|
|
|
|
if !isset {
|
|
|
|
respondWithError(res, http.StatusBadRequest, "No such game")
|
|
|
|
return
|
|
|
|
}
|
2022-03-07 16:14:30 -05:00
|
|
|
if gr.PlayerID == "red" {
|
|
|
|
p = s.redPlayer
|
|
|
|
} else {
|
|
|
|
p = s.bluePlayer
|
|
|
|
}
|
|
|
|
|
2022-03-07 15:21:37 -05:00
|
|
|
log.Println("sending game state")
|
2022-03-07 16:14:30 -05:00
|
|
|
respondWithJSON(res, http.StatusOK, gameResp{s.getBoard(p)})
|
2022-03-03 13:28:00 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//GetGameStatus returns current game status and turn number
|
|
|
|
func (a *API) GetGameStatus(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 gameReq
|
|
|
|
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
|
|
|
|
}
|
|
|
|
s, isset := a.games[id]
|
|
|
|
if !isset {
|
|
|
|
respondWithError(res, http.StatusBadRequest, "No such game")
|
|
|
|
return
|
|
|
|
}
|
2022-03-07 15:21:37 -05:00
|
|
|
log.Println("sending game status")
|
2022-03-03 13:28:00 -05:00
|
|
|
respondWithJSON(res, http.StatusOK, gameStatusResp{s.simulator.State, s.moveNum})
|
|
|
|
}
|
2022-03-07 14:47:21 -05:00
|
|
|
|
|
|
|
//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 {
|
2022-03-07 15:21:37 -05:00
|
|
|
respondWithError(res, http.StatusBadRequest, err.Error())
|
2022-03-07 14:47:21 -05:00
|
|
|
|
2022-03-07 15:21:37 -05:00
|
|
|
}
|
|
|
|
result, err := s.mutate(parsed)
|
|
|
|
if err != nil {
|
|
|
|
respondWithError(res, http.StatusBadRequest, err.Error())
|
|
|
|
}
|
|
|
|
if result == "" {
|
|
|
|
respondWithJSON(res, http.StatusOK, gameMovePostRes{true, false, "", err})
|
|
|
|
}
|
|
|
|
respondWithJSON(res, http.StatusOK, gameMovePostRes{true, true, result, err})
|
2022-03-07 14:47:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//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
|
|
|
|
}
|
2022-03-07 15:21:37 -05:00
|
|
|
move, err := strconv.Atoi(vars["movenum"])
|
2022-03-07 14:47:21 -05:00
|
|
|
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})
|
|
|
|
}
|