Write a bot
Your bot does two things in a loop: ask the server if it is your turn,
and answer with roll or hold. The server rolls
all the dice. You never roll anything yourself.
┌─────────────────────────────┐
│ GET /decision?token=TOKEN │ ── "waiting"? ask again
└──────────────┬──────────────┘
│ a decision
┌──────────────▼──────────────┐
│ POST /move roll | hold │ ── tells you what you rolled
└──────────────┬──────────────┘
└──── repeat ────┘
1. Get a token
Do this once. The token is your bot's password — anyone who has it can
play your games for you, so do not paste it into the group chat.
curl -X POST https://pig.ides.club/register \
-H 'Content-Type: application/json' \
-d '{"name": "ada"}'
{"ok": true, "id": "ada", "token": "PASTE_YOUR_TOKEN"}
Or just use the Play tab, which registers you and remembers the token.
2. Ask for a decision
GET /decision?token=TOKEN
Most of the time it is not your turn, and you get this:
{"status": "waiting"}
When it is your turn:
{
"status": "decide",
"decision_id": "g17-t9-d3",
"game_id": "g17",
"my_score": 41,
"opponent_score": 55,
"turn_total": 14,
"rolls_this_turn": [4, 6, 4],
"target": 100,
"deadline_ms": 5000
}
| field | means |
decision_id | send this back with your move. It is different every time |
my_score | points you have already banked |
opponent_score | points they have banked |
turn_total | points riding on this turn. You lose these if you roll a 1 |
rolls_this_turn | what you have rolled so far this turn |
target | points needed to win, normally 100 |
deadline_ms | milliseconds left to answer this decision |
Add &wait=10s and the server holds the connection open until
there is something to tell you, instead of saying waiting straight
away. That is kinder than asking over and over, but either way works.
3. Send your move
curl -X POST https://pig.ides.club/move \
-H 'Content-Type: application/json' \
-d '{"token": "TOKEN",
"decision_id": "g17-t9-d3",
"move": "roll"}'
move is exactly "roll" or "hold".
The reply tells you what happened:
{
"ok": true,
"rolled": 5,
"bust": false,
"turn_total": 19,
"turn_over": false,
"my_score": 41,
"opponent_score": 55,
"game_over": false
}
| field | means |
rolled | the die you just rolled. Absent if you held |
bust | true if you rolled a 1 and lost the turn total |
turn_over | true if your turn ended, by busting or holding |
game_over | true when someone reached the target. winner says who |
If something is wrong you get {"ok": false, "error": "..."} with
an HTTP error code. The usual causes are a decision_id that has
expired, one you already answered, or one from a different game.
Rules your bot has to live with
- One decision at a time. If you are in six games at once you are
asked about them one at a time, in the order they came in. Answer the one
you are given and the next one appears.
- Answer before
deadline_ms. Too slow counts as a
hold. The clock only starts when you actually pick the
decision up, so waiting in a queue never costs you time.
- Three misses in a row and you forfeit that game. Answering
anything resets the count.
- The
decision_id must match. You cannot answer twice,
answer late, or answer a decision that was never yours.
No JSON? Use CSV
Add &format=csv to any route and you get a header row plus
data rows, which is easier in some languages — and in bash.
GET /decision?token=TOKEN&format=csv
status,decision_id,game_id,my_score,opponent_score,turn_total,rolls_this_turn,target,deadline_ms
decide,g17-t9-d3,g17,41,55,14,4|6|4,100,5000
rolls_this_turn is joined with | so it does not break
the columns. A waiting reply is just status then
waiting. Moves work over GET too, so this is a legal move:
curl -X POST 'https://pig.ides.club/move?token=TOKEN&decision_id=g17-t9-d3&move=hold&format=csv'
ok,rolled,bust,turn_total,turn_over,my_score,opponent_score,game_over,winner
true,0,false,19,true,60,55,false,
Practice against a robot
Start a game whenever you like — you do not have to wait for a cousin.
curl -X POST 'https://pig.ides.club/practice?token=TOKEN&bot=house'
Opponents: loading....
Add &first=bot to let it go first.
Then poll /decision exactly as you would in a real game.
A whole bot, to copy
Python
import time, json, urllib.request
SERVER = "https://pig.ides.club"
TOKEN = "PASTE_YOUR_TOKEN"
def call(path, data=None):
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(SERVER + path, body,
{"Content-Type": "application/json"})
return json.load(urllib.request.urlopen(req))
def think(d):
"""Return "roll" or "hold". Change THIS."""
if d["my_score"] + d["turn_total"] >= d["target"]:
return "hold" # take the win
return "hold" if d["turn_total"] >= 20 else "roll"
while True:
d = call("/decision?token=" + TOKEN + "&wait=10s")
if d["status"] != "decide":
continue
r = call("/move", {"token": TOKEN,
"decision_id": d["decision_id"],
"move": think(d)})
if r.get("game_over"):
print("game over:", r["winner"], "wins")
Everything interesting is in think(). That is the
only part worth changing, and it is the whole tournament.
Every route
| route | what it does |
POST /register | {"name"} → your token |
GET /decision | ?token= → a decision or waiting |
POST /move | {"token","decision_id","move"} → what happened |
POST /practice | ?token=&bot= → start a game against a robot |
GET /bots | the robots you can practice against |
GET /games | every game. ?player=ada to filter |
GET /games/{id} | one game, every roll of it |
GET /leaderboard | who is winning |