API-dokumentasjon

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.

ls

5. 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 --version

Windows PowerShell

py --version

Slik 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.

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_TOKEN

Windows PowerShell

$env:FS_BOT_TOKEN = [Net.NetworkCredential]::new('', (Read-Host 'Bot token' -AsSecureString)).Password

På 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.py

Windows 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 Minimized

10. 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.6

Start

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-64

Start

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 --install
tar -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.

Egaroucid for Console

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.

FlipSight→ bot_match_client.py→ my_adapter.py
FlipSight← bot_match_client.py← my_adapter.py

Hva 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.py

Windows 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.py

2. 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 1777

my_engine → my_adapter.py

D3
import 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.

Felter i motorforespørselen

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

BegrepBetydning
APIEn avtalt måte for programmer å sende forespørsler og svar på. Tilkoblingsprogrammet tar seg av det for deg.
TokenEt passord bare for boten din. Tilkoblingsprogrammet bruker det til å bevise overfor serveren hvilken bot det er.
TerminalEt vindu der du skriver kommandoer. På Windows bruker du PowerShell.
MiljøvariabelEn midlertidig innstilling som gis videre til programmer som startes fra ett terminalvindu. Den forsvinner når vinduet lukkes.
JSONEt format for å skrive data som tekst. Eksempel: {"move":19}
MotorEt program som ser på en stilling og velger et trekk.
AdapterEt lite program som oversetter data mellom motoren din og tilkoblingsprogrammet.
NBoardNBoard 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 trekkEt felt du kan spille på nå. Serveren lister dem i legal_moves.

Nedlastinger

Last ned Python-eksempler

OpenAPI 3.1 JSON

README.md

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.

ParametereBeskrivelse
--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 PATHEdax 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 PATHSti til Edax eval.dat. Uten angivelse søkes det etter data/eval.dat i programmappen eller dens overordnede mappe.
--egaroucid PATHGjø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 NSender set depth N til NBoard-motoren. 0 til 60; 0 beholder motorens standard. (--edax: 0 → 60).
--max-think-seconds SMaksimalt 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 NAMEMotornavn som oppgis i botinformasjonen (høyst 120 tegn). Ikke ta med kommandoer eller stier.
--cpu-name NAMECPU-navn som skal oppgis (høyst 120 tegn). Oppdages automatisk hvis det utelates.
--once-match IDHå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 SRydder opp i motorene og avslutter etter dette antallet sekunder (avslutningskode 3).
--no-streamBruker ikke hendelsesstrømmen; spør bare med jevne mellomrom.
--api URL, --stream-url URLAdresser 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 / aborted

Varianter

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.

Spillgame_modeBrettStartbrikkerKlokke (per parti, per farge)Svarts første legal_moves
Standardstd8×8Tilfeldige 12 brikker60,000 msAvhenger av stillingen
Antianti8×8Tilfeldige 12 brikker60,000 msAvhenger av stillingen
Grand (10x10)grand10×10Tilfeldige 12 brikker60,000 msAvhenger av stillingen
Octagonoctagon10×10 (88)Tilfeldige 12 brikker60,000 msAvhenger av stillingen
Klassisk reversireversi8×8Tilfeldige 12 brikker60,000 msAvhenger 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

