Skip to content

Commit

Permalink
Implements support for WebAssembly compilation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mariano Gappa committed Mar 17, 2020
1 parent d6a43f2 commit 2d761db
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
cheesse
poc
6 changes: 3 additions & 3 deletions api/api_entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ type InputGame struct {
}

type InputAction struct {
FromSquare string `json:"fromSquare"`
ToSquare string `json:"toSquare"`
PromotePieceType string `json:"promotePieceType"`
FromSquare string `json:"fromSquare"`
ToSquare string `json:"toSquare"`
PromotionPieceType string `json:"promotionPieceType"`
}

type Board struct {
Expand Down
4 changes: 2 additions & 2 deletions api/api_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ func (a API) parseAction(ia InputAction, g game) (action, error) {
if err != nil {
return action{}, err
}
promotePieceType, err := a.stringToPieceType(ia.PromotePieceType)
promotionPieceType, err := a.stringToPieceType(ia.PromotionPieceType)
if err != nil {
return action{}, err
}

for _, action := range g.actions {
if action.fromPiece.xy != fromXY || action.toXY != toXY || (action.isPromotion && action.promotionPieceType != promotePieceType) {
if action.fromPiece.xy != fromXY || action.toXY != toXY || (action.isPromotion && action.promotionPieceType != promotionPieceType) {
continue
}
return action, nil
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//+build !js,wasm

package main

import (
Expand Down
191 changes: 191 additions & 0 deletions main_js.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// +build js,wasm

package main

import (
"syscall/js"

"github.com/marianogappa/cheesse/api"
)

func DefaultGame(this js.Value, p []js.Value) interface{} {
return js.ValueOf(convertOutputGame(a.DefaultGame()))
}

func ParseGame(this js.Value, p []js.Value) interface{} {
og, err := a.ParseGame(convertToInputGame(p[0]))
return js.ValueOf(map[string]interface{}{
"outputGame": convertOutputGame(og),
"error": convertError(err),
})
}

func DoAction(this js.Value, p []js.Value) interface{} {
og, oa, err := a.DoAction(convertToInputGame(p[0]), convertToInputAction(p[1]))
return js.ValueOf(map[string]interface{}{
"outputGame": convertOutputGame(og),
"outputAction": convertOutputAction(oa),
"error": convertError(err),
})
}

func main() {
js.Global().Set("DefaultGame", js.FuncOf(DefaultGame))
js.Global().Set("ParseGame", js.FuncOf(ParseGame))
js.Global().Set("DoAction", js.FuncOf(DoAction))
select {}
}

func convertToInputAction(v js.Value) api.InputAction {
return api.InputAction{
FromSquare: jsString(v.Get("fromSquare")),
ToSquare: jsString(v.Get("toSquare")),
PromotionPieceType: jsString(v.Get("promotionPieceType")),
}
}

func convertToInputGame(v js.Value) api.InputGame {
board := v.Get("board")
var (
innerBoard []string
outerBoard = api.Board{}
)
if !board.IsNull() && !board.IsUndefined() {
innerBoard = make([]string, board.Length())
for i := range innerBoard {
innerBoard[i] = jsString(board.Index(i))
}
outerBoard = api.Board{
Board: innerBoard,
CanWhiteKingsideCastle: jsBool(board.Get("canWhiteKingsideCastle")),
CanWhiteQueensideCastle: jsBool(board.Get("canWhiteQueensideCastle")),
CanBlackKingsideCastle: jsBool(board.Get("canBlackKingsideCastle")),
CanBlackQueensideCastle: jsBool(board.Get("canBlackQueensideCastle")),
HalfMoveClock: jsInt(board.Get("halfMoveClock")),
FullMoveNumber: jsInt(board.Get("fullMoveNumber")),
EnPassantTargetSquare: jsString(board.Get("enPassantTargetSquare")),
Turn: jsString(board.Get("turn")),
}
}
return api.InputGame{
DefaultGame: jsBool(v.Get("defaultGame")),
FENString: jsString(v.Get("fenString")),
Board: outerBoard,
}
}

func jsBool(j js.Value) bool {
if j.IsUndefined() || j.IsNull() {
return false
}
return j.Bool()
}

func jsInt(j js.Value) int {
if j.IsUndefined() || j.IsNull() || j.IsNaN() {
return 0
}
return j.Int()
}

func jsString(j js.Value) string {
if j.IsUndefined() || j.IsNull() {
return ""
}
return j.String()
}

func convertError(err error) string {
if err == nil {
return ""
}
return err.Error()
}

func convertOutputGame(og api.OutputGame) map[string]interface{} {
return map[string]interface{}{
"fenString": og.FENString,
"board": convertBoard(og.Board),
"actions": convertOutputActions(og.Actions),
"canWhiteCastle": og.CanWhiteCastle,
"canWhiteKingsideCastle": og.CanWhiteKingsideCastle,
"canWhiteQueensideCastle": og.CanWhiteQueensideCastle,
"canBlackCastle": og.CanBlackCastle,
"canBlackKingsideCastle": og.CanBlackKingsideCastle,
"canBlackQueensideCastle": og.CanBlackQueensideCastle,
"halfMoveClock": og.HalfMoveClock,
"fullMoveNumber": og.FullMoveNumber,
"isLastMoveEnPassant": og.IsLastMoveEnPassant,
"enPassantTargetSquare": og.EnPassantTargetSquare,
"moveNumber": og.MoveNumber,
"blackPieces": convertMapStringToString(og.BlackPieces),
"whitePieces": convertMapStringToString(og.WhitePieces),
"blackKing": og.BlackKing,
"whiteKing": og.WhiteKing,
"isCheck": og.IsCheck,
"isCheckmate": og.IsCheckmate,
"isStalemate": og.IsStalemate,
"isDraw": og.IsDraw,
"isGameOver": og.IsGameOver,
"gameOverWinner": og.GameOverWinner,
"inCheckBy": convertStringArr(og.InCheckBy),
}
}

func convertStringArr(ss []string) []interface{} {
is := make([]interface{}, len(ss))
for i := 0; i < len(ss); i++ {
is[i] = ss[i]
}
return is
}

func convertMapStringToString(mss map[string]string) map[string]interface{} {
m := make(map[string]interface{}, len(mss))
for k, v := range mss {
m[k] = v
}
return m
}

func convertOutputActions(as []api.OutputAction) []interface{} {
is := make([]interface{}, len(as))
for i := range as {
is[i] = convertOutputAction(as[i])
}
return is
}

func convertOutputAction(a api.OutputAction) map[string]interface{} {
return map[string]interface{}{
"fromPieceOwner": a.FromPieceOwner,
"fromPieceType": a.FromPieceType,
"fromPieceSquare": a.FromPieceSquare,
"fromSquare": a.FromPieceSquare, // TODO alias so that it can be used as input action
"toSquare": a.ToSquare,
"isCapture": a.IsCapture,
"isResign": a.IsResign,
"isPromotion": a.IsPromotion,
"isEnPassant": a.IsEnPassant,
"isEnPassantCapture": a.IsEnPassantCapture,
"isCastle": a.IsCastle,
"isKingsideCastle": a.IsKingsideCastle,
"isQueensideCastle": a.IsQueensideCastle,
"promotionPieceType": a.PromotionPieceType,
"capturedPieceType": a.CapturedPieceType,
}
}

func convertBoard(b api.Board) map[string]interface{} {
return map[string]interface{}{
"board": convertStringArr(b.Board),
"canWhiteKingsideCastle": b.CanWhiteKingsideCastle,
"canWhiteQueensideCastle": b.CanWhiteQueensideCastle,
"canBlackKingsideCastle": b.CanBlackKingsideCastle,
"canBlackQueensideCastle": b.CanBlackQueensideCastle,
"halfMoveClock": b.HalfMoveClock,
"fullMoveNumber": b.FullMoveNumber,
"enPassantTargetSquare": b.EnPassantTargetSquare,
"turn": b.Turn,
}
}

0 comments on commit 2d761db

Please sign in to comment.