Skip to content

Tasm-Devil/Onitama

Repository files navigation

Onitama Multiplayer Game made with ELM and Haskell

Makefile

There's a Makefile included with the following targets:

  • all -- Calls first setup and then build
  • setup -- Set up everything: install ghc and dependencies. (Needs stack, elm and elm-test.)
  • build -- Build the server and the client.
  • server-start -- Calls build and then starts the server. Open http://localhost:8080/ in your Browser. Requests sent to this server will trigger a recompilation (via make) of the client code (if its changed).

JSON API

JSON Message from Server to Client after two game moves. Last move comes first, thats fp style (Head of the List).

{
  "cards": ["Eel", "Rabbit", "Tiger", "Rooster", "Horse"],
  "history": [
    { "color": "Black", "card": "Rooster", "from": [1, 4], "move": [-1, -1] },
    { "color": "White", "card": "Eel", "from": [2, 0], "move": [-1, 1] }
  ]
}

JSON Message from Client to server after third game move.

{"color":"White","card":"Rabbit","from":[3,0],"move":[1,1]}

Client

The Game logic is implemented entirely on the client side only. So there's no checking for cheating on the server side currently! This is on purpose because I want to use it for demonstration.

Feel free to play the older non-multiplayer version here since it doesn't want you to setup a backend server.

Thanks

  • Inspiration came from here
  • Http-Server HowTo from here

Server

The Server is my first haskell project. So don't expect very much. I still do not understand monads ;)

Test with curl

You can easily test the API with some simple curl commands. The 1 before /onitama is the API Version.

Get all Games:
curl http://localhost:8080/1/onitama/summary -w "\n"

Alice posts a new Game and gets a table-number (= game-number):
curl -X POST http://localhost:8080/1/onitama/new -w "\n"

Response: ID (ID is table/game id e.g: 3)

Alice joins her new table 3:
curl -X PUT "http://localhost:8080/1/onitama?table=3&name=Alice" -w "\n"

Response: responseGame, responseToken (e.g.: a4cd5ddc-71a3-41a2-bff2-0c516df006d3)

Bob joins table 3 as black Player (and leaves it):
curl -X PUT "http://localhost:8080/1/onitama?table=3&name=Bob" -w "\n"

Response: responseGame, responseToken (e.g.: f5ea6fb0-2527-46d8-b0ab-9e861cf55395)

Bob rejoins table 3:
curl -X PUT "http://localhost:8080/1/onitama?table=3&name=Bob&token=f5ea6fb0-2527-46d8-b0ab-9e861cf55395" -w "\n"

Response: responseGame and old responseToken (e.g.: f5ea6fb0-2527-46d8-b0ab-9e861cf55395)

Bob posts a new GameMove to Game 3:
curl -X POST -d '{"color": "White","card": "Ox","from": [3,0],"move": [0,1]}' -H 'Content-Type: application/json' "http://localhost:8080/1/onitama?table=3&token=a4cd5ddc-71a3-41a2-bff2-0c516df006d3" -w "\n"

Response: {"color": "White","card": "Ox","from": [3,0],"move": [0,1]}

Alice fetches Game 3 to see Bobs last move:
curl "http://localhost:8080/1/onitama?table=3" -w "\n"

ToDos

In the order in which I would like to tackle them.

  • GetGame with UUID in the URL should work to
  • GetGames should also return all playernames with gameids.
  • GameIds from 1 to infinity instead of UUID
  • Change API to /VERSION/GAMENAME?table=GAMEID
  • Authetification by player name using sessions-ids
  • Save sessions in local storage
  • Implement http polling temporarily.
  • The common card should determine, which player starts the game.
  • Check for checkmate!
  • JSON for GameMove is to verbose. Simplyfy it to something like {"move":"white:c1b2:elephant"}
  • Use WebSocket to get new moves without the need to do http polling.
  • Implement Chat feature
  • Add support for the Cards from the Senseis Path explansion.

Expansion Cards

Thanks

Thanks to https://github.com/haskell-servant/example-servant-elm