A Python implementation of Discworld's Thud!
This is a simple Python backend for the boardgame Thud, which is a bit like chess but with more flying dwarves. It currently only uses the classic rules, but Khoom Valley rules are a planned feature.
The rules for Thud are simple, but mastering the game is challenging. Or maybe I'm just terrible at strategic board games.
The board is a 15x15 square, with triangles cut away in each of the corners to create an octagon. 32 Dwarves start arrayed on all the edge positions except for the center of each short side. 8 Trolls start arrayed around an impassable center space called the Thud Stone.
Dwarves can move any number of squares in any direction, including horizontally, vertically, and diagonally.
Trolls can move one square in any direction.
Dwarves capture a Troll by moving into the space it occupies, but they may not move more than one space to complete a capture. This means a Dwarf must start their turn next to a Troll in order to make a capture.
Trolls capture dwarves by moving into a space next to them. A troll can capture as many Dwarves as they are able to stand next to - theoretically, this means 8, but practically it's limited to 4 or 5.
However, both Dwarves and Trolls may work together to make captures more than one space away.
When either Dwarves or Trolls get in a line, they may work together to throw the leading creature at their enemy. Both are able to throw as far as there are allies in a straight line behind them - four creatures in a line can Toss/Shove the lead creature up to four spaces. There is no minimum distance for a Toss/Shove. In order for Dwarves to make a Toss, the lead Dwarf must land on the space occupied by a target troll. Trolls are larger, and don't fly through the air easily, so they simply Shove their compatriots towards the Dwarves. A Troll must land in an empty space at the end of a shove.
This backend is run at http://willwagner.me:12000. Migrations of this address will be posted here on my Thud github page.
There are two possible methods for a client to start a game. Using HTTP POST you can start a game for multiple players on the same computer. Using a websocket connection you can allow a player to connect and choose other players to match with.
To start a game, POST "/start" with the following JSON data in the body:
{"game": "begin",
"player_one": "Will",
"player_two": "Tom"}
This returns the entire board state, along with tokens for each player so the server can ensure you're moving at the correct times:
{"game": "game_token",
"player_one": "player_one_token",
"player_two": "player_two_token",
"board": {"row_num": [row_data]}}
To execute a move, POST "/move" with the following JSON data in the body:
Making a move:
{"game": "correct_game_token",
"player":"correct_player_token",
"start": [x, y],
"destination": [x, y]}
This returns either True, a dictionary of pieces that are removed, or False if the move fails:
If move is a valid move, returns true:
True
If move is a valid attack, the x,y coordinates of any possible targets:
[[target_x, target_y]]
If move is invalid, returns false:
False
To validate a move, meaning ensure a move is valid without actually executing that move, POST "/move/validate" with the same JSON you would use for "/move". This does not modify board state in any way, but means you don't need to implement game logic in your UI layer to do things like display possible valid moves.
Note: This functionality isn't currently available on the production Thud server. The below documentation will remain incomplete until this functionality is ported to Django.
The weboscket connection is reached at "/match/playername". You may not connect with a playername that is already connected. When you connect a player, the list of currently connected players is returned, as below:
**insert example here**
To start a game via websocket, you must return "match" to match with an existing player:
**insert example here**
Ensure you can handle a failure to match - if that player has already been matched, the server will return a refreshed list of players rather than new game information.
**insert example here**
For remaining functionality, the websocket layer is simply a wrapper around the HTTP POST JSON data described above, where the endpoint (i.e. "/move") is included as the key, and the JSON data is the value.
{"move": {JSON_Move_Data}}
This will return the typical JSON data you'd expect from the POST messages above, and the server will do the work of passing all information to your match partner.