FeltTypeBeskrivelse
game_modestringÉn av std, anti, grand, octagon, reversi. XOT i kamper mot mennesker kommer som std.
board_sizeinteger 8 | 108, eller 10 for grand og octagon.
boardinteger[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_squaresinteger[]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_movesinteger[]Felter du kan spille på nå. Hvis listen er tom, svarer du move=-1.
colorinteger 1 | 2Fargen som skal trekke. 1=svart, 2=hvit.
budget_msintegerTillatt 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_msintegerGjenværende tid for fargen din i dette partiet, i millisekunder, etter at tiden som allerede er brukt i denne turen, er trukket fra.
match_idinteger ≠ 0Kamp-ID. Negativ (-romnummer) for kamper mot mennesker.
leginteger 0 | 1Partinummer 0 eller 1. Alltid 0 for kamper mot mennesker.
revisionintegerTilstandsnummer for dette partiet. Send det uendret med agent_move.
historyarrayTrekk spilt i dette partiet. Ta avgjørelsen ut fra board.
round_nointeger | nullRundenummer i en kamp mot et menneske. null for botpar.
room_created_atstring | nullTidspunktet 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 63

På 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 99

Octagon (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

ParametereTypePåkrevdBeskrivelse
actionstring "agent_poll"PåkrevdNavnet på handlingen som kalles
environmentobjectValgfrittCPU, 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[])

FeltTypeBeskrivelse
idintegerKamp-ID (negativ for partier mot et menneske)
kindstringhuman for partier mot et menneske
bot_aintegerBot-ID for deltaker 0 (0 for et menneske)
bot_bintegerBot-ID for deltaker 1 (0 for et menneske)
game_modestringSpill (std, anti, grand, octagon, reversi)
time_limit_secintegerSekunder per parti, per farge
statusstringpending, running, finished, aborted, rejected, expired
expires_msintegerFrist for godkjenning (millisekunder)
rankedbooleanOm kampen er ratet
state.statusstringactive, finished eller aborted
state.game_modestringSpill (std, anti, grand, octagon, reversi)
state.board_sizeinteger 8 | 10Felter per side, 8 eller 10
state.blocked_squaresinteger[]Ubrukelige felter (bare Octagon, ikke sortert)
state.legsarrayPartier (2 mellom boter, 1 mot et menneske)
state.totals[integer, integer]Sum brikker fra begge partier per deltaker
state.winnerinteger | nullVinnende deltaker 0 eller 1, null ved remis
state.finish_reasonstring | nulldiscs, timeout, double_timeout, disconnect, no_first_move

Partiobjekt (state.legs[])

FeltTypeBeskrivelse
boardinteger[64 | 100]64 / 100 felt, 0=tomt 1=svart 2=hvit
turnintegerFargen som er i trekket, 1 (svart) eller 2 (hvit)
legal_movesinteger[]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_participantintegerDeltakeren som spiller svart i dette partiet
clocks_ms[number, number]Grunnverdier for gjenstående tid i fargerekkefølge (svart, hvit)
turn_started_msintegerServertid da gjeldende tur startet
revisionintegerØker med 1 hver gang dette partiet endres
statusstringactive, finished, timeout, stopped
historyarraySpilte 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.

Utfordre fra botsiden

ParametereTypePåkrevdBeskrivelse
actionstring "agent_challenge"PåkrevdNavnet på handlingen som kalles
target_idinteger ≥ 1ValgfrittID-en til boten som utfordres
target_namestringValgfrittNavnet på boten som utfordres (i stedet for target_id)
game_modestring std | anti | octagon | grand | reversiValgfrittSpill 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

ParametereTypePåkrevdBeskrivelse
actionstring "agent_accept"PåkrevdNavnet på handlingen som kalles
match_idinteger ≥ 1PåkrevdKamp-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å

ParametereTypePåkrevdBeskrivelse
actionstring "agent_reject"PåkrevdNavnet på handlingen som kalles
match_idinteger ≥ 1PåkrevdKamp-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

ParametereTypePåkrevdBeskrivelse
actionstring "agent_move"PåkrevdNavnet på handlingen som kalles
match_idinteger ≠ 0PåkrevdKamp-ID (negativ for partier mot et menneske)
round_nointeger ≥ 0ValgfrittBare partier mot et menneske: round_no fra kampobjektet
room_created_atstringValgfrittBare partier mot et menneske: room_created_at fra kampobjektet
leginteger 0 | 1PåkrevdParti 0 eller 1 (0 for partier mot et menneske)
revisioninteger ≥ 0Påkrevdrevision for partiet trekket ble beregnet for; 409 stale_revision hvis partiet er endret
moveinteger -1..99 | stringPåkrevdFelt 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}
HTTPerror
400JSON object required / unknown action
401invalid bot credential
403access denied / invalid csrf
405POST required
409stale_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
413request too large
429too many streams (bot-stream)
503bot match storage unavailable
Copyright © Othelloclubthe.othelloclub.com@gmail.com All rights reserved.