Skip to content

Commit

Permalink
Adds /defaultGame and /doAction API calls.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mariano Gappa committed Dec 28, 2019
1 parent 6f6ff6a commit 66891ab
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 26 deletions.
92 changes: 78 additions & 14 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,45 @@ package api

import (
"fmt"
"strings"
)

// // Cli
// // Server
// // Library

type API struct{}

func New() API { return API{} }

// func (a API) DoAction(game InputGame, action InputAction, options DoActionInputOptions) (OutputGame, OutputAction, error) {

// }

// func (a API) DefaultGame(options DefaultGameInputOptions) (OutputGame, error) {

// }
var (
errInvalidInputGame = fmt.Errorf("invalid input game: please supply a valid fenString or a board")
errInvalidInputGame = fmt.Errorf("invalid input game: please supply a valid fenString or a board")
errAlgebraicSquareInvalidOrOutOfBounds = fmt.Errorf("invalid algebraic square: empty or out of bounds")
errInvalidPieceTypeName = fmt.Errorf("invalid piece type name: please use one of {Queen|King|Bishop|Knight|Rook|Pawn} or empty string")
errInvalidActionForGivenGame = fmt.Errorf("the specified action is invalid for the specified game")
)

func (a API) DefaultGame() OutputGame {
return mapGameToOutputGame(defaultGame)
}

func (a API) ParseGame(g InputGame) (OutputGame, error) {
parsedGame, err := a.parseGame(g)
if err != nil {
return OutputGame{}, err
}
return mapGameToOutputGame(parsedGame), nil
}

func (a API) DoAction(game InputGame, action InputAction) (OutputGame, OutputAction, error) {
parsedGame, err := a.parseGame(game)
if err != nil {
return OutputGame{}, OutputAction{}, err
}
parsedAction, err := a.parseAction(action, parsedGame)
if err != nil {
return OutputGame{}, OutputAction{}, err
}
return mapGameToOutputGame(parsedGame.doAction(parsedAction)), mapInternalActionToAction(parsedAction), nil
}

