Trinnvis veiledning for nybegynnere
Dette trenger du
- En konto på FlipSight. Når du har logget inn, kan du registrere en bot og laste ned tilkoblingsprogrammet.
- Ett botbilde: en GIF-, JPG- eller PNG-fil på høyst 5 MB, minst 175 px bred og høy.
- Din egen datamaskin til å kjøre boten Trekkene til boten din beregnes på datamaskinen der tilkoblingsprogrammet kjører. Selv med samme motor kan styrken variere med datamaskinens ytelse og motorinnstillingene, og hvis du bytter datamaskin eller innstillinger, kan ratingen bevege seg tilsvarende.
- Python 3, et gratis program som kjører tilkoblingsprogrammet. Versjon 3.9 eller nyere fungerer; 3.11 eller nyere anbefales. Du sjekker dette i trinn 5.
- Motoren til boten din. Tilkoblingsprogrammet inkluderer en øvingsmotor for testing.
1. Registrer boten din
Logg inn og åpne botsiden (othelloclub.com/nb/flipsight/bot). I boksen Registrer min bot øverst skriver du et navn i Botnavn (2–24 tegn). La foreløpig bare Standard være avkrysset under Støttede spill. Velg et bilde under Last opp botbilde, og trykk deretter på knappen Registrer min bot.
Slik ser det ut når det fungerer: boksen Tilkoblingstoken (vises bare én gang) vises med en lang tekst som starter med fsbm_.
2. Ta vare på tokenet
Denne lange teksten er tokenet, et passord bare for boten din. Tilkoblingsprogrammet bruker det til å bevise overfor serveren at det snakker på vegne av denne boten. Kopier hele teksten og lim den inn et midlertidig sted, for eksempel i et tekstredigeringsprogram. Når du har lukket boksen, kan du ikke se det samme tokenet igjen.
Behandle tokenet som et passord. Ikke vis det til noen, og ikke del skjermbilder av det. Hvis du mister det eller noen andre ser det, åpner du Administrer i botlisten og trykker på Opprett tilkoblingstoken. Når du får et nytt token, slutter det gamle å virke med en gang.
3. Last ned tilkoblingsprogrammet
Trykk på Last ned Python-eksempler for å laste ned ZIP-filen, og pakk den ut. Denne veiledningen kaller den utpakkede mappen "botmappen". Legg den et sted der den er lett å finne, for eksempel på skrivebordet.
Slik ser det ut når det fungerer: botmappen inneholder filen README.md og mappen tools.
4. Åpne en terminal i botmappen
En terminal er et vindu der du skriver kommandoer. Åpne den slik for systemet ditt.
macOS: trykk på Command+Space, skriv Terminal og åpne programmet. Skriv cd og ett mellomrom, dra botmappen inn i vinduet, og trykk på Enter.
Linux: høyreklikk på botmappen i filbehandleren, og velg Åpne i terminal. Navnet på menyvalget kan variere mellom distribusjoner. Hvis menyvalget ikke finnes, åpner du en terminal og bruker cd som på macOS.
Windows: åpne botmappen i Filutforsker. Skriv powershell i adressefeltet øverst, og trykk på Enter. Et PowerShell-vindu åpnes i den mappen.
Sjekk: skriv kommandoen nedenfor, og trykk på Enter. Det har fungert hvis README.md og tools står i listen. Denne kommandoen er den samme på macOS, Linux og Windows PowerShell.
ls5. Sjekk Python
I samme vindu kopierer du den ene kommandoen for systemet ditt, limer den inn og trykker på Enter. Du kan bruke kopieringsknappen øverst til høyre i hver kodeboks.
macOS / Linux
python3 --versionWindows PowerShell
py --versionSlik ser det ut når det fungerer: en versjon som starter med 3, for eksempel Python 3.11.9. Versjon 3.9 eller nyere fungerer. Hvis kommandoen ikke blir funnet, installerer du Python som beskrevet nedenfor, lukker vinduet og begynner på nytt fra trinn 4.
macOS: last ned installasjonsprogrammet for macOS (.pkg) fra python.org og installer det. Kjør deretter Install Certificates.command én gang fra Python-mappen under Programmer. Dette klargjør sertifikatene som trengs for sikre tilkoblinger (HTTPS).
Linux: installer python3 med programvaresenteret eller pakkebehandleren i distribusjonen din.
Windows: installer Python install manager fra python.org.
6. Skriv inn tokenet
Legg tokenet i en miljøvariabel, en midlertidig innstilling som bare finnes i dette terminalvinduet. Den heter FS_BOT_TOKEN. Kopier kommandoen på én linje for systemet ditt nedenfor, lim den inn og trykk én gang på Enter. Da vises Bot token og venter på det du skriver inn. Lim nå inn tokenet du kopierte i trinn 2, og trykk på Enter.
macOS / Linux
printf 'Bot token: '; read -r -s FS_BOT_TOKEN; printf '\n'; export FS_BOT_TOKENWindows PowerShell
$env:FS_BOT_TOKEN = [Net.NetworkCredential]::new('', (Read-Host 'Bot token' -AsSecureString)).PasswordPå macOS og Linux vises ikke tokenet du limer inn, og på Windows ser du * i stedet for tegnene. Begge deler er normalt. Fordi tokenet ikke skrives inn i kommandoen, blir det ikke liggende i kommandohistorikken. Innstillingen gjelder bare i dette vinduet. Hvis du har lukket det eller åpnet et nytt vindu, gjentar du trinn 4 og 6.
Windows: I PowerShell limer du inn med Ctrl+V eller et høyreklikk. Denne kommandoen på én linje bruker en syntaks som virker både i Windows PowerShell 5.1, som følger med Windows, og i den nyere PowerShell 7, men den er ikke testet på en ekte Windows-maskin ennå.
Slik ser det ut når det fungerer: ledeteksten for neste kommando kommer tilbake uten feil.
7. Start tilkoblingsprogrammet
I samme vindu kopierer du kommandoen nedenfor slik den er, limer den inn og trykker på Enter. Ikke endre filnavnene i den. Boten din kobler seg til med øvingsmotoren, en svært svak motor som spiller det lovlige feltet med lavest nummer.
macOS / Linux
python3 tools/bot_match_client.py --engine 'python3 tools/bot_match_example_engine.py'Windows PowerShell
py tools/bot_match_client.py --engine 'py tools/bot_match_example_engine.py'Det er normalt at kommandoen ikke viser tekst eller gir deg ledeteksten tilbake mens den kjører. For å holde boten på nett må du la dette vinduet stå åpent med tilkoblingsprogrammet og motoren i gang, og hindre at datamaskinen går i dvale. Hvis du lukker vinduet eller trykker Ctrl+C, avsluttes begge programmene og boten kobles fra. Kjør kommandoen ovenfor igjen for å koble den til. Tilkoblingsprogrammet godtar automatisk utfordringer fra andre boter.
Så lenge boten kjører med øvingsmotoren, får den ingen automatiske kamper, og kampene den spiller mot andre boter, også de du ber om selv, er ikke ratet. Start den på nytt med din egen motor (trinn 10), så blir den paret og ratet fra da av.
Slik ser det ut når det fungerer: i listen Registrerte boter på botsiden er prikken til høyre for botnavnet ditt grønn. Når du holder musen over den, vises Tilkoblet. Hvis den er grå (Frakoblet), trykker du på Oppdater.
8. Test med en første kamp
Velg boten din under Min spillende bot på botsiden. Velg en hvilken som helst bot i listen FlipSight-boter, trykk på Utfordre og bekreft i vinduet som åpnes. I alle spilltyper beregner serveren trekkene til FlipSight-botene, så du trenger ikke holde spillrommet åpent. Med automatisk paring på (standard) setter nettstedet også opp botkamper mens tilkoblingsprogrammet kjører.
Slik ser det ut når det fungerer: spillrommet viser to brett, og en brikke legges hver gang det er botens tur. Øvingsmotoren er svært svak, så det er normalt å tape.
9. La den kjøre etter at vinduet er lukket (valgfritt)
Start med kommandoen nedenfor i stedet for trinn 7, så fortsetter boten å kjøre når du lukker vinduet. Kjør den i samme vindu som du skrev inn tokenet i (trinn 6). Den stopper hvis datamaskinen slås av eller går i hvilemodus. Stopper du den under en kamp, tapes kampen på tid eller på grunn av frakobling.
macOS / Linux
macOS / Linux: når du har kjørt startkommandoen, kan du lukke vinduet. Meldinger skrives til filen bot.log i botmappen. For å stoppe den åpner du en ny terminal og kjører stoppkommandoen. Kopier bare boksen du trenger: limer du inn begge boksene samtidig, stopper boten rett etter at den har startet.
Start
nohup python3 tools/bot_match_client.py --engine 'python3 tools/bot_match_example_engine.py' > bot.log 2>&1 &Stopp
pkill -f bot_match_client.pyWindows PowerShell
Windows: et minimert vindu vises på oppgavelinjen, og boten kjører i det. Du kan lukke det nåværende PowerShell-vinduet. For å stoppe den åpner du det minimerte vinduet og trykker på Ctrl+C, eller lukker det vinduet.
Start
Start-Process py -ArgumentList 'tools/bot_match_client.py --engine "py tools/bot_match_example_engine.py"' -WorkingDirectory $PWD -WindowStyle Minimized10. Bytt til din egen motor
Etter tilkoblingstesten bytter du til din egen motor: egne valg nedenfor for Edax eller Egaroucid, --nboard for andre kompatible motorer, JSON for din egen motor. Behold samme token.
Kryss bare av for en variant (Anti, 10x10, Octagon, klassisk Reversi) under Støttede spill hvis motoren din kan reglene for den. Andre boter og mennesker kan utfordre boten din i alle spill som er avkrysset. For å endre dette åpner du Administrer i botlisten, endrer Støttede spill og trykker på Lagre. Du kan ikke endre det mens en kamp pågår eller en utfordring venter.
Eksempler på motorforespørsler per spill
Koble til en NBoard-motor som Edax
NBoard er et grafisk Othello-program som kan brukes med NTest. NBoard-protokollen er programmets offentlige kommunikasjonsformat for motorer og fungerer med motorer som støtter den, som NTest og Edax.
Eksemplene på installasjon og oppstart nedenfor bruker Edax 4.6 og Egaroucid for Console 7.8.2.
Edax 4.6 følger ikke med tilkoblingsprogrammet. Last ned filen for operativsystemet ditt fra Assets på Edax 4.6, legg den i botmappen og pakk den ut med forberedelseskommandoene nedenfor. Windows- og Linux-kommandoene er for x86-64.
Windows PowerShell (x86-64): edax-4.6-MS-windows-x86.zip
Forbered (bare første gang)
Expand-Archive -LiteralPath edax-4.6-MS-windows-x86.zip -DestinationPath edax-4.6Start
py tools/bot_match_client.py --edax "edax-4.6\wEdax-x86-64.exe"Linux (x86-64): edax-4.6-linux-x86.tar.gz
Forbered (bare første gang)
mkdir -p edax-4.6
tar -xzf edax-4.6-linux-x86.tar.gz -C edax-4.6
chmod +x edax-4.6/lEdax-x86-64Start
python3 tools/bot_match_client.py --edax "edax-4.6/lEdax-x86-64"macOS: edax-reversi-4.6.tar.gz
Det finnes ingen offisiell macOS-programfil for Edax 4.6. Last ned Source code (tar.gz) og edax-4.6-linux-x86.tar.gz fra samme utgivelse. Bygg Mac-programmet fra kildekoden; hent bare den felles evalueringsfilen data/eval.dat fra Linux-arkivet. Xcode Command Line Tools kreves. Forberedelseskommandoene kompilerer kildekoden.
Forbered (bare første gang)
xcode-select --installtar -xzf edax-reversi-4.6.tar.gz
mv edax-reversi-4.6 edax-4.6
mkdir -p edax-4.6/bin
tar -xzf edax-4.6-linux-x86.tar.gz -C edax-4.6 data/eval.dat
(cd edax-4.6/src && make build ARCH=native OS=osx)Start
python3 tools/bot_match_client.py --edax "edax-4.6/bin/mEdax-native"Edax kan også kobles til med bare programstien via --edax nedenfor. En egen adapter trengs ikke; tilkoblingsprogrammet fordeler tenketiden per trekk fra gjenværende spilletid.
Bytt ut stien i kommandoen med hele stien til programfilen din. Sett stier med mellomrom i doble anførselstegn. Hvis evalueringsfilen ikke finnes automatisk, angi eval.dat med --edax-eval.
En NBoard-tilkobling spiller bare standardkamper på 8×8. La bare Standard være avkrysset under Støttede spill for denne boten. Hvis en variant kommer, spør ikke tilkoblingsprogrammet motoren, ingen trekk blir spilt, og kampen annulleres eller tapes på tid.
Egaroucid: --egaroucid
Gjør klar Egaroucid for Console. Velg konsollprogrammet og behold resources-mappen på sin plass. På macOS og Linux brukes en programfil bygget etter den offisielle veiledningen. Stillingen og resttiden sendes via setboard, settime og go uten adapter.
Windows PowerShell
py tools/bot_match_client.py --egaroucid "egaroucid\Egaroucid_for_console.exe"macOS / Linux
python3 tools/bot_match_client.py --egaroucid "egaroucid/bin/Egaroucid_for_Console.out"Begge moduser støtter bare standard 8×8, med én motor per samtidig parti. --max-think-seconds er sikkerhetsgrensen per trekk (10 sekunder som standard). Når Egaroucid når grensen, stoppes søket, et lovlig reservetrekk spilles, og motoren startes på nytt ved neste tur.
Egen motor: koble til via JSON
Les denne delen bare hvis du vil koble til en motor du har skrevet selv. Hvis du bruker Edax, Egaroucid eller en annen NBoard-motor, er du allerede ferdig ovenfor og kan hoppe over den.
Hver gang boten din er i trekket, kjører tilkoblingsprogrammet my_adapter.py én gang. Det leverer gjeldende stilling som én linje (hvor brikkene står, hvem som har trekket, hvilke felter som er lovlige, hvor mye tid som er igjen), my_adapter.py svarer med ett felt som én linje, og tilkoblingsprogrammet spiller det trekket på serveren. my_adapter.py er en liten Python-fil i midten som ber motoren din om trekket. Tilkoblingsprogrammet tar seg av tilkoblingen til serveren, tokenet og innsendingen av trekk, så denne filen trenger aldri å gjøre noe med det.
bot_match_client.py→ my_adapter.pybot_match_client.py← my_adapter.pyHva slags motor har du?
- En motor som velger trekket i Python-kode: bruk eksempel A nedenfor.
- En programfil som skriver ut én svarlinje og avslutter hver gang den kjøres: bruk eksempel B nedenfor.
- En programfil som holder seg åpen og utveksler kommandoer fortløpende: støtter den NBoard, kobler du den til med --nboard ovenfor. Med en annen protokoll tilpasser du eksempel B til protokollen og lar my_adapter.py holde motoren åpen og utveksle én linje om gangen i en løkke.
Trinn 1: en fil som bare sjekker tilkoblingen (my_adapter.py)
Lag en fil som heter my_adapter.py i botmappen (der README.md og tools ligger), lim inn koden nedenfor slik den er, og lagre filen. Denne filen bruker ingen motor og svarer bare med det første lovlige feltet. Den er der for å bekrefte at tilkoblingen virker før du kobler til motoren din.
import json
import sys
def choose_move(position):
legal = position["legal_moves"]
return legal[0] if legal else -1
line = sys.stdin.readline()
position = json.loads(line)
move = choose_move(position)
print(json.dumps({"move": move}), flush=True)
Sjekk inndata og utdata før du kobler til
Kommandoen i boks 1 sender eksempelstillingen rett inn i adapteren. Den skal skrive ut én linje: {"move": 19}. Når du ser den linjen, starter kommandoen i boks 2 tilkoblingsprogrammet med denne adapteren, i vinduet som har tokenet fra trinn 6. Kjør de to boksene hver for seg. Hvis motoren din selv leser dette JSON-formatet, kan du sette kommandoen for den rett etter --engine.
1. Test bare adapteren
macOS / Linux
printf '%s\n' '{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}' | python3 my_adapter.pyWindows PowerShell
'{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}' | py my_adapter.py2. Start tilkoblingsprogrammet med adapteren
macOS / Linux
python3 tools/bot_match_client.py --engine 'python3 my_adapter.py'Windows PowerShell
py tools/bot_match_client.py --engine 'py my_adapter.py'Trinn 2: bytt til en fil som kaller motoren din
Når trinn 1 virker, erstatter du hele innholdet i my_adapter.py med eksempel A eller B nedenfor. Endre bare linjene som er merket EDIT, og la resten stå som det er. Kjør deretter testkommando 1 ovenfor på nytt, og sjekk at det kommer én svarlinje. Det er motoren din som har valgt trekket, så et annet felt enn 19 er helt normalt.
Eksempel A: en motor som velger trekket med en Python-funksjon
Dette eksemplet forutsetter en fil som heter my_engine.py, med en funksjon search som velger trekket. Endre filnavnet og funksjonsnavnet ved EDIT 1 og verdiene som sendes inn ved EDIT 2, slik at de passer til motoren din. Funksjonen skal returnere feltnummeret (0 til 63) eller en koordinat som d3.
import json
import sys
from pathlib import Path
from my_engine import search # EDIT 1: your engine file and function name
def think_ms(position):
# Time for this move: share the remaining clock over my remaining moves.
my_moves_left = position["board"].count(0) // 2 + 1
share = position["remaining_ms"] / my_moves_left
return int(min(share, position["budget_ms"]) * 0.8)
def choose_move(position):
if not position["legal_moves"]:
return -1
# EDIT 2: pass what your function needs
return search(
board=position["board"],
color=position["color"],
legal_moves=position["legal_moves"],
time_limit_ms=think_ms(position),
)
position = json.loads(sys.stdin.readline())
legal = position["legal_moves"]
try:
move = choose_move(position)
except Exception as error:
# The engine failed: note why in my_adapter.log and play the first legal square.
with open(Path(__file__).with_name("my_adapter.log"), "a") as log:
log.write(repr(error) + "\n")
move = legal[0] if legal else -1
print(json.dumps({"move": move}), flush=True)Eksempel B: en motor som er en programfil
Dette eksemplet forutsetter at programmet leser én linje med 64 brett-tegn, siden som har trekket, og betenkningstiden i millisekunder, og svarer med én koordinatlinje som D3 (. = tomt, X = svart, O = hvit). Hver motor har sitt eget format, så endre navnet på programfilen ved EDIT 1, linjen som sendes til motoren ved EDIT 2, og delen som leser svaret ved EDIT 3, slik at det passer til motoren din.
my_adapter.py → my_engine
...........................OX......XO........................... X 1777my_engine → my_adapter.py
D3import json
import subprocess
import sys
from pathlib import Path
# EDIT 1: your engine program file (kept in the same folder as my_adapter.py)
ENGINE = Path(__file__).with_name("my_engine.exe" if sys.platform == "win32" else "my_engine")
def think_ms(position):
# Time for this move: share the remaining clock over my remaining moves.
my_moves_left = position["board"].count(0) // 2 + 1
share = position["remaining_ms"] / my_moves_left
return int(min(share, position["budget_ms"]) * 0.8)
def choose_move(position):
if not position["legal_moves"]:
return -1
# EDIT 2: build the line your engine reads
board = "".join(".XO"[cell] for cell in position["board"])
color = "X" if position["color"] == 1 else "O"
reply = subprocess.run(
[str(ENGINE)],
input=f"{board} {color} {think_ms(position)}\n",
text=True,
capture_output=True,
check=True,
timeout=position["budget_ms"] / 1000 * 0.9,
)
# EDIT 3: take the square out of your engine's answer
return reply.stdout.strip()
position = json.loads(sys.stdin.readline())
legal = position["legal_moves"]
try:
move = choose_move(position)
except Exception as error:
# The engine failed: note why in my_adapter.log and play the first legal square.
with open(Path(__file__).with_name("my_adapter.log"), "a") as log:
log.write(repr(error) + "\n")
move = legal[0] if legal else -1
print(json.dumps({"move": move}), flush=True)Betenkningstid: i botpartier har hver bot 1 minutt i hvert parti, så lang tenketid på ett trekk fører fort til tap på tid. think_ms i eksemplene deler gjenværende tid (remaining_ms) på antall trekk du har igjen, og bestemmer slik tiden for dette trekket. budget_ms er ikke tiden som skal brukes på dette trekket. Det er den lengste tiden tilkoblingsprogrammet venter på svaret (10 sekunder som standard). Hvis svaret kommer senere enn det, kan ikke boten fortsette i det partiet og taper det på tid, så gi motoren din think_ms og ikke budget_ms.
Når noe går galt: hvis kallet til motoren mislykkes, skriver eksempelfilene årsaken til my_adapter.log og spiller det første lovlige feltet i stedet. Hvis trekkene ser rare ut, åpner du den filen først. Tilkoblingsprogrammet viser ikke feilmeldingene fra adapteren på skjermen. Bruk print bare til den ene svarlinjen, og skriv all feilsøkingstekst til en fil.
Hastighet: tilkoblingen holder my_adapter.py i gang for hvert parti og sender én linje per trekk. En fil som svarer én linje og avslutter, slik som eksemplene, startes på nytt ved neste trekk, så motoren din starter også på nytt hver gang. Er motoren treg å starte eller skal den beholde arbeidet fra tidligere trekk, gjør my_adapter.py til en løkke: les én linje, svar én linje, gjenta. Ikke les input til slutten, og flush etter hvert svar.
Resten av denne delen er oppslagsstoff om hva tilkoblingsprogrammet og my_adapter.py utveksler. Hvis du bruker eksempelfilene ovenfor slik de er, trenger du ikke å lese det.
Inndata-JSON (tilkoblingsprogram → adapter)
Dette er eksempeldata fra tilkoblingsprogrammet, ikke kjørbar kode. Ikke lagre dem som en Python-fil. Under partiet sendes oppdaterte data automatisk for hvert trekk.
Nedenfor er et eksempel på standard startstilling på 8×8. I ekte partier fyller tilkoblingsprogrammet inn gjeldende stilling. board lister feltene fra a1 mot høyre og deretter neste rad; 0=tomt, 1=svart, 2=hvit. color=1 ber om et trekk for svart. legal_moves lister feltene du kan spille på. remaining_ms er gjenværende tid på klokken, og budget_ms er den lengste tiden tilkoblingsprogrammet venter på svaret for dette trekket, begge i millisekunder (1000 = 1 sekund). Felter og eksempler for varianter står i avsnittet om varianter nedenfor.
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Svar-JSON (adapter → tilkoblingsprogram)
Skriv ett av svarene nedenfor som én JSON-linje som slutter med linjeskift. move er et feltnummer eller en koordinat, uavhengig av store og små bokstaver. På 8×8 er d3 (3−1)×8+3 = 19. Velg alltid blant legal_moves du har mottatt. I botpar uten lovlig trekk sender du -1 eller pass; i kamper mot mennesker avgjør serveren tvungne pass. Skriv bare svarlinjen til stdout, uten andre meldinger.
{"move":19}{"move":"d3"}{"move":-1}Eksempler på motorforespørsler per spill
Eksempler på den første forespørselen for svart som tilkoblingsprogrammet sender til en motor med --engine, generert med regelkoden. Ekte kamper av alle typer starter fra en tilfeldig stilling med 12 brikker, så board og legal_moves er forskjellige i hver kamp. For at eksemplene skal være faste, er åpningstrekkene valgt nær midten av brettet. match_id og klokkeverdiene er også annerledes i ekte kamper.
game_mode: Én av std, anti, grand, octagon, reversi. XOT i kamper mot mennesker kommer som std.board_size: 8, eller 10 for grand og octagon.board: Tabell med lengde board_size². Leses fra a1 mot høyre og deretter neste rad. 0=tomt (inkludert blokkerte felter i Octagon), 1=svart, 2=hvit.blocked_squares: Ubrukelige felter i Octagon. En tom tabell i andre spill.placed: Brikker lagt så langt per farge, medregnet de tilfeldige åpningstrekkene; nøklene er strengene "1" og "2". Brukes for grensen på 32 brikker i klassisk Reversi.
Anti (anti)
Inndata-JSON (tilkoblingsprogram → adapter)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [2, 3, 12, 25, 42, 44, 45],
"game_mode": "anti",
"board_size": 8,
"blocked_squares": [],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}Svar-JSON (adapter → tilkoblingsprogram)
{"move":2}Grand (10x10) (grand)
Inndata-JSON (tilkoblingsprogram → adapter)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [13, 14, 25, 42, 63, 65, 66],
"game_mode": "grand",
"board_size": 10,
"blocked_squares": [],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}Svar-JSON (adapter → tilkoblingsprogram)
{"move":13}Octagon (octagon)
Inndata-JSON (tilkoblingsprogram → adapter)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [13, 14, 25, 42, 63, 65, 66],
"game_mode": "octagon",
"board_size": 10,
"blocked_squares": [0, 1, 10, 8, 9, 19, 80, 90, 91, 89, 98, 99],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}Svar-JSON (adapter → tilkoblingsprogram)
{"move":13}Klassisk reversi (reversi)
Inndata-JSON (tilkoblingsprogram → adapter)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [18, 25, 33, 41, 42, 50, 51],
"game_mode": "reversi",
"board_size": 8,
"blocked_squares": [],
"placed": {
"1": 6,
"2": 6
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}Svar-JSON (adapter → tilkoblingsprogram)
{"move":18}Vanlige problemer
| Symptom | Årsak og løsning |
|---|---|
| Boten har en grå prikk (frakoblet). | Sjekk at vinduet med tilkoblingsprogrammet fortsatt kjører. Det stopper når du lukker vinduet, trykker på Ctrl+C eller datamaskinen går i hvilemodus. Gjenta trinn 6 og 7, og trykk deretter på Oppdater. |
Det står at kommandoen ikke ble funnet.command not found / is not recognized | Python mangler, eller vinduet ble ikke åpnet på nytt etter installasjonen. Se trinn 5, åpne et nytt vindu og begynn på nytt fra trinn 4. |
Det står at filen ikke kan åpnes.can't open file | Du kjørte kommandoen utenfor botmappen. Gå til botmappen som i trinn 4, og sjekk med ls at README.md og tools står i listen. |
Det står at tokenet mangler, og programmet avsluttes.FS_BOT_TOKEN is missing or invalid | Dette vinduet har ikke noe token. Hvis du har åpnet et nytt vindu, gjentar du trinn 6. |
Det står at tokenet ble avvist, og programmet stopper.Bot credential rejected | Tokenet ble limt inn feil eller er et gammelt token. Etter at du har opprettet et nytt token eller deaktivert boten, virker ikke det gamle tokenet lenger. Begynn på nytt fra trinn 6 med det nyeste tokenet. |
Den samme feillinjen fortsetter å komme.Connection/state error | Sjekk internettilkoblingen. På macOS sjekker du at du har kjørt Install Certificates.command fra trinn 5. Hvis feilen bare kommer under kamper, kan serveren avvise trekket fra motoren din som ulovlig. Tilkoblingsprogrammet sender det samme trekket på nytt, så motoren må rettes. |
| Utfordringsknappen virker ikke, eller utfordringen blir ikke godtatt. | Begge botene må ha grønn prikk. Sjekk at boten din er valgt under Min spillende bot. En bot som allerede er i en annen kamp, tar ikke imot en ny utfordring. En utfordring som ikke blir godtatt, utløper etter 120 sekunder. |
Boten gjør ingen trekk og taper deretter på tid, eller kampen annulleres.Engine failed for match | Motoren svarte ikke i tide, eller svaret hadde feil format. Sjekk motorkommandoen og JSON-utdataene på én linje. Hvis en bot ikke gjør sitt første trekk innen 30 sekunder etter start, annulleres kampen. |
| Det kommer ingen utfordringer i varianter. | Utfordringsvinduet viser bare spill som begge botene støtter. Sjekk at spillet er avkrysset under Støttede spill for boten din, og at den andre boten også støtter det. En bot som er koblet til via NBoard, bør bare ha Standard avkrysset. |
Ordliste
| Begrep | Betydning |
|---|---|
| API | En avtalt måte for programmer å sende forespørsler og svar på. Tilkoblingsprogrammet tar seg av det for deg. |
| Token | Et passord bare for boten din. Tilkoblingsprogrammet bruker det til å bevise overfor serveren hvilken bot det er. |
| Terminal | Et vindu der du skriver kommandoer. På Windows bruker du PowerShell. |
| Miljøvariabel | En midlertidig innstilling som gis videre til programmer som startes fra ett terminalvindu. Den forsvinner når vinduet lukkes. |
| JSON | Et format for å skrive data som tekst. Eksempel: {"move":19} |
| Motor | Et program som ser på en stilling og velger et trekk. |
| Adapter | Et lite program som oversetter data mellom motoren din og tilkoblingsprogrammet. |
| NBoard | NBoard er et grafisk Othello-program som kan brukes med NTest. NBoard-protokollen er programmets offentlige kommunikasjonsformat for motorer og fungerer med motorer som støtter den, som NTest og Edax. |
| Lovlig trekk | Et felt du kan spille på nå. Serveren lister dem i legal_moves. |
Nedlastinger
Logg inn for å laste ned. .zip inneholder veiledning, tilkoblingsprogram og eksempelmotor; .json er API-spesifikasjonen og .md er veiledningen.
Detaljert spesifikasjon
Resten av siden er en detaljert referanse for utviklere som jobber direkte med en motor eller med API-et.
Valg for tilkoblingsprogrammet
Valg for tools/bot_match_client.py. Nøyaktig ett av --engine og --nboard / --edax / --egaroucid er påkrevd. Tokenet er aldri et valg; det leses bare fra miljøvariabelen FS_BOT_TOKEN. Avslutningskoder: 0 normal stopp, 2 token avvist, 3 --max-runtime nådd.
| Parametere | Beskrivelse |
|---|---|
--engine "COMMAND" | Starter denne kommandoen én gang per parti og utveksler én JSON-linje per trekk uten å lukke inputen. En motor som svarer én linje og avslutter, startes på nytt ved neste trekk. |
--nboard "COMMAND" | Beholder én NBoard-motor per parti, to totalt. Bare standard (std). |
--edax PATH | Edax kan også kobles til med bare programstien via --edax nedenfor. En egen adapter trengs ikke; tilkoblingsprogrammet fordeler tenketiden per trekk fra gjenværende spilletid. |
--edax-eval PATH | Sti til Edax eval.dat. Uten angivelse søkes det etter data/eval.dat i programmappen eller dens overordnede mappe. |
--egaroucid PATH | Gjør klar Egaroucid for Console. Velg konsollprogrammet og behold resources-mappen på sin plass. På macOS og Linux brukes en programfil bygget etter den offisielle veiledningen. Stillingen og resttiden sendes via setboard, settime og go uten adapter. |
--nboard-depth N | Sender set depth N til NBoard-motoren. 0 til 60; 0 beholder motorens standard. (--edax: 0 → 60). |
--max-think-seconds S | Maksimalt antall sekunder det ventes på motoren per trekk. Standard 10, maksimum 300. Aldri lenger enn gjenværende tid på klokken minus 0,75 sekunder. Dette er en sikkerhetsgrense i tilkoblingsprogrammet; serveren har ingen tidsgrense per trekk. Med 0 fjernes grensen per trekk, og gjenværende spilletid brukes. |
--engine-name NAME | Motornavn som oppgis i botinformasjonen (høyst 120 tegn). Ikke ta med kommandoer eller stier. |
--cpu-name NAME | CPU-navn som skal oppgis (høyst 120 tegn). Oppdages automatisk hvis det utelates. |
--once-match ID | Håndterer bare denne kampen og avslutter når den er over (ferdig, annullert, utløpt, avvist). Negative ID-er for kamper mot mennesker fungerer også. Ved testing kan du kombinere det med --max-runtime. |
--max-runtime S | Rydder opp i motorene og avslutter etter dette antallet sekunder (avslutningskode 3). |
--no-stream | Bruker ikke hendelsesstrømmen; spør bare med jevne mellomrom. |
--api URL, --stream-url URL | Adresser til API og strøm. Behold vanligvis standardverdiene. Bare HTTPS godtas, og siden tokenet sendes med, må strømmen ligge på API-verten. |
Implementer API-et selv
Motta utfordringer og stillinger med agent_poll eller den autentiserte hendelsesstrømmen. Send agent_accept for ventende utfordringer der du er bot_b. Beregn deretter bare stillinger der det er din tur, i hvert parti i en pågående kamp. Send inn høyst én gang per match_id, parti og revision, og forkast utdatert arbeid når tilstanden endres. Kamper mot mennesker bruker negativ match_id og leg=0, og krever round_no og room_created_at nøyaktig slik de ble mottatt. I vanlige rom håndterer serveren tvungne pass; bare botpar sender inn pass.
agent_poll / bot-stream → pending (bot_b = my_id)
→ agent_accept → running → legs[0] + legs[1]
→ agent_move(match_id, leg, revision, move) → finished / abortedVarianter
En bot mottar bare spillene som er avkrysset under Støttede spill. game_mode i motorforespørsler og kamptilstand forteller hvilket spill det er. Serveren beregner brettstørrelse, blokkerte felter og lovlige felter, så motoren trenger bare å velge blant legal_moves den mottar. Ikke generer trekk for 10×10 eller klassisk Reversi med trekkgenerering for standard 8×8.
| Spill | game_mode | Brett | Startbrikker | Klokke (per parti, per farge) | Svarts første legal_moves |
|---|---|---|---|---|---|
| Standard | std | 8×8 | Tilfeldige 12 brikker | 60,000 ms | Avhenger av stillingen |
| Anti | anti | 8×8 | Tilfeldige 12 brikker | 60,000 ms | Avhenger av stillingen |
| Grand (10x10) | grand | 10×10 | Tilfeldige 12 brikker | 60,000 ms | Avhenger av stillingen |
| Octagon | octagon | 10×10 (88) | Tilfeldige 12 brikker | 60,000 ms | Avhenger av stillingen |
| Klassisk reversi | reversi | 8×8 | Tilfeldige 12 brikker | 60,000 ms | Avhenger av stillingen |
Felles regler: Svart (1) begynner. Begge partiene starter fra samme stilling med byttede farger og spilles samtidig. Hvis du i et botpar ikke har noe lovlig trekk, kommer legal_moves som en tom tabell, og boten må selv sende move=-1 (pass). Serveren melder ikke pass for deg, og klokken din fortsetter å gå. Det er ulovlig å melde pass når et lovlig trekk finnes. Et parti slutter når ingen av fargene kan trekke. Tomme felter gis ikke til noen; bare faktiske brikker summeres over begge partiene, og like summer er remis. Alle botpartier starter fra en tilfeldig stilling med 12 brikker. I alle spilltyper har hver bot 1 minutt i hvert parti.
Anti: brikker legges og snus som i standard Othello. Siden med færrest brikker totalt over begge partiene vinner.
10x10: standardregler på et 10×10-brett (100 felter). Startbrikkene står på de fire midtfeltene; botpar legger til 8 tilfeldige trekk og starter med 12 brikker.
Octagon: samme brett og startoppstilling som 10x10, men tre felter i hvert hjørne, 12 totalt, kan ikke brukes (88 spillbare felter). Blokkerte felter kommer som feltnumre i blocked_squares og som 0, samme verdi som tomt, i board. Tabellen er ikke i numerisk rekkefølge. Du kan ikke spille på et blokkert felt, og rekker av brikker stopper der.
Klassisk Reversi: starter etter reglene på et tomt brett. Så lenge ett av de fire midtfeltene (27, 28, 35, 36) er tomt, legger du bare der, og ingenting snus. Når alle fire er fylt, gjelder standardreglene. Hver farge legger høyst 32 brikker, medregnet de fire første trekkene. placed teller brikkene hver farge har lagt så langt; nøklene er strengene "1" (svart) og "2" (hvit). Botpar starter etter at serveren har lagt 12 tilfeldige brikker, medregnet de fire midttrekkene, så i den første forespørselen blir de to placed-tallene til sammen 12 (vanligvis {"1":6,"2":6}). En farge som har lagt alle 32, mottar en tom legal_moves og sender -1 hver gang det er dens tur.
Eksempler på motorforespørsler per spill
Eksempler på den første forespørselen for svart som tilkoblingsprogrammet sender til en motor med --engine, generert med regelkoden. Ekte kamper av alle typer starter fra en tilfeldig stilling med 12 brikker, så board og legal_moves er forskjellige i hver kamp. For at eksemplene skal være faste, er åpningstrekkene valgt nær midten av brettet. match_id og klokkeverdiene er også annerledes i ekte kamper.
Anti (anti)
{"board":[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,1,2,2,1,0,0,0,0,2,2,2,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[2,3,12,25,42,44,45],"game_mode":"anti","board_size":8,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Grand (10x10) (grand)
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[13,14,25,42,63,65,66],"game_mode":"grand","board_size":10,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Octagon (octagon)
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[13,14,25,42,63,65,66],"game_mode":"octagon","board_size":10,"blocked_squares":[0,1,10,8,9,19,80,90,91,89,98,99],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Klassisk reversi (reversi)
{"board":[0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,2,1,1,0,0,0,0,2,2,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[18,25,33,41,42,50,51],"game_mode":"reversi","board_size":8,"blocked_squares":[],"placed":{"1":6,"2":6},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Felter i motorforespørselen
| Felt | Type | Beskrivelse |
|---|---|---|
game_mode | string | Én av std, anti, grand, octagon, reversi. XOT i kamper mot mennesker kommer som std. |
board_size | integer 8 | 10 | 8, eller 10 for grand og octagon. |
board | integer[board_size²] | Tabell med lengde board_size². Leses fra a1 mot høyre og deretter neste rad. 0=tomt (inkludert blokkerte felter i Octagon), 1=svart, 2=hvit. |
blocked_squares | integer[] | Ubrukelige felter i Octagon. En tom tabell i andre spill. |
placed | {"1": integer, "2": integer} | Brikker lagt så langt per farge, medregnet de tilfeldige åpningstrekkene; nøklene er strengene "1" og "2". Brukes for grensen på 32 brikker i klassisk Reversi. |
legal_moves | integer[] | Felter du kan spille på nå. Hvis listen er tom, svarer du move=-1. |
color | integer 1 | 2 | Fargen som skal trekke. 1=svart, 2=hvit. |
budget_ms | integer | Tillatt tid for dette trekket i millisekunder: den minste av --max-think-seconds og gjenværende tid på klokken minus 0,75 sekunder. Tilkoblingsprogrammet stopper motoren når den overskrides. |
remaining_ms | integer | Gjenværende tid for fargen din i dette partiet, i millisekunder, etter at tiden som allerede er brukt i denne turen, er trukket fra. |
match_id | integer ≠ 0 | Kamp-ID. Negativ (-romnummer) for kamper mot mennesker. |
leg | integer 0 | 1 | Partinummer 0 eller 1. Alltid 0 for kamper mot mennesker. |
revision | integer | Tilstandsnummer for dette partiet. Send det uendret med agent_move. |
history | array | Trekk spilt i dette partiet. Ta avgjørelsen ut fra board. |
round_no | integer | null | Rundenummer i en kamp mot et menneske. null for botpar. |
room_created_at | string | null | Tidspunktet rommet for kampen mot et menneske ble opprettet. null for botpar. |
Utfordre en annen bot til en variant
Legg til game_mode i agent_challenge; standard er std. Begge botene må ha spillet i supported_games. Les motstanderens spill fra bots[].supported_games i svaret fra agent_poll. Hvis en av botene mangler spillet, er svaret HTTP 409 med feilen nedenfor.
{"action":"agent_challenge","target_id":2,"game_mode":"anti"}
{"action":"agent_challenge","target_name":"Opponent","game_mode":"grand"}HTTP 409
{"ok":false,"error":"unsupported game mode","server_now_ms":1800000000000}Endre supported_games
Registreringsskjemaet starter med Standard avkrysset, og eldre boter uten en lagret liste støtter std. Du kan bare endre listen under Administrer på botsiden på nettet, aldri med bottokenet (API). Endringen avvises mens en kamp pågår eller venter på å bli godtatt. En tom liste kan ikke lagres.
NBoard og varianter
En --nboard-tilkobling støtter bare standard (std). Når en variant kommer, spør ikke tilkoblingsprogrammet motoren og gir opp den turen (meldingen Engine failed for match). Ingen trekk sendes, så kampen annulleres før første trekk, eller partiet tapes på tid senere. Gi en NBoard-bot standard som eneste støttede spill.
Mennesker mot registrerte boter
Mennesker kan utfordre boten din i alle spill den har registrert. Hvis den støtter standard, kan både STD og XOT komme. XOT kommer med game_mode std og starter fra et brett der 8 trekk allerede er spilt (de er med i history). Den som utfordrer, velger klokken, og kampen teller ikke på ratingen. En kamp mot et menneske har ett parti (leg 0) og en negativ match_id. Serveren håndterer pass når ingen trekk er mulig, så ikke send -1. Registrerte boter på nett med automatisk paring på kan også delta i støttede STD/XOT-hurtigkamper. De er ratede for medlemmer og uratede for gjester.
Ulovlige trekk og tid
Et ulovlig trekk eller en utdatert revision avvises med HTTP 409 (illegal_move, stale_revision, not_your_turn), og brettet endres ikke. Klokken går imens. Tilkoblingsprogrammet sender det samme trekket på nytt med samme revision, så med mindre motoren rettes, tapes partiet til slutt på tid. Serveren har ingen grense per trekk og sjekker bare hver farges gjenværende tid. De 10 sekundene er standardverdien for --max-think-seconds i tilkoblingsprogrammet.
Autentisering
Bruk HTTPS, JSON POST og Authorization: Bearer. Tokenet gjelder én bot. Ikke skriv det i URL-er, offentlig kode eller logger.
Content-Type: application/json
Authorization: Bearer <FS_BOT_TOKEN>POST https://othelloclub.com/flipsight/bot_match_api.php
Kampregler
Alle botpartier starter fra en tilfeldig stilling med 12 brikker. To partier spilles samtidig med byttede farger. Samlet antall brikker avgjør vinneren; i Anti vinner færrest brikker.
Alle botpartier starter fra en tilfeldig stilling med 12 brikker. I alle spilltyper har hver bot 1 minutt i hvert parti.
Hvis en bot ikke har spilt sitt første trekk innen 30 sekunder etter start, annulleres kampen og teller ikke i ratingen. Hvis én bot mister tilkoblingen i mer enn 30 sekunder under kampen mens den andre er tilkoblet, vinner den tilkoblede boten (finish_reason: disconnect), og resultatet teller i ratingen.
Serveren beregner trekkene til FlipSight-boten i alle spilltyper. Både utfordringer på nettet og via API-et (agent_challenge) tas imot, og serveren starter kampen med en gang, så du trenger ikke holde spillrommet åpent. Hvis serverens beregning stopper i mer enn 30 sekunder, annulleres kampen (finish_reason: technical) og ratingen påvirkes ikke. Varianter er tunge å beregne, så høyst 2 variantkamper mot FlipSight-boter går samtidig. Er plassene fulle, får du HTTP 409 med site bot variant matches are full; prøv igjen om litt.
Automatiske botkamper: nettstedet holder alltid to rom med botkamper i gang. Mens en registrert bot med automatisk paring på er tilkoblet og ikke spiller, får den en utfordring til en standard botkamp (std) mot en bot med lignende rating (først en annen registrert bot, ellers en FlipSight-bot) som bot_b. Tilkoblingsprogrammet godtar automatisk, og kampen starter. Hvis boten ikke godtar innen 120 sekunder eller avslår, holdes den utenfor automatisk paring i 10 minutter. Automatiske kamper er ratet. Automatiske botkamper fortsetter mens Arena-partier pågår. Automatisk paring er på som standard og kan slås av under Administrer på botsiden. En bot som er startet med øvingsmotoren (environment.practice er true), holdes utenfor automatiske kamper, og kampene dens mot andre boter i den tiden er ikke ratet.
En direkte utfordring fra et menneske spilles som ett parti i et vanlig rom med støttet spill og tid. Serveren gjør alltid direkte utfordringer uratede. Registrerte boter på nett med automatisk paring på kan også delta i støttede STD/XOT-hurtigkamper. De er ratede for medlemmer og uratede for gjester. En registrert bot tar bare imot så mange partier som innstillingen for samtidige partier tillater (standard 2). Et parti mot et menneske og en botkamp (to brett) teller 1 hver.
pending → running → finished / aborted
pending → rejected / expired
kind=human: id=-room_id, legs[0], round_no, room_created_at
agent_move: move=19 / "d3" / "D3" (8×8)
10×10: "j10" = "J0" = 99
pass: -1 / "pass" / "PA" / "PS" / "--" (paired games only)
index=row*board_size+column (0-based)Kampforløp
Alle botpartier starter fra en tilfeldig stilling med 12 brikker. To partier spilles samtidig med byttede farger. Samlet antall brikker avgjør vinneren; i Anti vinner færrest brikker.
Deltakernummeret ditt er 0 hvis du er bot_a og 1 hvis du er bot_b. Deltaker 0 er svart (1) i legs[0] og hvit (2) i legs[1]; for deltaker 1 er det motsatt. Det er din tur når leg.status er active og leg.turn er din farge. Det kan være din tur i begge partiene samtidig.
Har du ikke noe lovlig trekk, må du selv sende move -1 (pass); serveren melder ikke pass for deg. I partier mot et menneske håndterer serveren pass som i vanlige spillrom.
På din tur er gjenstående tid = clocks_ms[din farge - 1] - (server_now_ms - turn_started_ms). clocks_ms er i fargerekkefølge (svart, hvit); totals og winner er i deltakerrekkefølge (winner 0 eller 1, null ved remis).
Feltnumre
Feltnummer = rad × 8 + kolonne, så a1=0, h1=7, a2=8 og h8=63. For eksempel er 19 d3 og 37 f5. board-tabellen bruker samme rekkefølge, med 0=tomt, 1=svart, 2=hvit.
a b c d e f g h
1 0 1 2 3 4 5 6 7
2 8 9 10 11 12 13 14 15
3 16 17 18 19 20 21 22 23
4 24 25 26 27 28 29 30 31
5 32 33 34 35 36 37 38 39
6 40 41 42 43 44 45 46 47
7 48 49 50 51 52 53 54 55
8 56 57 58 59 60 61 62 63På 10×10 (grand, octagon) er felt = rad × 10 + kolonne. Kolonnene er a til j, og den tiende raden skrives som 10 eller 0 i koordinater. a1=0, j1=9, a2=10, j10=99 (samme som j0). Samme koordinat har et annet nummer på hver brettstørrelse: d3 er 19 på 8×8 og 23 på 10×10.
a b c d e f g h i j
1 0 1 2 3 4 5 6 7 8 9
2 10 11 12 13 14 15 16 17 18 19
3 20 21 22 23 24 25 26 27 28 29
4 30 31 32 33 34 35 36 37 38 39
5 40 41 42 43 44 45 46 47 48 49
6 50 51 52 53 54 55 56 57 58 59
7 60 61 62 63 64 65 66 67 68 69
8 70 71 72 73 74 75 76 77 78 79
9 80 81 82 83 84 85 86 87 88 89
10 90 91 92 93 94 95 96 97 98 99Octagon (octagon)
a b c d e f g h i j
1 ## ## 2 3 4 5 6 7 ## ##
2 ## 11 12 13 14 15 16 17 18 ##
3 20 21 22 23 24 25 26 27 28 29
4 30 31 32 33 34 35 36 37 38 39
5 40 41 42 43 44 45 46 47 48 49
6 50 51 52 53 54 55 56 57 58 59
7 60 61 62 63 64 65 66 67 68 69
8 70 71 72 73 74 75 76 77 78 79
9 ## 81 82 83 84 85 86 87 88 ##
10 ## ## 92 93 94 95 96 97 ## ##Hendelsesstrøm
Koble til med samme Bearer-token til GET https://othelloclub.com/flipsight_api/bot-stream for å motta én JSON-hendelse per linje (NDJSON): hello bekrefter tilkoblingen, match betyr at en av kampene dine er endret (hendelser mellom boter inneholder hele kampobjektet), og ping er et keep-alive-signal hvert 10. sekund. Når du mottar match, kaller du agent_poll én gang. Hvis tilkoblingen brytes, kobler du til igjen med en ventetid som øker fra 1 til 30 sekunder, og fortsetter å spørre i mellomtiden. Mens strømmen er tilkoblet, vises boten din som tilkoblet; hver bot kan åpne opptil 3 strømmer.
Hendelseseksempler
curl -N 'https://othelloclub.com/flipsight_api/bot-stream' \
-H "Authorization: Bearer $FS_BOT_TOKEN"
{"type":"hello","bot_id":1,"server_now_ms":1800000000000}
{"type":"match","match":{"id":123,"bot_a":1,"bot_b":2,"status":"running","state":{...}},"server_now_ms":1800000000500}
{"type":"match","match":{"id":-45,"kind":"human","room_id":45},"server_now_ms":1800000003000}
{"type":"ping","server_now_ms":1800000010000}Motoradapter
FlipSight-bottilkoblingen (Python 3.9+, kun standardbiblioteket) kjører på Windows, macOS og Linux og kobler til en motor på to måter. --engine starter motoren én gang per parti, sender én JSON-linje for hvert trekk og leser én linje {"move": felt}. En motor som svarer én linje og avslutter, fungerer fortsatt fordi den startes på nytt ved neste trekk, men en motor som leser input til slutten (sys.stdin.read() osv.), svarer aldri, så les én linje om gangen. legal_moves i forespørselen viser de lovlige feltene; er listen tom, svar -1. --nboard holder en NBoard-motor i gang, én per parti; søkedybden settes med --nboard-depth.
Edax kan også kobles til med bare programstien via --edax nedenfor. En egen adapter trengs ikke; tilkoblingsprogrammet fordeler tenketiden per trekk fra gjenværende spilletid.
Gjør klar Egaroucid for Console. Velg konsollprogrammet og behold resources-mappen på sin plass. På macOS og Linux brukes en programfil bygget etter den offisielle veiledningen. Stillingen og resttiden sendes via setboard, settime og go uten adapter.
Inndata-JSON (tilkoblingsprogram → adapter)
Dette er eksempeldata fra tilkoblingsprogrammet, ikke kjørbar kode. Ikke lagre dem som en Python-fil. Under partiet sendes oppdaterte data automatisk for hvert trekk.
{"board":[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,1,2,2,1,0,0,0,0,2,2,2,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[2,3,12,25,42,44,45],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":40000,"match_id":123,"leg":1,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}Svar-JSON (adapter → tilkoblingsprogram)
{"move":2}Tilstandssynkronisering
Med strømmen tilkoblet kaller du agent_poll når en hendelse kommer, og hvert 10. sekund. Uten strøm spør du hvert sekund under en kamp og hvert 5. sekund når du venter, men aldri oftere enn én gang per sekund. Nettverkstid trekkes fra klokken din. Går svaret på et trekk tapt, henter du ny tilstand og sender samme trekk på nytt bare hvis revision er uendret.
API-handlinger
Svareksemplene viser formatet. Kopieringsknappen kopierer bare forespørselen og kaller ikke API-et.
POST agent_poll
Hent tilstand
| Parametere | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
action | string "agent_poll" | Påkrevd | Navnet på handlingen som kalles |
environment | object | Valgfritt | CPU, OS og motornavn for tilkoblings-PC-en (opptil 120 tegn hver, valgfritt) og practice (true eller false, valgfritt). practice true betyr at boten øver: Den holdes utenfor automatiske kamper, og botkamper som bes om eller godtas i den tiden, er ikke ratet. Tilkoblingsprogrammet sender den selv når det startes med øvingsmotoren. Serveren husker siste verdi, så send den uten practice eller med false når øvingen er over. |
Eksempel på forespørsel
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_poll","environment":{"cpu":"Apple M4","engine":"MyEngine","os":"Darwin"}}'Eksempel på svar
{
"ok": true,
"bots": [
{
"id": 1,
"name": "Opponent",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=1&v=1794474000000"
},
{
"id": 2,
"name": "MyBot",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std", "anti"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=2&v=1794474000000"
}
],
"record_bots": [],
"matches": [
{
"id": 123,
"bot_a": 1,
"bot_b": 2,
"game_mode": "std",
"time_limit_sec": 60,
"status": "running",
"state": {
"version": 1,
"game_mode": "std",
"time_limit_sec": 60,
"status": "active",
"revision": 1,
"started_ms": 1799999980000,
"last_now_ms": 1799999984200,
"finished_ms": null,
"opening_moves": [19, 20, 29, 34, 26, 11, 43, 37],
"opening_history": [
{
"color": 1,
"move": 19
},
{
"color": 2,
"move": 20
},
{
"color": 1,
"move": 29
},
{
"color": 2,
"move": 34
},
{
"color": 1,
"move": 26
},
{
"color": 2,
"move": 11
},
{
"color": 1,
"move": 43
},
{
"color": 2,
"move": 37
}
],
"legs": [
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 1, 2, 2, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"turn": 2,
"black_participant": 0,
"placed": {
"1": 5,
"2": 4
},
"clocks_ms": [55800, 60000],
"turn_started_ms": 1799999984200,
"revision": 1,
"history": [
{
"color": 1,
"participant": 0,
"move": 44,
"at_ms": 1799999984200
}
],
"status": "active",
"discs": [5, 8],
"finished_ms": null,
"legal_moves": [18, 21, 22, 25, 30, 33, 38, 42, 50, 51, 52]
},
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"turn": 1,
"black_participant": 1,
"placed": {
"1": 4,
"2": 4
},
"clocks_ms": [60000, 60000],
"turn_started_ms": 1799999980000,
"revision": 0,
"history": [],
"status": "active",
"discs": [3, 9],
"finished_ms": null,
"legal_moves": [2, 3, 12, 25, 42, 44, 45]
}
],
"totals": [14, 11],
"winner": null,
"finish_reason": null,
"board_size": 8,
"blocked_squares": []
},
"auto": false,
"expires_ms": 1800000080000,
"ranked": true,
"rating_applied": false,
"rating_before": [null, null],
"rating_after": [null, null],
"created_at": "2026-11-12 19:00:00"
}
],
"me": "example",
"bot": {
"id": 2,
"name": "MyBot",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std", "anti"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=2&v=1794474000000"
},
"server_now_ms": 1800000000000
}Kampobjekt (matches[])
| Felt | Type | Beskrivelse |
|---|---|---|
id | integer | Kamp-ID (negativ for partier mot et menneske) |
kind | string | human for partier mot et menneske |
bot_a | integer | Bot-ID for deltaker 0 (0 for et menneske) |
bot_b | integer | Bot-ID for deltaker 1 (0 for et menneske) |
game_mode | string | Spill (std, anti, grand, octagon, reversi) |
time_limit_sec | integer | Sekunder per parti, per farge |
status | string | pending, running, finished, aborted, rejected, expired |
expires_ms | integer | Frist for godkjenning (millisekunder) |
ranked | boolean | Om kampen er ratet |
state.status | string | active, finished eller aborted |
state.game_mode | string | Spill (std, anti, grand, octagon, reversi) |
state.board_size | integer 8 | 10 | Felter per side, 8 eller 10 |
state.blocked_squares | integer[] | Ubrukelige felter (bare Octagon, ikke sortert) |
state.legs | array | Partier (2 mellom boter, 1 mot et menneske) |
state.totals | [integer, integer] | Sum brikker fra begge partier per deltaker |
state.winner | integer | null | Vinnende deltaker 0 eller 1, null ved remis |
state.finish_reason | string | null | discs, timeout, double_timeout, disconnect, no_first_move |
Partiobjekt (state.legs[])
| Felt | Type | Beskrivelse |
|---|---|---|
board | integer[64 | 100] | 64 / 100 felt, 0=tomt 1=svart 2=hvit |
turn | integer | Fargen som er i trekket, 1 (svart) eller 2 (hvit) |
legal_moves | integer[] | Lovlige felter for fargen som skal trekke. Tom for ferdige partier |
placed | {"1": integer, "2": integer} | Lagte brikker per farge, nøkler "1" (svart) og "2" (hvit) |
black_participant | integer | Deltakeren som spiller svart i dette partiet |
clocks_ms | [number, number] | Grunnverdier for gjenstående tid i fargerekkefølge (svart, hvit) |
turn_started_ms | integer | Servertid da gjeldende tur startet |
revision | integer | Øker med 1 hver gang dette partiet endres |
status | string | active, finished, timeout, stopped |
history | array | Spilte trekk (color, participant, move, at_ms) |
discs | [integer, integer] | Antall brikker i fargerekkefølge (svart, hvit) |
result_discs | [integer, integer] (optional) | Valgfri tildelt poengsum [svart, hvit] for et parti tapt på tid; legg den sammen i stedet for brikkene. Poengsum for siden som gikk tom for tid, og for motstanderen: std og reversi 0 til 64, grand 0 til 100, octagon 0 til 88, anti 64 til 0. Det andre partiet fortsetter, og summene avgjør vinneren når begge partiene er ferdige. Eldre avsluttede registreringer blir ikke beregnet på nytt. |
POST agent_challenge
Utfordre
Angi target_id (bot-ID) eller target_name (botnavn), som står i listen bots i svaret fra agent_poll. Innebygde FlipSight-boter (is_builtin: true) kan utfordres via API-et i alle spilltyper, og serveren starter kampen med en gang. Er det allerede 2 variantkamper mot innebygde boter, får du HTTP 409 med site bot variant matches are full.
| Parametere | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
action | string "agent_challenge" | Påkrevd | Navnet på handlingen som kalles |
target_id | integer ≥ 1 | Valgfritt | ID-en til boten som utfordres |
target_name | string | Valgfritt | Navnet på boten som utfordres (i stedet for target_id) |
game_mode | string std | anti | octagon | grand | reversi | Valgfritt | Spill for et botpar. Standard er std. Begge botene må støtte det. Standard / Anti / Octagon / Grand (10x10) / Klassisk reversi |
Eksempel på forespørsel
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_challenge","target_id":2,"game_mode":"anti"}'Eksempel på svar
{
"ok": true,
"match_id": 123,
"server_now_ms": 1800000000000
}POST agent_accept
Godta
| Parametere | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
action | string "agent_accept" | Påkrevd | Navnet på handlingen som kalles |
match_id | integer ≥ 1 | Påkrevd | Kamp-ID (negativ for partier mot et menneske) |
Eksempel på forespørsel
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_accept","match_id":123}'Eksempel på svar
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_reject
Avslå
| Parametere | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
action | string "agent_reject" | Påkrevd | Navnet på handlingen som kalles |
match_id | integer ≥ 1 | Påkrevd | Kamp-ID (negativ for partier mot et menneske) |
Eksempel på forespørsel
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_reject","match_id":123}'Eksempel på svar
{
"ok": true,
"match": {
"id": 123,
"status": "rejected",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_move
Send trekk
| Parametere | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
action | string "agent_move" | Påkrevd | Navnet på handlingen som kalles |
match_id | integer ≠ 0 | Påkrevd | Kamp-ID (negativ for partier mot et menneske) |
round_no | integer ≥ 0 | Valgfritt | Bare partier mot et menneske: round_no fra kampobjektet |
room_created_at | string | Valgfritt | Bare partier mot et menneske: room_created_at fra kampobjektet |
leg | integer 0 | 1 | Påkrevd | Parti 0 eller 1 (0 for partier mot et menneske) |
revision | integer ≥ 0 | Påkrevd | revision for partiet trekket ble beregnet for; 409 stale_revision hvis partiet er endret |
move | integer -1..99 | string | Påkrevd | Felt 0-(board_size²−1), -1 for pass / d3 / D3 / pass |
Eksempel på forespørsel
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_move","match_id":123,"leg":1,"revision":0,"move":2}'Eksempel på svar
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}Feil
Feil ser slik ut: {"ok": false, "error": "…"}. Ved 401: stopp og sjekk tokenet. Ved 409: hent gjeldende tilstand og sjekk tur, revision og lovlige trekk. 429 betyr for mange strømmer for én bot. Prøv tilkoblingsfeil og 503 på nytt med økende ventetid, og send aldri et ulovlig trekk på nytt.
{"ok":false,"error":"stale_revision","server_now_ms":1800000000000}| HTTP | error |
|---|---|
| 400 | JSON object required / unknown action |
| 401 | invalid bot credential |
| 403 | access denied / invalid csrf |
| 405 | POST required |
| 409 | stale_revision / not_your_turn / illegal_move / leg_finished / match not running / match timed out / stale room revision / invalid move coordinate / move outside board / unsupported game mode / both bots must be connected / bot already has an active match / bot busy / challenge expired or answered / site bot variant matches are full / target bot not found |
| 413 | request too large |
| 429 | too many streams (bot-stream) |
| 503 | bot match storage unavailable |