/graphql-chess-server

A Node.js GraphQL server for powering chess

Primary LanguageJavaScriptMIT LicenseMIT

Chess GraphQL

A GraphQL server for powering a chess game. It is driven by representing a chess board using Forsyth–Edwards Notation (FEN).

Here's an example of a chess board in the starting positions.

GraphQL query
{
  chess {
    analysis {
      bestMove {
        from
        to
        flags
      }
    }
    board {
      rank
      squares {
        file
        piece {
          type
          color
        }
      }
    }
    fen
    gameOver
    inCheck
    inCheckmate
    inDraw
    inStalemate
    insufficientMaterial
    inThreefoldRepetition
    moves {
      color
      from
      to
      promotion
    }
    turn
  }
}
Response JSON
{
  "data": {
    "chess": {
      "analysis": {
        "bestMove": {
          "from": "e2",
          "to": "e4",
          "flags": null
        }
      },
      "board": [
        {
          "rank": 8,
          "squares": [
            {
              "file": "a",
              "piece": {
                "type": "r",
                "color": "b"
              }
            },
            {
              "file": "b",
              "piece": {
                "type": "n",
                "color": "b"
              }
            },
            {
              "file": "c",
              "piece": {
                "type": "b",
                "color": "b"
              }
            },
            {
              "file": "d",
              "piece": {
                "type": "q",
                "color": "b"
              }
            },
            {
              "file": "e",
              "piece": {
                "type": "k",
                "color": "b"
              }
            },
            {
              "file": "f",
              "piece": {
                "type": "b",
                "color": "b"
              }
            },
            {
              "file": "g",
              "piece": {
                "type": "n",
                "color": "b"
              }
            },
            {
              "file": "h",
              "piece": {
                "type": "r",
                "color": "b"
              }
            }
          ]
        },
        {
          "rank": 7,
          "squares": [
            {
              "file": "a",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "b",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "c",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "d",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "e",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "f",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "g",
              "piece": {
                "type": "p",
                "color": "b"
              }
            },
            {
              "file": "h",
              "piece": {
                "type": "p",
                "color": "b"
              }
            }
          ]
        },
        {
          "rank": 6,
          "squares": [
            {
              "file": "a",
              "piece": null
            },
            {
              "file": "b",
              "piece": null
            },
            {
              "file": "c",
              "piece": null
            },
            {
              "file": "d",
              "piece": null
            },
            {
              "file": "e",
              "piece": null
            },
            {
              "file": "f",
              "piece": null
            },
            {
              "file": "g",
              "piece": null
            },
            {
              "file": "h",
              "piece": null
            }
          ]
        },
        {
          "rank": 5,
          "squares": [
            {
              "file": "a",
              "piece": null
            },
            {
              "file": "b",
              "piece": null
            },
            {
              "file": "c",
              "piece": null
            },
            {
              "file": "d",
              "piece": null
            },
            {
              "file": "e",
              "piece": null
            },
            {
              "file": "f",
              "piece": null
            },
            {
              "file": "g",
              "piece": null
            },
            {
              "file": "h",
              "piece": null
            }
          ]
        },
        {
          "rank": 4,
          "squares": [
            {
              "file": "a",
              "piece": null
            },
            {
              "file": "b",
              "piece": null
            },
            {
              "file": "c",
              "piece": null
            },
            {
              "file": "d",
              "piece": null
            },
            {
              "file": "e",
              "piece": null
            },
            {
              "file": "f",
              "piece": null
            },
            {
              "file": "g",
              "piece": null
            },
            {
              "file": "h",
              "piece": null
            }
          ]
        },
        {
          "rank": 3,
          "squares": [
            {
              "file": "a",
              "piece": null
            },
            {
              "file": "b",
              "piece": null
            },
            {
              "file": "c",
              "piece": null
            },
            {
              "file": "d",
              "piece": null
            },
            {
              "file": "e",
              "piece": null
            },
            {
              "file": "f",
              "piece": null
            },
            {
              "file": "g",
              "piece": null
            },
            {
              "file": "h",
              "piece": null
            }
          ]
        },
        {
          "rank": 2,
          "squares": [
            {
              "file": "a",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "b",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "c",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "d",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "e",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "f",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "g",
              "piece": {
                "type": "p",
                "color": "w"
              }
            },
            {
              "file": "h",
              "piece": {
                "type": "p",
                "color": "w"
              }
            }
          ]
        },
        {
          "rank": 1,
          "squares": [
            {
              "file": "a",
              "piece": {
                "type": "r",
                "color": "w"
              }
            },
            {
              "file": "b",
              "piece": {
                "type": "n",
                "color": "w"
              }
            },
            {
              "file": "c",
              "piece": {
                "type": "b",
                "color": "w"
              }
            },
            {
              "file": "d",
              "piece": {
                "type": "q",
                "color": "w"
              }
            },
            {
              "file": "e",
              "piece": {
                "type": "k",
                "color": "w"
              }
            },
            {
              "file": "f",
              "piece": {
                "type": "b",
                "color": "w"
              }
            },
            {
              "file": "g",
              "piece": {
                "type": "n",
                "color": "w"
              }
            },
            {
              "file": "h",
              "piece": {
                "type": "r",
                "color": "w"
              }
            }
          ]
        }
      ],
      "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
      "gameOver": false,
      "inCheck": false,
      "inCheckmate": false,
      "inDraw": false,
      "inStalemate": false,
      "insufficientMaterial": false,
      "inThreefoldRepetition": false,
      "moves": [
        {
          "color": "w",
          "from": "a2",
          "to": "a3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "a2",
          "to": "a4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "b2",
          "to": "b3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "b2",
          "to": "b4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "c2",
          "to": "c3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "c2",
          "to": "c4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "d2",
          "to": "d3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "d2",
          "to": "d4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "e2",
          "to": "e3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "e2",
          "to": "e4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "f2",
          "to": "f3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "f2",
          "to": "f4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "g2",
          "to": "g3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "g2",
          "to": "g4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "h2",
          "to": "h3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "h2",
          "to": "h4",
          "promotion": null
        },
        {
          "color": "w",
          "from": "b1",
          "to": "a3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "b1",
          "to": "c3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "g1",
          "to": "f3",
          "promotion": null
        },
        {
          "color": "w",
          "from": "g1",
          "to": "h3",
          "promotion": null
        }
      ],
      "turn": "w"
    }
  }
}