func (a API) parseGame(g InputGame) (game, error) {
var (
parsedGame game
err error
Expand All @@ -37,8 +54,55 @@ func (a API) ParseGame(g InputGame) (OutputGame, error) {
err = errInvalidInputGame
}
if err != nil {
return OutputGame{}, err
return game{}, err
}
return parsedGame, nil
}

return mapGameToOutputGame(parsedGame), nil
func (a API) parseAction(ia InputAction, g game) (action, error) {
fromXY, err := a.algebraicToXY(strings.ToLower(ia.FromSquare))
if err != nil {
return action{}, err
}
toXY, err := a.algebraicToXY(strings.ToLower(ia.ToSquare))
if err != nil {
return action{}, err
}
promotePieceType, err := a.stringToPieceType(ia.PromotePieceType)
if err != nil {
return action{}, err
}

for _, action := range g.actions {
if action.fromPiece.xy != fromXY || action.toXY != toXY || (action.isPromotion && action.promotionPieceType != promotePieceType) {
continue
}
return action, nil
}

return action{}, errInvalidActionForGivenGame
}

func (a API) algebraicToXY(sq string) (xy, error) {
if len(sq) != 2 || sq[0] < 'a' || sq[0] > 'h' || sq[1] < '1' || sq[1] > '8' {
return xy{}, errAlgebraicSquareInvalidOrOutOfBounds
}
return xy{int(sq[0] - 'a'), int('8' - sq[1])}, nil
}

func (a API) stringToPieceType(s string) (pieceType, error) {
m := map[string]pieceType{
"Queen": pieceQueen,
"King": pieceKing,
"Bishop": pieceBishop,
"Knight": pieceKnight,
"Rook": pieceRook,
"Pawn": piecePawn,
"": pieceNone,
}
pt, ok := m[s]
if !ok {
return pieceNone, errInvalidPieceTypeName
}
return pt, nil
}
16 changes: 7 additions & 9 deletions api/api_entities.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package api

type InputGame struct {
FENString string
Board Board
FENString string `json:"fenString"`
Board Board `json:"board"`
}

// type InputAction struct {
// ActionType ActionType
// Action string
// }
type InputAction struct {
FromSquare string `json:"fromSquare"`
ToSquare string `json:"toSquare"`
PromotePieceType string `json:"promotePieceType"`
}

type Board struct {
Board []string `json:"board"`
Expand Down Expand Up @@ -67,9 +68,6 @@ type OutputAction struct {
CapturedPieceType string `json:"capturedPieceType"`
}

// type OutputGameSteps struct {
// }

func mapGameToOutputGame(g game) OutputGame {
var o OutputGame

Expand Down
67 changes: 64 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,41 @@ import (
)

var (
flagServe = flag.Int("serve", 0, "Start a server on the specified port.")
flagParseGame = flag.String("parseGame", "", "ParseGame api call. Requires a JSON string with arguments. Please review spec.")
a = api.New()
flagServe = flag.Int("serve", 0, "Start a server on the specified port.")
flagDefaultGame = flag.Bool("defaultGame", false, "Default API call. Returns a default game.")
flagParseGame = flag.String("parseGame", "", "ParseGame API call. Requires a JSON string with arguments. Please review spec.")
flagDoAction = flag.String("doAction", "", "DoAction API call. Requires a JSON string with arguments. Please review spec.")
a = api.New()
)

// api.InputGame{FENString: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"},

func main() {
flag.Parse()
http.HandleFunc("/parseGame", handleServerParseGame)
http.HandleFunc("/defaultGame", handleServerDefaultGame)
http.HandleFunc("/doAction", handleServerDoAction)
switch {
case *flagServe != 0:
http.ListenAndServe(fmt.Sprintf(":%v", *flagServe), nil)
case *flagDefaultGame:
handleCliDefaultGame()
case *flagParseGame != "":
handleCliParseGame(flagParseGame)
case *flagDoAction != "":
handleCliDoAction(flagDoAction)
}
}

func handleServerDefaultGame(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(a.DefaultGame())
}

func handleCliDefaultGame() {
byts, _ := json.Marshal(a.DefaultGame())
fmt.Println(string(byts))
}

func handleServerParseGame(w http.ResponseWriter, r *http.Request) {
var ig api.InputGame
if err := json.NewDecoder(r.Body).Decode(&ig); err != nil {
Expand Down Expand Up @@ -57,6 +74,50 @@ func handleCliParseGame(flagParseGame *string) {
fmt.Println(string(byts))
}

func handleServerDoAction(w http.ResponseWriter, r *http.Request) {
type args struct {
Game api.InputGame `json:"game"`
Action api.InputAction `json:"action"`
}
var input args
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
fmt.Fprintln(w, formatError(err))
return
}
defer r.Body.Close()
outputGame, outputAction, err := a.DoAction(input.Game, input.Action)
if err != nil {
fmt.Fprintln(w, formatError(err))
return
}
type out struct {
Game api.OutputGame `json:"game"`
Action api.OutputAction `json:"action"`
}
json.NewEncoder(w).Encode(out{outputGame, outputAction})
}

func handleCliDoAction(flagDoAction *string) {
type args struct {
Game api.InputGame `json:"game"`
Action api.InputAction `json:"action"`
}
var input args
if err := json.Unmarshal([]byte(*flagDoAction), &input); err != nil {
mustCliFatal(err)
}
outputGame, outputAction, err := a.DoAction(input.Game, input.Action)
if err != nil {
mustCliFatal(err)
}
type out struct {
Game api.OutputGame `json:"game"`
Action api.OutputAction `json:"action"`
}
byts, _ := json.Marshal(out{outputGame, outputAction})
fmt.Println(string(byts))
}

func mustCliFatal(err error) {
fmt.Println(formatError(err))
os.Exit(1)
Expand Down

0 comments on commit 66891ab

Please sign in to comment.