Vaiheittainen opas aloittelijoille
Mitä tarvitset
- FlipSight-tili. Voit rekisteröidä botin ja ladata yhteysohjelman, kun olet kirjautunut sisään.
- Yksi botin kuva: GIF-, JPG- tai PNG-tiedosto, enintään 5 Mt, leveys ja korkeus vähintään 175 px.
- Oma tietokone botin käyttämiseen Bottisi siirrot lasketaan tietokoneella, jossa yhdistin on käynnissä. Samallakin moottorilla vahvuus voi vaihdella tietokoneen tehon ja moottorin asetusten mukaan, ja jos vaihdat tietokonetta tai asetuksia, vahvuusluku voi muuttua sen mukaisesti.
- Python 3, ilmainen ohjelma, joka suorittaa yhteysohjelman. Versio 3.9 tai uudempi toimii; 3.11 tai uudempi on suositeltava. Tarkistat sen vaiheessa 5.
- Oma bottimoottori. Yhteysohjelman mukana tulee harjoitusmoottori testaamista varten.
1. Rekisteröi bottisi
Kirjaudu sisään ja avaa bottisivu (othelloclub.com/fi/flipsight/bot). Kirjoita yläosan ruudussa Rekisteröi bottini nimi kenttään Botin nimi (2–24 merkkiä). Jätä kohdassa Tuetut pelit toistaiseksi valituksi vain Standard. Valitse kuva kohdassa Lataa botin kuva ja paina sitten painiketta Rekisteröi bottini.
Onnistuminen näyttää tältä: näkyviin tulee ruutu Yhteystunniste (näytetään vain kerran), jossa on pitkä teksti, joka alkaa merkeillä fsbm_.
2. Ota tunniste talteen
Tämä pitkä teksti on tunniste, vain bottiasi varten oleva salasana. Yhteysohjelma todistaa sillä palvelimelle, että se toimii tämän botin puolesta. Kopioi se kokonaan ja liitä se väliaikaisesti jonnekin, esimerkiksi tekstieditoriin. Kun suljet ruudun, et näe samaa tunnistetta enää uudelleen.
Käsittele tunnistetta kuin salasanaa. Älä näytä sitä kenellekään äläkä julkaise siitä kuvakaappausta. Jos kadotat sen tai joku näkee sen, avaa bottiluettelossa Hallitse ja paina Luo yhteystunniste. Kun saat uuden tunnisteen, vanha lakkaa toimimasta heti.
3. Lataa yhteysohjelma
Lataa ZIP-tiedosto painamalla Lataa Python-esimerkit ja pura se. Tässä oppaassa purettua kansiota kutsutaan nimellä ”bottikansio”. Sijoita se paikkaan, josta löydät sen helposti, esimerkiksi työpöydälle.
Onnistuminen näyttää tältä: bottikansiossa on README.md-tiedosto ja tools-kansio.
4. Avaa pääte bottikansiossa
Pääte on ikkuna, johon kirjoitetaan komentoja. Avaa se järjestelmäsi mukaan seuraavasti.
macOS: paina Command+Space, kirjoita Terminal ja avaa se. Kirjoita cd ja yksi välilyönti, vedä bottikansio ikkunaan ja paina sitten Enter.
Linux: napsauta tiedostonhallinnassa bottikansiota hiiren oikealla painikkeella ja valitse Avaa päätteessä. Valikon nimi voi vaihdella jakeluittain. Jos tällaista valikkoa ei ole, avaa pääte ja käytä komentoa cd kuten macOSissa.
Windows: avaa bottikansio Resurssienhallinnassa. Kirjoita yläreunan osoiteriville powershell ja paina Enter. Kansioon avautuu PowerShell-ikkuna.
Tarkistus: kirjoita alla oleva komento ja paina Enter. Onnistuminen tarkoittaa, että luettelossa näkyvät README.md ja tools. Komento on sama macOSissa, Linuxissa ja Windowsin PowerShellissä.
ls5. Tarkista Python
Kopioi samassa ikkunassa järjestelmääsi vastaava komento, liitä se ja paina Enter. Voit käyttää kunkin koodiruudun oikeassa yläkulmassa olevaa kopiointipainiketta.
macOS / Linux
python3 --versionWindows PowerShell
py --versionOnnistuminen näyttää tältä: 3:lla alkava versio, esimerkiksi Python 3.11.9. Versio 3.9 tai uudempi toimii. Jos komentoa ei löydy, asenna Python alla olevien ohjeiden mukaan, sulje ikkuna ja aloita uudelleen vaiheesta 4.
macOS: lataa python.org-sivustolta macOS-asennusohjelma (.pkg) ja asenna se. Suorita sitten kerran Install Certificates.command Ohjelmat-kansion Python-kansiosta. Se valmistelee suojattuihin (HTTPS) yhteyksiin tarvittavat varmenteet.
Linux: asenna python3 jakelusi ohjelmistokeskuksella tai paketinhallinnalla.
Windows: asenna Python install manager python.org-sivustolta.
6. Syötä tunniste
Tallenna tunniste ympäristömuuttujaan. Se on väliaikainen asetus, joka on olemassa vain tässä pääteikkunassa. Sen nimi on FS_BOT_TOKEN. Kopioi alta järjestelmääsi vastaava yksirivinen komento, liitä se ja paina Enter kerran. Näkyviin tulee Bot token, ja se odottaa syötettäsi. Liitä nyt vaiheessa 2 kopioimasi tunniste ja paina 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)).PasswordmacOSissa ja Linuxissa liitettyä tunnistetta ei näytetä, ja Windowsissa näet merkkien tilalla *. Molemmat ovat normaaleja. Koska tunnistetta ei kirjoiteta komentoon, se ei jää komentohistoriaan. Asetus on voimassa vain tässä ikkunassa. Jos suljit sen tai avasit uuden ikkunan, toista vaiheet 4 ja 6.
Windows: PowerShellissä liität Ctrl+V-näppäinyhdistelmällä tai hiiren oikealla painikkeella. Tämä yksirivinen komento käyttää kirjoitustapaa, joka toimii sekä Windowsin mukana tulevassa Windows PowerShell 5.1 -versiossa että uudemmassa PowerShell 7 -versiossa, mutta sitä ei ole vielä testattu oikealla Windows-koneella.
Onnistuminen näyttää tältä: seuraavan komennon kehote palaa ilman virhettä.
7. Käynnistä yhteysohjelma
Kopioi samassa ikkunassa alla oleva komento sellaisenaan, liitä se ja paina Enter. Älä muuta sen tiedostonimiä. Bottisi yhdistyy harjoitusmoottorilla. Se on hyvin heikko moottori, joka pelaa sen laillisen ruudun, jolla on pienin numero.
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'On normaalia, ettei komento tulosta tekstiä eikä palaa komentokehotteeseen ollessaan käynnissä. Pidä tämä ikkuna auki, yhteysohjelma ja pelimoottori käynnissä sekä estä tietokonetta siirtymästä lepotilaan, jotta botti pysyy verkossa. Ikkunan sulkeminen tai Ctrl+C lopettaa molemmat ohjelmat ja katkaisee botin yhteyden. Suorita yllä oleva komento uudelleen yhdistääksesi botin. Yhteysohjelma hyväksyy muiden bottien haasteet automaattisesti.
Niin kauan kuin botti toimii harjoitusmoottorilla, se ei saa automaattisia otteluita, eivätkä sen ottelut muita botteja vastaan, edes itse pyydetyt, vaikuta vahvuuslukuun. Käynnistä se uudelleen omalla moottorillasi (vaihe 10), niin siitä lähtien se saa pareja ja ottelut vaikuttavat vahvuuslukuun.
Onnistuminen näyttää tältä: bottisivun luettelossa Rekisteröidyt botit bottisi nimen oikealla puolella oleva pallo on vihreä. Kun viet osoittimen sen päälle, näkyy Paikalla. Jos se on harmaa (Poissa), paina Päivitä.
8. Testaa ensimmäisellä ottelulla
Valitse bottisivulla bottisi kohdassa Pelaava bottini. Valitse mikä tahansa botti luettelosta FlipSight-botit, paina Haasta ja vahvista avautuvassa ikkunassa. Kaikissa pelityypeissä palvelin laskee FlipSight-bottien siirrot, joten pelihuonetta ei tarvitse pitää auki. Kun automaattinen parinmuodostus on päällä (oletus), sivusto järjestää myös bottiotteluita, kun yhteysohjelma on käynnissä.
Onnistuminen näyttää tältä: pelihuoneessa näkyy kaksi lautaa, ja bottisi asettaa nappulan jokaisella vuorollaan. Harjoitusmoottori on hyvin heikko, joten häviäminen on normaalia.
9. Pidä käynnissä ikkunan sulkemisen jälkeen (valinnainen)
Käynnistä vaiheen 7 sijaan alla olevalla komennolla, niin botti jatkaa toimintaansa, vaikka suljet ikkunan. Suorita se samassa ikkunassa, jossa syötit tunnisteen (vaihe 6). Se pysähtyy, jos tietokone sammuu tai menee lepotilaan. Jos pysäytät sen kesken ottelun, häviät sen ottelun ajan loppumiseen tai yhteyden katkeamiseen.
macOS / Linux
macOS / Linux: käynnistyskomennon suorittamisen jälkeen voit sulkea ikkunan. Viestit kirjoitetaan bottikansion bot.log-tiedostoon. Pysäytä botti avaamalla uusi pääte ja suorittamalla pysäytyskomento. Kopioi vain tarvitsemasi laatikko: jos liität molemmat laatikot kerralla, botti pysähtyy heti käynnistyttyään.
Käynnistys
nohup python3 tools/bot_match_client.py --engine 'python3 tools/bot_match_example_engine.py' > bot.log 2>&1 &Pysäytys
pkill -f bot_match_client.pyWindows PowerShell
Windows: tehtäväpalkkiin ilmestyy pienennetty ikkuna, jossa botti toimii. Voit sulkea nykyisen PowerShell-ikkunan. Pysäytä botti avaamalla pienennetty ikkuna ja painamalla Ctrl+C tai sulkemalla kyseinen ikkuna.
Käynnistys
Start-Process py -ArgumentList 'tools/bot_match_client.py --engine "py tools/bot_match_example_engine.py"' -WorkingDirectory $PWD -WindowStyle Minimized10. Vaihda omaan moottoriisi
Yhteystestin jälkeen vaihda omaan moottoriisi: Edaxille ja Egaroucidille alla olevat omat valitsimet, muille yhteensopiville --nboard ja itse tehdylle moottorille JSON. Tunniste pysyy samana.
Valitse kohdassa Tuetut pelit pelimuunnelma (Anti, 10x10, Octagon, klassinen Reversi) vain, jos moottorisi tuntee sen säännöt. Muut botit ja ihmiset voivat haastaa bottisi kaikissa valituissa peleissä. Muuta valintaa avaamalla bottiluettelossa Hallitse, muokkaamalla kohtaa Tuetut pelit ja painamalla Tallenna. Et voi muuttaa sitä, kun ottelu on käynnissä tai haaste odottaa.
Moottoripyyntöjen esimerkit peleittäin
Yhdistä NBoard-yhteensopiva pelimoottori, kuten Edax
NBoard on graafinen Othello-ohjelma, jota voi käyttää NTestin kanssa. NBoard-protokolla on sen julkinen viestintämuoto pelimoottoreille ja toimii sitä tukevien moottorien, kuten NTestin ja Edaxin, kanssa.
Alla olevissa asennus- ja käynnistysesimerkeissä käytetään Edax 4.6:ta ja Egaroucid for Console 7.8.2:ta.
Edax 4.6 ei sisälly yhteysohjelmaan. Lataa käyttöjärjestelmäsi tiedosto kohdan Edax 4.6 Assets-osiosta, siirrä se bottikansioon ja pura se alla olevilla valmistelukomennoilla. Windows- ja Linux-komennot ovat x86-64-tietokoneille.
Windows PowerShell (x86-64): edax-4.6-MS-windows-x86.zip
Valmistelu (vain ensimmäisellä kerralla)
Expand-Archive -LiteralPath edax-4.6-MS-windows-x86.zip -DestinationPath edax-4.6Käynnistys
py tools/bot_match_client.py --edax "edax-4.6\wEdax-x86-64.exe"Linux (x86-64): edax-4.6-linux-x86.tar.gz
Valmistelu (vain ensimmäisellä kerralla)
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-64Käynnistys
python3 tools/bot_match_client.py --edax "edax-4.6/lEdax-x86-64"macOS: edax-reversi-4.6.tar.gz
Edax 4.6:sta ei ole virallista macOS-ohjelmatiedostoa. Lataa saman julkaisun Source code (tar.gz) ja edax-4.6-linux-x86.tar.gz. Käännä Mac-ohjelma lähdekoodista ja poimi Linux-arkistosta vain yhteinen arviointitiedosto data/eval.dat. Xcode Command Line Tools tarvitaan. Valmistelukomennot kääntävät lähdekoodin.
Valmistelu (vain ensimmäisellä kerralla)
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)Käynnistys
python3 tools/bot_match_client.py --edax "edax-4.6/bin/mEdax-native"Edax voidaan yhdistää myös pelkällä ohjelmapolulla käyttäen alla olevaa --edax-valintaa. Erillistä sovitinta ei tarvita; yhdistämisohjelma jakaa miettimisajan siirroille jäljellä olevan peliajan perusteella.
Korvaa komennon polku oman ohjelmasi täydellä polulla. Laita välilyöntejä sisältävät polut lainausmerkkeihin. Jos arviointitiedostoa ei löydy automaattisesti, määritä eval.dat valitsimella --edax-eval.
NBoard-yhteys pelaa vain tavallisia 8×8-pelejä. Jätä tämän botin kohtaan Tuetut pelit valituksi vain Standard. Jos saapuu pelimuunnelma, yhteysohjelma ei kysy moottorilta, siirtoa ei pelata, ja peli mitätöidään tai hävitään ajan loppumiseen.
Egaroucid: --egaroucid
Valmistele Egaroucid for Console. Valitse konsoliohjelma ja säilytä resources-kansio paikallaan. macOS- ja Linux-järjestelmissä käytetään virallisten ohjeiden mukaan käännettyä ohjelmaa. Asema ja jäljellä oleva aika välitetään komennoilla setboard, settime ja go ilman sovitinta.
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"Molemmat tilat tukevat vain tavallista 8×8-peliä, yksi moottori kutakin samanaikaista peliä kohti. --max-think-seconds on siirron turvaraja (oletus 10 sekuntia). Jos Egaroucid saavuttaa rajan, haku lopetetaan, tehdään laillinen varasiirto ja moottori käynnistetään seuraavalla vuorolla uudelleen.
Itse tehty moottori: yhdistä JSONin kautta
Lue tämä osa vain, jos haluat liittää itse kirjoittamasi moottorin. Jos käytössäsi on Edax, Egaroucid tai jokin muu NBoard-moottori, olet jo valmis yllä olevien ohjeiden jälkeen ja voit ohittaa tämän osan.
Aina kun on bottisi vuoro, yhteysohjelma suorittaa tiedoston my_adapter.py kerran. Se antaa nykyisen aseman yhtenä rivinä (missä nappulat ovat, kenen vuoro on, mitkä ruudut ovat laillisia, paljonko aikaa on jäljellä), my_adapter.py vastaa yhdellä ruudulla yhtenä rivinä, ja yhteysohjelma pelaa sen siirron palvelimella. my_adapter.py on pieni Python-tiedosto niiden välissä, ja se kysyy siirron moottoriltasi. Yhteysohjelma hoitaa palvelinyhteyden, tunnisteen ja siirtojen lähettämisen, joten tämän tiedoston ei tarvitse koskaan huolehtia niistä.
bot_match_client.py→ my_adapter.pybot_match_client.py← my_adapter.pyMillainen moottorisi on?
- Moottori, joka valitsee siirtonsa Python-koodissa: käytä alla olevaa esimerkkiä A.
- Ohjelmatiedosto, joka tulostaa yhden vastausrivin ja sulkeutuu joka kerta, kun se suoritetaan: käytä alla olevaa esimerkkiä B.
- Ohjelmatiedosto, joka pysyy auki ja vaihtaa komentoja jatkuvasti: jos se tukee NBoardia, liitä se yllä olevalla --nboard-valinnalla. Muulla protokollalla sovita esimerkki B siihen ja anna my_adapter.py:n pitää moottori auki ja vaihtaa rivi kerrallaan silmukassa.
Vaihe 1: tiedosto, joka vain tarkistaa yhteyden (my_adapter.py)
Luo bottikansioon (jossa README.md ja tools ovat) tiedosto nimeltä my_adapter.py, liitä alla oleva koodi siihen sellaisenaan ja tallenna. Tämä tiedosto ei käytä mitään moottoria, vaan vastaa yksinkertaisesti ensimmäisellä laillisella ruudulla. Sen avulla varmistat, että yhteys toimii, ennen kuin liität oman moottorisi.
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)
Tarkista syöte ja tuloste ennen yhdistämistä
Laatikon 1 komento syöttää esimerkkiaseman suoraan sovittimelle. Sen pitäisi tulostaa yksi rivi: {"move": 19}. Kun näet tämän rivin, laatikon 2 komento käynnistää yhteysohjelman tällä sovittimella siinä ikkunassa, jossa on vaiheen 6 tunniste. Suorita kaksi laatikkoa erikseen. Jos moottorisi lukee tätä JSON-muotoa itse, voit kirjoittaa sen komennon suoraan valitsimen --engine perään.
1. Testaa pelkkä sovitin
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. Käynnistä yhteysohjelma sovittimen kanssa
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'Vaihe 2: vaihda tiedostoon, joka kutsuu moottoriasi
Kun vaihe 1 toimii, korvaa tiedoston my_adapter.py koko sisältö alla olevalla esimerkillä A tai B. Muuta vain EDIT-merkityt rivit ja jätä muu ennalleen. Suorita sitten yllä oleva testikomento 1 uudelleen ja tarkista, että näkyviin tulee yksi vastausrivi. Siirron valitsi nyt moottorisi, joten on normaalia, että ruutu on jokin muu kuin 19.
Esimerkki A: moottori, joka valitsee siirtonsa Python-funktiolla
Tässä esimerkissä oletetaan, että on tiedosto nimeltä my_engine.py ja siinä funktio search, joka valitsee siirron. Muuta kohdassa EDIT 1 tiedoston ja funktion nimi ja kohdassa EDIT 2 funktiolle annettavat arvot omaan moottoriisi sopiviksi. Funktion pitää palauttaa ruudun numero (0:sta 63:een) tai koordinaatti, kuten 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)Esimerkki B: moottori, joka on ohjelmatiedosto
Tässä esimerkissä oletetaan, että ohjelma lukee yhden rivin, jossa on 64 lautamerkkiä, siirtovuorossa oleva puoli ja miettimisaika millisekunteina, ja vastaa yhdellä koordinaattirivillä, kuten D3 (. = tyhjä, X = musta, O = valkoinen). Jokaisella moottorilla on oma muotonsa, joten muuta kohdassa EDIT 1 ohjelmatiedoston nimi, kohdassa EDIT 2 moottorille lähetettävä rivi ja kohdassa EDIT 3 vastauksen lukeva osa omaan moottoriisi sopiviksi.
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)Miettimisaika: bottipeleissä kummallakin botilla on 1 minuutti peliä kohden, joten pitkä miettiminen yhden siirron kohdalla johtaa nopeasti häviöön ajan loppumiseen. Esimerkkien think_ms jakaa jäljellä olevan ajan (remaining_ms) jäljellä olevien siirtojesi määrällä ja päättää näin tämän siirron ajan. budget_ms ei ole aika, joka tähän siirtoon pitäisi käyttää. Se on pisin aika, jonka yhteysohjelma odottaa vastausta (oletuksena 10 sekuntia). Jos vastaus tulee sitä myöhemmin, botti ei voi jatkaa kyseistä peliä ja häviää sen ajan loppumiseen. Anna siis moottorillesi think_ms eikä budget_ms.
Kun jokin menee vikaan: jos moottorin kutsu epäonnistuu, esimerkkitiedostot kirjoittavat syyn tiedostoon my_adapter.log ja pelaavat sen sijaan ensimmäisen laillisen ruudun. Jos siirrot näyttävät oudoilta, avaa ensin tuo tiedosto. Yhteysohjelma ei näytä sovittimen virheilmoituksia näytöllä. Käytä print-komentoa vain yhteen vastausriviin ja kirjoita kaikki virheenjäljitysteksti tiedostoon.
Nopeus: yhteysohjelma pitää my_adapter.py:n käynnissä jokaista peliä varten ja lähettää rivin siirtoa kohden. Tiedosto, joka vastaa yhden rivin ja sulkeutuu kuten esimerkit, käynnistetään uudelleen seuraavalla siirrolla, joten moottorisikin käynnistyy joka kerta uudelleen. Jos moottori käynnistyy hitaasti tai sen pitää säilyttää aiempien siirtojen työ, tee my_adapter.py:stä silmukka: lue rivi, vastaa rivi, toista. Älä lue syötettä loppuun asti, ja tee flush jokaisen vastauksen jälkeen.
Tämän osan loppu on viiteaineistoa siitä, mitä yhteysohjelma ja my_adapter.py vaihtavat keskenään. Jos käytät yllä olevia esimerkkitiedostoja sellaisenaan, sinun ei tarvitse lukea sitä.
Syöte-JSON (yhteysohjelma → sovitin)
Tämä on yhteysohjelman lähettämää esimerkkidataa, ei suoritettavaa koodia. Älä tallenna sitä Python-tiedostoksi. Pelin aikana ajantasaiset tiedot lähetetään automaattisesti joka vuorolla.
Alla on esimerkki tavallisen 8×8-laudan alkuasemasta. Oikeissa peleissä yhteysohjelma täyttää nykyisen aseman. board luettelee ruudut a1:stä oikealle ja sitten seuraavan rivin; 0=tyhjä, 1=musta, 2=valkoinen. color=1 pyytää mustan siirtoa. legal_moves luettelee ruudut, joihin saat pelata. remaining_ms on pelikellon jäljellä oleva aika ja budget_ms pisin aika, jonka yhteysohjelma odottaa tämän siirron vastausta, molemmat millisekunteina (1000 = 1 sekunti). Pelimuunnelmien kentät ja esimerkit ovat alempana muunnelmia käsittelevässä osiossa.
{"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}Vastaus-JSON (sovitin → yhteysohjelma)
Kirjoita yksi alla olevista vastauksista yhtenä JSON-rivinä, joka päättyy rivinvaihtoon. move on ruudun numero tai koordinaatti, eikä isoilla ja pienillä kirjaimilla ole väliä. 8×8-laudalla d3 on (3−1)×8+3 = 19. Valitse aina saamastasi legal_moves-luettelosta. Bottipareissa, kun laillista siirtoa ei ole, lähetä -1 tai pass; ihmistä vastaan pelatuissa peleissä palvelin hoitaa pakolliset passit. Kirjoita stdout-tulosteeseen vain vastausrivi, ei muita viestejä.
{"move":19}{"move":"d3"}{"move":-1}Moottoripyyntöjen esimerkit peleittäin
Esimerkkejä ensimmäisestä mustalle tarkoitetusta pyynnöstä, jonka yhteysohjelma lähettää --engine-moottorille, tuotettuna sääntökoodilla. Kaikkien pelimuotojen oikeat pelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa, joten board ja legal_moves vaihtelevat pelistä toiseen. Jotta esimerkit pysyisivät samoina, niiden aloitussiirrot valittiin laudan keskikohdan läheltä. Myös match_id ja kelloarvot ovat oikeissa peleissä erilaiset.
game_mode: Yksi seuraavista: std, anti, grand, octagon, reversi. XOT saapuu ihmispeleissä arvona std.board_size: 8, tai 10 peleissä grand ja octagon.board: Taulukko, jonka pituus on board_size². Luetaan a1:stä oikealle ja sitten seuraava rivi. 0=tyhjä (myös Octagonin estetyt ruudut), 1=musta, 2=valkoinen.blocked_squares: Octagonin käyttökelvottomat ruudut. Muissa peleissä tyhjä taulukko.placed: Kunkin värin tähän mennessä asettamat nappulat, mukaan lukien satunnaiset aloitussiirrot; avaimet ovat merkkijonot "1" ja "2". Käytetään klassisen Reversin 32 nappulan rajaan.
Anti (anti)
Syöte-JSON (yhteysohjelma → sovitin)
{
"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
}Vastaus-JSON (sovitin → yhteysohjelma)
{"move":2}Grand (10x10) (grand)
Syöte-JSON (yhteysohjelma → sovitin)
{
"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
}Vastaus-JSON (sovitin → yhteysohjelma)
{"move":13}Octagon (octagon)
Syöte-JSON (yhteysohjelma → sovitin)
{
"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
}Vastaus-JSON (sovitin → yhteysohjelma)
{"move":13}Klassinen Reversi (reversi)
Syöte-JSON (yhteysohjelma → sovitin)
{
"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
}Vastaus-JSON (sovitin → yhteysohjelma)
{"move":18}Yleisiä ongelmia
| Oire | Syy ja korjaus |
|---|---|
| Botilla on harmaa pallo (poissa). | Tarkista, että yhteysohjelman ikkuna on yhä käynnissä. Se pysähtyy, kun suljet ikkunan, painat Ctrl+C tai tietokone menee lepotilaan. Toista vaiheet 6 ja 7 ja paina sitten Päivitä. |
Ilmoitus kertoo, että komentoa ei löytynyt.command not found / is not recognized | Python puuttuu, tai ikkunaa ei avattu uudelleen asennuksen jälkeen. Katso vaihe 5, avaa uusi ikkuna ja aloita uudelleen vaiheesta 4. |
Ilmoitus kertoo, että tiedostoa ei voi avata.can't open file | Suoritit komennon bottikansion ulkopuolella. Siirry bottikansioon kuten vaiheessa 4 ja tarkista komennolla ls, että README.md ja tools näkyvät luettelossa. |
Ilmoitus kertoo, että tunniste puuttuu, ja ohjelma sulkeutuu.FS_BOT_TOKEN is missing or invalid | Tässä ikkunassa ei ole tunnistetta. Jos avasit uuden ikkunan, toista vaihe 6. |
Ilmoitus kertoo, että tunniste hylättiin, ja ohjelma pysähtyy.Bot credential rejected | Tunniste liitettiin väärin, tai se on vanha. Kun luot uuden tunnisteen tai poistat botin käytöstä, vanha tunniste ei enää toimi. Aloita uudelleen vaiheesta 6 uusimmalla tunnisteella. |
Sama virherivi toistuu jatkuvasti.Connection/state error | Tarkista internetyhteys. Tarkista macOSissa, että suoritit vaiheen 5 tiedoston Install Certificates.command. Jos virhe näkyy vain otteluiden aikana, palvelin saattaa hylätä moottorisi siirron laittomana. Yhteysohjelma lähettää saman siirron uudelleen, joten moottori on korjattava. |
| Haastepainike ei toimi, tai haastetta ei hyväksytä. | Molemmilla boteilla on oltava vihreä pallo. Tarkista, että bottisi on valittuna kohdassa Pelaava bottini. Botti, joka on jo toisessa ottelussa, ei ota vastaan uutta haastetta. Haaste, jota ei hyväksytä, vanhenee 120 sekunnin kuluttua. |
Botti ei tee siirtoa ja häviää sitten ajan loppumiseen, tai ottelu mitätöidään.Engine failed for match | Moottori ei vastannut ajoissa, tai sen vastaus oli väärässä muodossa. Tarkista moottorin komento ja sen yhden rivin JSON-tuloste. Jos botti ei tee ensimmäistä siirtoaan 30 sekunnin kuluessa alusta, ottelu mitätöidään. |
| Pelimuunnelmien haasteita ei tule. | Haasteikkunassa näkyvät vain pelit, joita molemmat botit tukevat. Tarkista, että peli on valittu bottisi kohdassa Tuetut pelit ja että myös toinen botti tukee sitä. NBoardin kautta yhdistetyllä botilla pitäisi olla valittuna vain Standard. |
Sanasto
| Termi | Merkitys |
|---|---|
| API | Sovittu tapa, jolla ohjelmat lähettävät pyyntöjä ja vastauksia. Yhteysohjelma hoitaa sen puolestasi. |
| Tunniste | Vain bottiasi varten oleva salasana. Yhteysohjelma todistaa sillä palvelimelle, mikä botti se on. |
| Pääte | Ikkuna, johon kirjoitetaan komentoja. Windowsissa käytä PowerShelliä. |
| Ympäristömuuttuja | Väliaikainen asetus, joka välitetään yhdestä pääteikkunasta käynnistetyille ohjelmille. Se katoaa, kun ikkuna suljetaan. |
| JSON | Muoto tietojen kirjoittamiseen tekstinä. Esimerkki: {"move":19} |
| Moottori | Ohjelma, joka tarkastelee asemaa ja valitsee siirron. |
| Sovitin | Pieni ohjelma, joka muuntaa tietoja moottorisi ja yhteysohjelman välillä. |
| NBoard | NBoard on graafinen Othello-ohjelma, jota voi käyttää NTestin kanssa. NBoard-protokolla on sen julkinen viestintämuoto pelimoottoreille ja toimii sitä tukevien moottorien, kuten NTestin ja Edaxin, kanssa. |
| Laillinen siirto | Ruutu, johon saat pelata nyt. Palvelin luettelee ne kentässä legal_moves. |
Lataukset
Kirjaudu ladataksesi. .zip sisältää oppaan, yhdistimen ja esimerkkimoottorin; .json on API-määritys ja .md on opas.
Yksityiskohtainen määritys
Sivun loppuosa on yksityiskohtaista viitetietoa kehittäjille, jotka työskentelevät suoraan moottorin tai API:n kanssa.
Yhteysohjelman valitsimet
Ohjelman tools/bot_match_client.py valitsimet. Täsmälleen yksi valitsimista --engine ja --nboard / --edax / --egaroucid on pakollinen. Tunniste ei ole koskaan valitsin; se luetaan vain ympäristömuuttujasta FS_BOT_TOKEN. Paluukoodit: 0 normaali pysähdys, 2 tunniste hylätty, 3 --max-runtime saavutettu.
| Parametrit | Kuvaus |
|---|---|
--engine "COMMAND" | Käynnistää komennon kerran peliä kohden ja vaihtaa yhden JSON-rivin siirtoa kohden sulkematta sen syötettä. Yhden rivin vastaava ja sulkeutuva moottori käynnistetään uudelleen seuraavalla siirrolla. |
--nboard "COMMAND" | Pitää yhden NBoard-moottorin käynnissä peliä kohden, yhteensä kaksi. Vain tavallinen peli (std). |
--edax PATH | Edax voidaan yhdistää myös pelkällä ohjelmapolulla käyttäen alla olevaa --edax-valintaa. Erillistä sovitinta ei tarvita; yhdistämisohjelma jakaa miettimisajan siirroille jäljellä olevan peliajan perusteella. |
--edax-eval PATH | Edaxin eval.dat-tiedoston polku. Ilman valintaa etsitään data/eval.dat ohjelman kansiosta tai sen yläkansiosta. |
--egaroucid PATH | Valmistele Egaroucid for Console. Valitse konsoliohjelma ja säilytä resources-kansio paikallaan. macOS- ja Linux-järjestelmissä käytetään virallisten ohjeiden mukaan käännettyä ohjelmaa. Asema ja jäljellä oleva aika välitetään komennoilla setboard, settime ja go ilman sovitinta. |
--nboard-depth N | Lähettää NBoard-moottorille set depth N. Arvo 0:sta 60:een; 0 säilyttää moottorin oletusarvon. (--edax: 0 → 60). |
--max-think-seconds S | Enimmäisaika sekunteina, jonka moottoria odotetaan siirtoa kohden. Oletus 10, enintään 300. Ei koskaan pidempi kuin jäljellä oleva kelloaika miinus 0,75 sekuntia. Tämä on yhteysohjelman turvaraja; palvelimella ei ole siirtokohtaista aikarajaa. Arvo 0 poistaa siirtokohtaisen rajan; käytössä on jäljellä oleva peliaika. |
--engine-name NAME | Botin tiedoissa ilmoitettava moottorin nimi (enintään 120 merkkiä). Älä sisällytä komentoja tai polkuja. |
--cpu-name NAME | Ilmoitettava suorittimen nimi (enintään 120 merkkiä). Tunnistetaan automaattisesti, jos se jätetään pois. |
--once-match ID | Käsittelee vain tämän ottelun ja sulkeutuu, kun se päättyy (päättynyt, mitätöity, vanhentunut, hylätty). Myös ihmispelien negatiiviset ID:t toimivat. Testeissä yhdistä se valitsimeen --max-runtime. |
--max-runtime S | Siivoaa moottorit ja sulkeutuu näin monen sekunnin jälkeen (paluukoodi 3). |
--no-stream | Ei käytä tapahtumavirtaa; käyttää vain kyselyä. |
--api URL, --stream-url URL | API:n ja virran osoitteet. Pidä yleensä oletusarvot. Vain HTTPS hyväksytään, ja koska tunniste lähetetään mukana, virran on oltava API-palvelimella. |
API:n toteuttaminen itse
Vastaanota haasteet ja asemat agent_poll-kutsulla tai tunnistautuneella tapahtumavirralla. Lähetä agent_accept odottaville haasteille, joissa olet bot_b, ja laske sitten käynnissä olevan ottelun kummassakin pelissä vain asemat, joissa on sinun vuorosi. Lähetä enintään kerran kutakin match_id-, peli- ja revision-yhdistelmää kohden, ja hylkää vanhentunut laskenta, kun tila muuttuu. Ihmistä vastaan pelatuissa peleissä match_id on negatiivinen ja leg=0, ja round_no ja room_created_at on lähetettävä täsmälleen sellaisina kuin ne vastaanotettiin. Tavallisissa huoneissa palvelin hoitaa pakolliset passit; vain bottiparit lähettävät passeja.
agent_poll / bot-stream → pending (bot_b = my_id)
→ agent_accept → running → legs[0] + legs[1]
→ agent_move(match_id, leg, revision, move) → finished / abortedPelimuunnelmat
Botti saa vain ne pelit, jotka on valittu kohdassa Tuetut pelit. Moottoripyyntöjen ja ottelun tilan game_mode kertoo pelin. Palvelin laskee laudan koon, estetyt ruudut ja lailliset ruudut, joten moottorin tarvitsee vain valita saamastaan legal_moves-luettelosta. Älä tuota 10×10-laudan tai klassisen Reversin siirtoja tavallisen 8×8-laudan siirtogeneroinnilla.
| Peli | game_mode | Lauta | Aloitusnappulat | Aika (peliä ja väriä kohden) | Mustan ensimmäiset legal_moves |
|---|---|---|---|---|---|
| Standard | std | 8×8 | Satunnaiset 12 nappulaa | 60,000 ms | Riippuu asemasta |
| Anti | anti | 8×8 | Satunnaiset 12 nappulaa | 60,000 ms | Riippuu asemasta |
| Grand (10x10) | grand | 10×10 | Satunnaiset 12 nappulaa | 60,000 ms | Riippuu asemasta |
| Octagon | octagon | 10×10 (88) | Satunnaiset 12 nappulaa | 60,000 ms | Riippuu asemasta |
| Klassinen Reversi | reversi | 8×8 | Satunnaiset 12 nappulaa | 60,000 ms | Riippuu asemasta |
Yhteiset säännöt: Musta (1) siirtää ensin. Molemmat pelit alkavat samasta asemasta vaihdetuin värein ja ovat käynnissä samanaikaisesti. Bottipareissa, kun sinulla ei ole laillista siirtoa, legal_moves saapuu tyhjänä taulukkona ja botin on itse lähetettävä move=-1 (passi). Palvelin ei passaa puolestasi, ja kellosi jatkaa käymistä. Passaaminen, kun laillinen siirto on olemassa, on laitonta. Peli päättyy, kun kumpikaan väri ei voi siirtää. Tyhjiä ruutuja ei anneta kenellekään; vain todelliset nappulat lasketaan yhteen molemmista peleistä, ja yhtä suuret summat ovat tasapeli. Kaikki bottipelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa. Kaikissa pelimuodoissa kummallakin botilla on 1 minuutti peliä kohden.
Anti: nappuloiden asettaminen ja kääntäminen toimivat kuten tavallisessa Othellossa. Voittaja on se, jolla on molemmissa peleissä yhteensä vähemmän nappuloita.
10x10: tavalliset säännöt 10×10-laudalla (100 ruutua). Aloitusnappulat ovat neljässä keskiruudussa; bottiparit lisäävät 8 satunnaista siirtoa ja aloittavat 12 nappulasta.
Octagon: sama lauta ja alkuasetelma kuin 10x10:ssä, mutta jokaisen kulman kolme ruutua, yhteensä 12, ovat käyttökelvottomia (88 pelattavaa ruutua). Estetyt ruudut saapuvat ruutunumeroina kentässä blocked_squares ja arvona 0, samana kuin tyhjä, kentässä board. Taulukko ei ole numerojärjestyksessä. Estettyyn ruutuun ei voi pelata, ja nappularivit katkeavat siihen.
Klassinen Reversi: sääntöjen mukaan alkaa tyhjältä laudalta. Niin kauan kuin jokin neljästä keskiruudusta (27, 28, 35, 36) on tyhjä, nappuloita asetetaan vain niihin eikä mitään käännetä. Kun kaikki neljä on täytetty, tavalliset säännöt ovat voimassa. Kukin väri asettaa enintään 32 nappulaa, mukaan lukien neljä ensimmäistä siirtoa. placed laskee kunkin värin tähän mennessä asettamat nappulat; sen avaimet ovat merkkijonot "1" (musta) ja "2" (valkoinen). Bottiparien pelit alkavat, kun palvelin on asettanut 12 nappulaa satunnaisesti, mukaan lukien neljä keskisiirtoa, joten ensimmäisessä pyynnössä placed-arvojen summa on 12 (yleensä {"1":6,"2":6}). Väri, joka on asettanut kaikki 32, saa tyhjän legal_moves-luettelon ja lähettää -1 jokaisella vuorollaan.
Moottoripyyntöjen esimerkit peleittäin
Esimerkkejä ensimmäisestä mustalle tarkoitetusta pyynnöstä, jonka yhteysohjelma lähettää --engine-moottorille, tuotettuna sääntökoodilla. Kaikkien pelimuotojen oikeat pelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa, joten board ja legal_moves vaihtelevat pelistä toiseen. Jotta esimerkit pysyisivät samoina, niiden aloitussiirrot valittiin laudan keskikohdan läheltä. Myös match_id ja kelloarvot ovat oikeissa peleissä erilaiset.
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}Klassinen 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}Moottoripyynnön kentät
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
game_mode | string | Yksi seuraavista: std, anti, grand, octagon, reversi. XOT saapuu ihmispeleissä arvona std. |
board_size | integer 8 | 10 | 8, tai 10 peleissä grand ja octagon. |
board | integer[board_size²] | Taulukko, jonka pituus on board_size². Luetaan a1:stä oikealle ja sitten seuraava rivi. 0=tyhjä (myös Octagonin estetyt ruudut), 1=musta, 2=valkoinen. |
blocked_squares | integer[] | Octagonin käyttökelvottomat ruudut. Muissa peleissä tyhjä taulukko. |
placed | {"1": integer, "2": integer} | Kunkin värin tähän mennessä asettamat nappulat, mukaan lukien satunnaiset aloitussiirrot; avaimet ovat merkkijonot "1" ja "2". Käytetään klassisen Reversin 32 nappulan rajaan. |
legal_moves | integer[] | Ruudut, joihin saat pelata nyt. Jos tyhjä, vastaa move=-1. |
color | integer 1 | 2 | Siirtovuorossa oleva väri. 1=musta, 2=valkoinen. |
budget_ms | integer | Tähän siirtoon sallittu aika millisekunteina: pienempi arvoista --max-think-seconds ja jäljellä oleva kelloaika miinus 0,75 sekuntia. Yhteysohjelma pysäyttää moottorin, kun aika ylittyy. |
remaining_ms | integer | Värisi jäljellä oleva kelloaika tässä pelissä millisekunteina, kun tällä vuorolla jo käytetty aika on vähennetty. |
match_id | integer ≠ 0 | Ottelun id. Ihmispeleissä negatiivinen (-huoneen numero). |
leg | integer 0 | 1 | Pelin numero 0 tai 1. Ihmispeleissä aina 0. |
revision | integer | Tämän pelin tilanumero. Lähetä se muuttamattomana agent_move-kutsun mukana. |
history | array | Tässä pelissä pelatut siirrot. Tee päätös kentän board perusteella. |
round_no | integer | null | Ihmispelin kierrosnumero. Bottipareissa null. |
room_created_at | string | null | Ihmispelin huoneen luontiaika. Bottipareissa null. |
Toisen botin haastaminen pelimuunnelmaan
Lisää game_mode kutsuun agent_challenge; oletus on std. Molemmilla boteilla on oltava se kentässä supported_games. Lue vastustajan pelit agent_poll-vastauksen kentästä bots[].supported_games. Jos jommaltakummalta botilta puuttuu peli, vastaus on HTTP 409 ja alla oleva virhe.
{"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}supported_games-luettelon muuttaminen
Rekisteröintilomakkeessa Standard on valmiiksi valittuna, ja vanhat botit, joilla ei ole tallennettua luetteloa, tukevat peliä std. Voit muuttaa luetteloa vain bottisivun kohdassa Hallitse, et koskaan bottitunnisteella (API). Muutos hylätään, kun ottelu on käynnissä tai odottaa hyväksyntää. Tyhjää luetteloa ei voi tallentaa.
NBoard ja pelimuunnelmat
--nboard-yhteys tukee vain tavallista peliä (std). Kun saapuu pelimuunnelma, yhteysohjelma ei kysy moottorilta ja luopuu siitä vuorosta (viesti Engine failed for match). Siirtoa ei lähetetä, joten ottelu mitätöidään ennen ensimmäistä siirtoa, tai kyseinen peli hävitään myöhemmin ajan loppumiseen. Anna NBoard-botille ainoaksi tuetuksi peliksi tavallinen peli.
Ihmiset rekisteröityjä botteja vastaan
Ihmiset voivat haastaa bottisi missä tahansa sille rekisteröidyssä pelissä. Jos se tukee tavallista peliä, saapua voi sekä STD että XOT. XOT saapuu arvolla game_mode std ja alkaa laudalta, jolla on jo pelattu 8 siirtoa (ne sisältyvät kenttään history). Haastaja valitsee ajan, eikä peliä lasketa vahvuuslukuun. Ihmistä vastaan pelattavassa ottelussa on yksi peli (leg 0) ja negatiivinen match_id. Palvelin hoitaa passit, kun siirtoa ei voi tehdä, joten älä lähetä -1. Verkossa olevat rekisteröidyt botit, joilla automaattinen paritus on päällä, osallistuvat myös tuettuihin STD/XOT-pikapeleihin. Ne ovat jäsenille luokiteltuja ja vieraille luokittelemattomia.
Laittomat siirrot ja aika
Laiton siirto tai vanhentunut revision hylätään vastauksella HTTP 409 (illegal_move, stale_revision, not_your_turn), eikä lauta muutu. Kello käy sillä välin. Yhteysohjelma lähettää saman siirron uudelleen samalla revisionilla, joten ellei moottoria korjata, kyseinen peli hävitään lopulta ajan loppumiseen. Palvelimella ei ole siirtokohtaista rajaa, ja se tarkistaa vain kunkin värin jäljellä olevan kelloajan. 10 sekuntia on yhteysohjelman valitsimen --max-think-seconds oletusarvo.
Tunnistautuminen
Käytä HTTPS:ää, JSON POSTia ja Authorization: Bearer -otsaketta. Tunniste koskee yhtä bottia. Älä kirjoita sitä URL-osoitteisiin, julkiseen koodiin tai lokeihin.
Content-Type: application/json
Authorization: Bearer <FS_BOT_TOKEN>POST https://othelloclub.com/flipsight/bot_match_api.php
Ottelusäännöt
Kaikki bottipelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa. Kaksi peliä pelataan samanaikaisesti vaihdetuin värein. Nappuloiden yhteismäärä ratkaisee; Antissa pienempi määrä voittaa.
Kaikki bottipelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa. Kaikissa pelimuodoissa kummallakin botilla on 1 minuutti peliä kohden.
Jos botti ei ole tehnyt ensimmäistä siirtoaan 30 sekunnin kuluessa alusta, ottelu mitätöidään eikä sitä lasketa vahvuuslukuun. Jos toisen botin yhteys katkeaa ottelun aikana yli 30 sekunniksi toisen ollessa yhteydessä, yhteydessä oleva botti voittaa (finish_reason: disconnect) ja tulos lasketaan vahvuuslukuun.
Palvelin laskee FlipSight-botin siirrot kaikissa pelityypeissä. Sekä verkosta että API:n kautta (agent_challenge) tehdyt haasteet hyväksytään, ja palvelin aloittaa ottelun heti, joten pelihuonetta ei tarvitse pitää auki. Jos palvelimen laskenta pysähtyy yli 30 sekunniksi, ottelu mitätöidään (finish_reason: technical) eikä se vaikuta vahvuuslukuun. Muunnelmien laskeminen on raskasta, joten FlipSight-botteja vastaan pelataan kerrallaan enintään 2 muunnelmaottelua. Kun paikat ovat täynnä, saat HTTP 409 ja site bot variant matches are full; yritä hetken päästä uudelleen.
Automaattiset bottiottelut: sivusto pitää aina kaksi bottiotteluhuonetta käynnissä. Kun rekisteröity botti, jonka automaattinen parinmuodostus on päällä, on paikalla eikä pelaa, se saa haasteen tavalliseen (std) bottiotteluun samantasoista bottia vastaan (ensin toinen rekisteröity botti, muuten FlipSight-botti) bot_b:nä. Yhteysohjelma hyväksyy haasteen automaattisesti, ja ottelu alkaa. Jos botti ei hyväksy 120 sekunnissa tai hylkää haasteen, se jätetään automaattisen parinmuodostuksen ulkopuolelle 10 minuutiksi. Automaattiset ottelut vaikuttavat vahvuuslukuun. Automaattiset bottiottelut jatkuvat myös Arena-pelien aikana. Automaattinen parinmuodostus on oletuksena päällä, ja sen voi ottaa pois bottisivun kohdasta Hallitse. Harjoitusmoottorilla käynnistetty botti (environment.practice on true) jätetään automaattisten otteluiden ulkopuolelle, eivätkä sen ottelut muita botteja vastaan sinä aikana vaikuta vahvuuslukuun.
Ihmisen suora haaste pelataan yhtenä pelinä tavallisessa huoneessa tuetulla pelillä ja ajalla. Palvelin tekee suorista haasteista aina luokittelemattomia. Verkossa olevat rekisteröidyt botit, joilla automaattinen paritus on päällä, osallistuvat myös tuettuihin STD/XOT-pikapeleihin. Ne ovat jäsenille luokiteltuja ja vieraille luokittelemattomia. Rekisteröity botti ottaa vastaan vain niin monta peliä kuin samanaikaisten pelien asetus sallii (oletus 2). Peli ihmistä vastaan ja bottien ottelu (kaksi lautaa) lasketaan kumpikin 1:ksi.
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)Ottelun kulku
Kaikki bottipelit alkavat satunnaisesta asemasta, jossa on 12 nappulaa. Kaksi peliä pelataan samanaikaisesti vaihdetuin värein. Nappuloiden yhteismäärä ratkaisee; Antissa pienempi määrä voittaa.
Osallistujanumerosi on 0, jos olet bot_a, ja 1, jos olet bot_b. Osallistuja 0 on musta (1) pelissä legs[0] ja valkoinen (2) pelissä legs[1]; osallistujalla 1 päinvastoin. On sinun vuorosi, kun leg.status on active ja leg.turn on sinun värisi. Voit olla vuorossa molemmissa peleissä yhtä aikaa.
Jos sinulla ei ole laillista siirtoa, sinun on itse lähetettävä move -1 (passi); palvelin ei passaa puolestasi. Ihmistä vastaan pelatuissa peleissä palvelin hoitaa passit kuten tavallisissa pelihuoneissa.
Omalla vuorollasi jäljellä oleva aika = clocks_ms[oma värisi - 1] - (server_now_ms - turn_started_ms). clocks_ms on värijärjestyksessä (musta, valkoinen); totals ja winner ovat osallistujajärjestyksessä (winner 0 tai 1, tasapelissä null).
Ruutunumerot
Ruutunumero = rivi × 8 + sarake, joten a1=0, h1=7, a2=8 ja h8=63. Esimerkiksi 19 on d3 ja 37 on f5. board-taulukko käyttää samaa järjestystä: 0=tyhjä, 1=musta, 2=valkoinen.
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 6310×10-laudalla (grand, octagon) ruutu = rivi × 10 + sarake. Sarakkeet ovat a:sta j:hin, ja kymmenes rivi kirjoitetaan koordinaateissa 10 tai 0. a1=0, j1=9, a2=10, j10=99 (sama kuin j0). Samalla koordinaatilla on eri numero kullakin laudan koolla: d3 on 19 8×8-laudalla ja 23 10×10-laudalla.
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 ## ##Tapahtumavirta
Yhdistä samalla Bearer-tunnisteella osoitteeseen GET https://othelloclub.com/flipsight_api/bot-stream, niin saat yhden JSON-tapahtuman riviä kohden (NDJSON): hello vahvistaa yhteyden, match tarkoittaa, että jokin otteluistasi on muuttunut (bottien välisissä tapahtumissa on mukana koko otteluobjekti), ja ping on 10 sekunnin välein lähetettävä ylläpitosignaali. Kun saat match-tapahtuman, kutsu agent_poll kerran. Jos yhteys katkeaa, yhdistä uudelleen viiveellä, joka kasvaa 1 sekunnista 30 sekuntiin, ja jatka sillä välin kyselyä. Kun virta on yhdistetty, bottisi näytetään paikalla olevana; kukin botti voi avata enintään 3 virtaa.
Tapahtumaesimerkit
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}Moottorisovitin
FlipSightin bottiyhteysohjelma (Python 3.9+, vain vakiokirjasto) toimii Windowsissa, macOS:ssä ja Linuxissa ja liittää moottorin kahdella tavalla. --engine käynnistää moottorin kerran peliä kohden, lähettää jokaisella siirrolla yhden JSON-rivin ja lukee yhden rivin {"move": ruutu}. Moottori, joka vastaa yhden rivin ja sulkeutuu, toimii yhä, koska se käynnistetään uudelleen seuraavalla siirrolla, mutta syötteen loppuun asti lukeva moottori (sys.stdin.read() ym.) ei koskaan vastaa, joten lue rivi kerrallaan. Pyynnön legal_moves luettelee lailliset ruudut; jos se on tyhjä, vastaa -1. --nboard pitää NBoard-moottorin käynnissä, yhden peliä kohden; hakusyvyys asetetaan --nboard-depth-valinnalla.
Edax voidaan yhdistää myös pelkällä ohjelmapolulla käyttäen alla olevaa --edax-valintaa. Erillistä sovitinta ei tarvita; yhdistämisohjelma jakaa miettimisajan siirroille jäljellä olevan peliajan perusteella.
Valmistele Egaroucid for Console. Valitse konsoliohjelma ja säilytä resources-kansio paikallaan. macOS- ja Linux-järjestelmissä käytetään virallisten ohjeiden mukaan käännettyä ohjelmaa. Asema ja jäljellä oleva aika välitetään komennoilla setboard, settime ja go ilman sovitinta.
Syöte-JSON (yhteysohjelma → sovitin)
Tämä on yhteysohjelman lähettämää esimerkkidataa, ei suoritettavaa koodia. Älä tallenna sitä Python-tiedostoksi. Pelin aikana ajantasaiset tiedot lähetetään automaattisesti joka vuorolla.
{"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}Vastaus-JSON (sovitin → yhteysohjelma)
{"move":2}Tilan synkronointi
Kun virta on yhdistetty, kutsu agent_poll tapahtuman saapuessa ja 10 sekunnin välein. Ilman virtaa kysy ottelun aikana sekunnin välein ja odottaessa 5 sekunnin välein, mutta älä koskaan useammin kuin kerran sekunnissa. Verkkoaika kuluttaa kelloasi. Jos siirron vastaus katoaa, hae uusi tila ja lähetä sama siirto uudelleen vain, jos revision on yhä sama.
API-toiminnot
Vastausesimerkit näyttävät muodon. Kopiointipainike kopioi vain pyynnön eikä kutsu API:a.
POST agent_poll
Hae tila
| Parametrit | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
action | string "agent_poll" | Pakollinen | Kutsuttavan toiminnon nimi |
environment | object | Valinnainen | Yhdistin-PC:n suoritin, käyttöjärjestelmä ja moottorin nimi (kukin enintään 120 merkkiä, valinnainen) sekä practice (true tai false, valinnainen). practice true tarkoittaa, että botti harjoittelee: se jätetään automaattisten otteluiden ulkopuolelle, eivätkä sinä aikana pyydetyt tai hyväksytyt bottiottelut vaikuta vahvuuslukuun. Yhdistin lähettää arvon itse, kun se käynnistetään harjoitusmoottorilla. Palvelin muistaa viimeisen arvon, joten kun harjoittelu päättyy, lähetä se ilman practicea tai arvolla false. |
Pyyntöesimerkki
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"}}'Vastausesimerkki
{
"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
}Otteluobjekti (matches[])
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
id | integer | Ottelun ID (negatiivinen ihmistä vastaan pelatuissa peleissä) |
kind | string | human, kun vastassa on ihminen |
bot_a | integer | Osallistujan 0 botin ID (ihmiselle 0) |
bot_b | integer | Osallistujan 1 botin ID (ihmiselle 0) |
game_mode | string | Peli (std, anti, grand, octagon, reversi) |
time_limit_sec | integer | Sekunnit peliä ja väriä kohden |
status | string | pending, running, finished, aborted, rejected, expired |
expires_ms | integer | Hyväksynnän määräaika (millisekunteina) |
ranked | boolean | Lasketaanko ottelu vahvuuslukuun |
state.status | string | active, finished tai aborted |
state.game_mode | string | Peli (std, anti, grand, octagon, reversi) |
state.board_size | integer 8 | 10 | Ruutuja sivulla, 8 tai 10 |
state.blocked_squares | integer[] | Käyttökelvottomat ruudut (vain Octagon, ei järjestetty) |
state.legs | array | Pelit (bottien kesken 2, ihmistä vastaan 1) |
state.totals | [integer, integer] | Molempien pelien nappulasummat osallistujittain |
state.winner | integer | null | Voittanut osallistuja 0 tai 1, tasapelissä null |
state.finish_reason | string | null | discs, timeout, double_timeout, disconnect, no_first_move |
Peliobjekti (state.legs[])
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
board | integer[64 | 100] | 64 / 100 ruutua, 0=tyhjä 1=musta 2=valkoinen |
turn | integer | Vuorossa oleva väri, 1 (musta) tai 2 (valkoinen) |
legal_moves | integer[] | Siirtovuorossa olevan värin lailliset ruudut. Tyhjä päättyneissä peleissä |
placed | {"1": integer, "2": integer} | Asetetut nappulat väreittäin, avaimet "1" (musta) ja "2" (valkoinen) |
black_participant | integer | Osallistuja, joka pelaa mustalla tässä pelissä |
clocks_ms | [number, number] | Jäljellä olevan ajan perusarvot värijärjestyksessä (musta, valkoinen) |
turn_started_ms | integer | Palvelimen aika nykyisen vuoron alkaessa |
revision | integer | Kasvaa yhdellä aina, kun tämä peli muuttuu |
status | string | active, finished, timeout, stopped |
history | array | Pelatut siirrot (color, participant, move, at_ms) |
discs | [integer, integer] | Nappulamäärät värijärjestyksessä (musta, valkoinen) |
result_discs | [integer, integer] (optional) | Valinnainen määrätty tulos [musta, valkoinen] pelille, joka hävittiin ajan loppumiseen; summaan lasketaan tämä nappuloiden sijaan. Ajan ylittäneen puolen ja sen vastustajan tulokset: std ja reversi 0 ja 64, grand 0 ja 100, octagon 0 ja 88, anti 64 ja 0. Toinen peli jatkuu, ja summat ratkaisevat voittajan, kun molemmat pelit ovat päättyneet. Vanhoja päättyneitä tietoja ei lasketa uudelleen. |
POST agent_challenge
Haasta
Anna target_id (botin numero) tai target_name (botin nimi); ne löytyvät agent_poll-vastauksen bots-luettelosta. Sisäänrakennettuja FlipSight-botteja (is_builtin: true) voi haastaa API:n kautta kaikissa pelityypeissä, ja palvelin aloittaa ottelun heti. Jos sisäänrakennettuja botteja vastaan on jo 2 muunnelmaottelua, saat HTTP 409 ja site bot variant matches are full.
| Parametrit | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
action | string "agent_challenge" | Pakollinen | Kutsuttavan toiminnon nimi |
target_id | integer ≥ 1 | Valinnainen | Haastettavan botin ID |
target_name | string | Valinnainen | Haastettavan botin nimi (target_id:n sijaan) |
game_mode | string std | anti | octagon | grand | reversi | Valinnainen | Bottiparin peli. Oletus on std. Molempien bottien on tuettava sitä. Standard / Anti / Octagon / Grand (10x10) / Klassinen Reversi |
Pyyntöesimerkki
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"}'Vastausesimerkki
{
"ok": true,
"match_id": 123,
"server_now_ms": 1800000000000
}POST agent_accept
Hyväksy
| Parametrit | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
action | string "agent_accept" | Pakollinen | Kutsuttavan toiminnon nimi |
match_id | integer ≥ 1 | Pakollinen | Ottelun ID (negatiivinen ihmistä vastaan pelatuissa peleissä) |
Pyyntöesimerkki
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}'Vastausesimerkki
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_reject
Hylkää
| Parametrit | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
action | string "agent_reject" | Pakollinen | Kutsuttavan toiminnon nimi |
match_id | integer ≥ 1 | Pakollinen | Ottelun ID (negatiivinen ihmistä vastaan pelatuissa peleissä) |
Pyyntöesimerkki
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}'Vastausesimerkki
{
"ok": true,
"match": {
"id": 123,
"status": "rejected",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_move
Lähetä siirto
| Parametrit | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
action | string "agent_move" | Pakollinen | Kutsuttavan toiminnon nimi |
match_id | integer ≠ 0 | Pakollinen | Ottelun ID (negatiivinen ihmistä vastaan pelatuissa peleissä) |
round_no | integer ≥ 0 | Valinnainen | Vain ihmistä vastaan: otteluobjektin round_no |
room_created_at | string | Valinnainen | Vain ihmistä vastaan: otteluobjektin room_created_at |
leg | integer 0 | 1 | Pakollinen | Peli 0 tai 1 (ihmistä vastaan 0) |
revision | integer ≥ 0 | Pakollinen | Sen pelin revision, jolle siirto laskettiin; 409 stale_revision, jos peli on muuttunut |
move | integer -1..99 | string | Pakollinen | Ruutu 0-(board_size²−1), passi -1 / d3 / D3 / pass |
Pyyntöesimerkki
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}'Vastausesimerkki
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}Virheet
Virheet ovat muotoa {"ok": false, "error": "…"}. 401: pysähdy ja tarkista tunniste. 409: hae nykyinen tila ja tarkista vuoro, revision sekä lailliset siirrot. 429 tarkoittaa, että yhdellä botilla on liian monta virtaa. Yritä yhteysvirheitä ja 503:a uudelleen kasvavin viivein, äläkä koskaan lähetä laitonta siirtoa uudelleen.
{"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 |