Getting started

# clones this repo
git clone https://github.com/ncksllvn/chess-graphql.git

# switch to new directory
cd chess-graphql/

# Make sure you're using the right version of Node (via Node Version Manager)
nvm use

# Set up your environment
cp sample.env .env

# start the site
npm start # -> localhost:4000

Running tests

npm test

Examples

Make a move

Example below returns the resultant board after passing the board in starting position with a move from A2 to A3 applied.

GraphQL mutation
mutation {
  move(input: {
    fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
    move: {
      from: a2,
      to: a3
    }
  }) {
    analysis {
      bestMove {
        from
        to
      }
    }
    fen
    gameOver
    inCheck
    inCheckmate
    moves {
      from
      to
      promotion
    }
    turn
  }
}
Response JSON
{
  "data": {
    "move": {
      "analysis": {
        "bestMove": {
          "from": "d7",
          "to": "d5"
        }
      },
      "fen": "rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b KQkq - 0 1",
      "gameOver": false,
      "inCheck": false,
      "inCheckmate": false,
      "moves": [
        {
          "from": "b8",
          "to": "c6",
          "promotion": null
        },
        {
          "from": "b8",
          "to": "a6",
          "promotion": null
        },
        {
          "from": "g8",
          "to": "h6",
          "promotion": null
        },
        {
          "from": "g8",
          "to": "f6",
          "promotion": null
        },
        {
          "from": "a7",
          "to": "a6",
          "promotion": null
        },
        {
          "from": "a7",
          "to": "a5",
          "promotion": null
        },
        {
          "from": "b7",
          "to": "b6",
          "promotion": null
        },
        {
          "from": "b7",
          "to": "b5",
          "promotion": null
        },
        {
          "from": "c7",
          "to": "c6",
          "promotion": null
        },
        {
          "from": "c7",
          "to": "c5",
          "promotion": null
        },
        {
          "from": "d7",
          "to": "d6",
          "promotion": null
        },
        {
          "from": "d7",
          "to": "d5",
          "promotion": null
        },
        {
          "from": "e7",
          "to": "e6",
          "promotion": null
        },
        {
          "from": "e7",
          "to": "e5",
          "promotion": null
        },
        {
          "from": "f7",
          "to": "f6",
          "promotion": null
        },
        {
          "from": "f7",
          "to": "f5",
          "promotion": null
        },
        {
          "from": "g7",
          "to": "g6",
          "promotion": null
        },
        {
          "from": "g7",
          "to": "g5",
          "promotion": null
        },
        {
          "from": "h7",
          "to": "h6",
          "promotion": null
        },
        {
          "from": "h7",
          "to": "h5",
          "promotion": null
        }
      ],
      "turn": "b"
    }
  }
}

Lookup by FEN

Example below shows a board with a pawn positioned to be promoted in a move from C7 to C8.

GraphQL query
{
  chess(fen: "8/q1P1k3/8/8/8/8/6PP/7K w - - 0 1") {
    analysis {
      bestMove {
        from
        to
      }
    }
    fen
    gameOver
    inCheck
    inCheckmate
    inDraw
    inStalemate
    insufficientMaterial
    inThreefoldRepetition
    moves {
      from
      to
      promotion
    }
    turn
  }
}
Response JSON
{
  "data": {
    "chess": {
      "analysis": {
        "bestMove": {
          "from": "c7",
          "to": "c8"
        }
      },
      "fen": "8/q1P1k3/8/8/8/8/6PP/7K w - - 0 1",
      "gameOver": false,
      "inCheck": false,
      "inCheckmate": false,
      "inDraw": false,
      "inStalemate": false,
      "insufficientMaterial": false,
      "inThreefoldRepetition": false,
      "moves": [
        {
          "from": "c7",
          "to": "c8",
          "promotion": "q"
        },
        {
          "from": "c7",
          "to": "c8",
          "promotion": "r"
        },
        {
          "from": "c7",
          "to": "c8",
          "promotion": "b"
        },
        {
          "from": "c7",
          "to": "c8",
          "promotion": "n"
        },
        {
          "from": "g2",
          "to": "g3",
          "promotion": null
        },
        {
          "from": "g2",
          "to": "g4",
          "promotion": null
        },
        {
          "from": "h2",
          "to": "h3",
          "promotion": null
        },
        {
          "from": "h2",
          "to": "h4",
          "promotion": null
        }
      ],
      "turn": "w"
    }
  }
}