Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointiputka: Tekoälykilpailu: morabaraba

Sivun loppuun

Metabolix [10.01.2014 18:00:00]

#

Tämän talven kilpailun aiheena on morabaraba, kahden pelaajan lautapeli, joka muistuttaa Suomessa pelattavaa myllyä.

Osallistumisen helpottamiseksi on jälleen tarjolla esimerkkiohjelma muutamalla yleisimmällä kielellä sekä Javalla tehty testausohjelma, jolla voi pelata omaa tekoälyään vastaan. Kilpailuaika päättyy sunnuntaina 9.2.2014 kello 18.00.

Tällä kertaa kilpailussa tekoälyn pistemäärä riippuu myös sen nopeudesta: mitä hitaampi tekoäly on, sitä pienemmät pisteet se saa voitosta ja isommat sakot häviöstä. Laskutavan johdosta aika on jälleen kilpailussa tiukalla, mutta toivottavasti peliin löytyy silti hyviäkin tekoälyjä.

Tarkemmat kilpailuohjeet ovat kilpailusivulla. Onnea kilpailuun!

FooBat [11.01.2014 05:12:52]

#

Taitaa testiohjelmassa olla pieni bugi sovellettaessa sääntöä, että rikottua myllyä ei saa korjata, jos sen rikkomisella tehtiin toinen mylly. Nyt se ei anna siirtää kyseiseen kohtaan mitään lehmää, vaikka siirto ei tekisikään myllyä (siirrettäessä rikotun myllyn jäljelle jääneitä lehmiä rikottuun kohtaan).

Säännöissä ei myöskään mainita sitä, että lehmän saa ampua myllystä, jos kaikki vastutajan lehmät ovat myllyssä. Testiohjelma tämän säännön toteuttaakin jo.

Metabolix [11.01.2014 12:32:10]

#

Nyt edellä mainittu testaus- ja esimerkkiohjelmien bugi on toivottavasti korjattu. Ampumissääntö kyllä mainittiin jo ohjeissa (”ensisijaisesti sellaisen, joka ei ole osana myllyä”), mutta täsmensin vielä ilmaisua.

Oskuz [14.01.2014 17:33:53]

#

Montako tekoälyä on jo "ilmoittautunut"?

Metabolix [15.01.2014 16:25:33]

#

Ei ole vielä ilmoittautuneita, mikä ei sinänsä ole ihme, koska aihe on kohtalaisen vaikea ja kunnollisen tekoälyn tekemisessä menee käytännössä aina monta päivää eikä nopeasta ilmoittautumisesta saa mitään lisäpisteitä. Kannattaa kuitenkin taas ilmoittautua jo ajoissa ennen kisan päättymistä, jotta ehditään varmistaa, että tekoäly toimii myös kisaympäristössä.

Uutta: Kilpailuun voi nyt ilmoittautua nettilomakkeella. Jatkokeskustelu tekoälyn bugeista käydään tarvittaessa silti sähköpostitse.

jalski [16.01.2014 20:33:11]

#

Harmi, ettei Linuxille löydy kattavaa PL/I-kääntäjän toteutusta. Voisin nimittäin harkita osallistuvani jollain yksinkertaisella bittitaulukoihin ja bittimerkkijonoihin pohjautuvalla toteutuksella.

PL/I tarjoaa hyvät mahdollisuudet taulukoiden käsittelyyn. Esimerkiksi, kaikkien myllyjen määrän pelilaudalla voisi tutkia tarkistamalla 22 siivua taulukosta.

Jos pelilauta olisi määritelty:

dcl board(7, 7) bit(1) init('1'b, '0'b, '0'b, '1'b, '0'b, '0'b, '1'b,
                            '0'b, '1'b, '0'b, '1'b, '0'b, '1'b, '0'b,
                            '0'b, '0'b, '1'b, '1'b, '1'b, '0'b, '0'b,
                            '1'b, '1'b, '1'b, '0'b, '1'b, '1'b, '1'b,
                            '0'b, '0'b, '1'b, '1'b, '1'b, '0'b, '0'b,
                            '0'b, '1'b, '0'b, '1'b, '0'b, '1'b, '0'b,
                            '1'b, '0'b, '0'b, '1'b, '0'b, '0'b, '1'b);

Ja haluttaisiin tutkia myllyjen määrä suoralla linjalla kulmittain vasemmasta yläkulmasta oikeaan alakulmaan, voitaisiin tehdä:

dcl slice(7) bit(1) def board(1sub, 1sub); /* vasen yläkulma - oikea alakulma */
dcl dummy(7) bit (1); /* dummy copy */
dcl (v1, result)  bit(7);

dummy = slice; /* Argument to STRING needs to be CONNECTED */
v1 = string(dummy);

Eli tutkittavasta diagonaalista muodostetaan bittimerkkijono. Nythän boolean AND-operaatioilla ja yksinkertasella merkkijonohaulla voidaan tutkia lehmien määrä vasemmassa ylänurkassa ja oikeassa alanurkassa.

dcl v2 bit(7) value('1110000'b);
dcl v3 bit(7) value('0000111'b);

result = v1 & v2;
put ('Vasen ylä, lehmiä myllyssä: ' || trim(tally(result, '1'b)));

put skip(2);

result = v1 & v3;
put ('Oikea ala, lehmiä myllyssä: ' || trim(tally(result, '1'b)));

jlaire [17.01.2014 18:02:36]

#

jalski kirjoitti:

Nythän boolean AND-operaatioilla ja yksinkertasella merkkijonohaulla voidaan tutkia lehmien määrä vasemmassa ylänurkassa ja oikeassa alanurkassa.

Niin, jos tekisi esimerkiksi C:llä, tulisi varmaan käytettyä tehokkaita bittioperaatioita merkkijonohaun sijaan.

Kielitarjonta on mielestäni niin hyvä, että siitä valittaminen tuntuu lähinnä tekosyyltä jättää osallistumatta. Varsinkin jos oikeasti osaisi käyttää jotain tarjotuista kielistä, mutta haluaa vain nirsoilla.

jalski [17.01.2014 20:15:36]

#

jlaire kirjoitti:

Niin, jos tekisi esimerkiksi C:llä, tulisi varmaan käytettyä tehokkaita bittioperaatioita merkkijonohaun sijaan.

Ovatko nuo C:ssä mielestäsi jotenkin erinomaisesti toteutettu?

Sitä paitsi missasit pointin, Kokeilepas toteuttaa alla oleva C:llä ja vastaavalla määrällä koodia:

 /* Pelilautaa kuvaava bitti-matriisi, koostuu kolmesta vierekkäin olevasta 3x3 alimatriisista. */
 /*  Nämä kuvaavat pelilaudan kolmea kehää.                                                     */
 dcl boards(3, 9) bit(1)
     init( '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b,
           '1'b, '0'b, '1'b, '1'b, '0'b, '1'b, '1'b, '0'b, '1'b,
           '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b, '1'b );

/* Näillä pääsee käpistelemään pelilaudan alimatriiseja */
 dcl square1(3, 3) bit(1) def boards(1sub, 2sub);
 dcl square2(3, 3) bit(1) def boards(1sub, 2sub + 3);
 dcl square3(3, 3) bit(1) def boards(1sub, 2sub + 6);

 /* Vektorit alimatriisien ylärivien ruuduista. */
 dcl top1(3) bit(1) def boards(1,1sub + 2*(1sub = 2) + (4*(1sub = 3)));
 dcl top2(3) bit(1) def boards(1,1sub + 1 + 2*(1sub = 2) + (4*(1sub = 3)));
 dcl top3(3) bit(1) def boards(1,1sub + 2 + 2*(1sub = 2) + (4*(1sub = 3)));

 /* Vektorit alimatriisien keskirivien ruuduista. */
 dcl mid1(3) bit(1) def boards(2,1sub + 2*(1sub = 2) + (4*(1sub = 3)));
 dcl mid3(3) bit(1) def boards(2,1sub + 2 + 2*(1sub = 2) + (4*(1sub = 3)));

 /* Vektorit alimatriisien alarivien ruuduista. */
 dcl bottom1(3) bit(1) def boards(3,1sub + 2*(1sub = 2) + (4*(1sub = 3)));
 dcl bottom2(3) bit(1) def boards(3,1sub + 1 + 2*(1sub = 2) + (4*(1sub = 3)));
 dcl bottom3(3) bit(1) def boards(3,1sub + 2 + 2*(1sub = 2) + (4*(1sub = 3)));

Tutki tuota ja mieti, mitä se tekee. Jos vielä sen jälkeen luulet C:n tukevan vastaavaa toiminnallisuutta, niin olisi mielenkiintoista nähdä toteutus!

Sisuaski [17.01.2014 21:26:27]

#

jlairen pointtina tuskin oli, että C:n operaatiot olisivat mitenkään ihmeellisiä, vaan että kaiken pelin kannalta olennaisen voi toteuttaa ihan perusbittioperaatioilla millä tahansa kielellä.

Esim. laudassa on 3 kierrosta, joissa kussakin on 8 ruutua, joten nappuloiden paikkoja voidaan esittää 3*8 bittivektorina:

int lauta = sisinKierros | (keskiKierros << 8) | (uloinKierros << 16);

Jos halutaan tarkistaa, onko jossain kohtaa myllyä, riittää tehdä bitti-and sopivalla maskilla. Esimerkiksi vinottain vasemmalta yläkulmasta saatavan myllyn testaus onnistuu seuraavasti:

int maski = 1 | (1<<8) | (1<<16);
if ((lauta & maski) == maski) {/* mylly löytyi. */}

Näitä maskeja ei tietenkään tarvitse oikeassa koodissa kirjoitella käsin, vaan ne voi generoida koodilla, joka on lyhyempi kuin nuo pasteamasi määritykset.

Metabolix [17.01.2014 22:09:13]

#

Minäkään en ymmärrä, mitä kisan kannalta hienoa tai hyödyllistä on siinä, että PL/I:llä voi tehdä noin. Vaikea uskoa, että tekoälyllä olisi mitään toivoa kisassa, jos sen tärkein toimintaa määrittelevä piirre on pelilaudan tallennusmuoto. Jopa esimerkkiohjelmassa on mielestäni tärkeimpänä asiana ruudun valinta. Tekoälyn ohjelmoimiseen ei vaikuta tippaakaan, miten lauta tallennetaan ja mylly tarkistetaan; jokainen fiksu koodari kapseloi tarvitsemansa tarkistukset esimerkiksi funktioihin, jotta niiden käyttö varsinaisessa tekoälyssä on toteutuksesta riippumatta yhtä yksinkertaista. Vain nopeus voi muuttua, ja siinä bittioperaatiot luultavasti jyräävät.

jalski [17.01.2014 22:43:55]

#

Sisuaski kirjoitti:

Jos halutaan tarkistaa, onko jossain kohtaa myllyä, riittää tehdä bitti-and sopivalla maskilla. Esimerkiksi vinottain vasemmalta yläkulmasta saatavan myllyn testaus onnistuu seuraavasti:

int maski = 1 | (1<<8) | (1<<16);
if ((lauta & maski) == maski) {/* mylly löytyi. */}

Onko tuo mielestäsi helpompi hahmottaa, kuin:

if all(top1) then
  do;
      ...
  end;

Tai kaikkien pystylinjassa kehillä olevien myllyjen tarkastus yhdellä kertaa:

dcl result bit(9);
dcl num_result fixed bin(31);

result = string(boards(1,*)) & string(boards(2,*)) & string(boards(3,*));
num_result =  tally(result, '1'b);
display('Myllyjä kehillä pystylinjassa: ' || trim(num_result));

Nythän siis result bittimerkkijonon bitti vastaa suoraan tiettyä myllyä.

Metabolix [17.01.2014 22:48:36]

#

jalski kirjoitti:

Sisuaski kirjoitti:

int maski = 1 | (1<<8) | (1<<16);
if ((lauta & maski) == maski) {/* mylly löytyi. */}

Onko tuo mielestäsi helpompi hahmottaa, kuin:

if all(top1) then

Nyt varmaan esität vain tyhmää.

#define all(x) (((lauta) & (x)) == (x))
#define top1 (1 | (1<<1) | (1<<2))

Ongelma ratkaistu!

jalski [17.01.2014 23:06:37]

#

Metabolix kirjoitti:

Nyt varmaan esität vain tyhmää.

#define all(x) (((lauta) & (x)) == (x))
#define top1 (1 | (1<<1) | (1<<2))

Ongelma ratkaistu!

Sinäkin näköjään missasit varsinaisen pointtini: Voin muokata pelilauta matriisia, sen alimatriiseja tai määrittelemiäni vektoreita ja kaikki muutokset heijastuvat suoraan samalle pelilaudalle. Tila varataan siis vain varsinaiselle pelilauta matriisille.

Näytäpä tuohon joku näppärä esikääntäjä jippo...

Sisuaski [18.01.2014 00:06:23]

#

Toistetaan nyt vielä mitä Metabolix jo totesi: on aivan yhdentekevää, vaikka kuinka hienona rakenteena esittäisit laudan; oleellista ovat ainoastaan laudalle tehtävät operaatiot, ja niiden yksityiskohdat voi piilottaa funktioiden tai makrojen sisään. Jos haluat todistaa PL/I:si ylivertaisuuden, sinun on näytettävä jokin pelin kannalta oleellinen operaatio, jota ei voi esittää C:n funktiona. Et ole tähän mennessä tarjonnut mitään sellaista, ja pelkkä hieno pelilaudan sisäinen toteutus ei ole vastaus.

jalski [18.01.2014 03:34:01]

#

Sisuaski kirjoitti:

on aivan yhdentekevää, vaikka kuinka hienona rakenteena esittäisit laudan; oleellista ovat ainoastaan laudalle tehtävät operaatiot, ja niiden yksityiskohdat voi piilottaa funktioiden tai makrojen sisään.

Tuo nyt on pelkästään typerää väittää, että yleisesti tiedon esitys -tai tallennustavalla ei olisi mitään merkitystä ongelman ratkaisussa. Saan 15 yksinkertaisella testillä tarkastettua kaikki pelilaudan myllyt ja pelisiirrot saan tehtyä suoraan 2-ulotteiseen taulukkoon. En tarvitse tähän manuaalista bittien shiftaamista, enkä makroja. Kääntäjä hoitaa laskemisen suoraan.

Makroja on muuten C:stä puhuttaessa turha mainostaa, esikääntäjäkin on toiminnallisuudeltaan yksi ohjelmointi maailman rajoittuneimmista...

kllp [18.01.2014 07:30:04]

#

No voi hyvänen aika. Jos tuollainen triviaali tiedon esitys- ja tallennustavan muunnos tuottaa ongelmia, niin vaikea kuvitella, että muutenkaan olisi mahdollisuuksia saada ongelmaa ratkaistua. Vai luuletko tuollaisten PL/I-viritelmien muka olevan jotenkin nopeampia tms. kuin esimerkiksi C++:lla ja silmukoilla toteutetut toiminnaltaan vastaavat?

Makrot mainittiin vain yhtenä keinona. Jos ne tuntuvat liian rajoittuneilta, voi aina käyttää funktiota.

Metabolix [18.01.2014 11:28:05]

#

jalski kirjoitti:

Voin muokata pelilauta matriisia, sen alimatriiseja tai määrittelemiäni vektoreita ja kaikki muutokset heijastuvat suoraan samalle pelilaudalle.

Kerro nyt edes jokin järkevä esimerkkitapaus, jossa olisi tärkeää tuolla tavalla muokata juuri myllyä nimeltä top1 ja sen jälkeen kysyä, mitä pelilaudalle ja muille myllyille tapahtui. Sitä paitsi tekoälystä tulee todellinen purkkaviritelmä, jos käytät siinä yksitellen nimettyjä myllyjä: joudut ohjelmoimaan kaiken logiikan uudestaan jokaiselle eri myllylle, vaikka pelilauta on symmetrinen.

jalski kirjoitti:

Saan 15 yksinkertaisella testillä tarkastettua kaikki pelilaudan myllyt

Aiemmin sanoit, että pitää tarkistaa 22 siivua taulukosta. En ymmärrä kummankaan luvun alkuperää, kun pelissä on 20 myllyn paikkaa.

jalski kirjoitti:

pelisiirrot saan tehtyä suoraan 2-ulotteiseen taulukkoon.

Hieno homma, entä sitten? Oletko edes lukenut sääntöjä ja katsonut esimerkkiohjelmia: esimerkissä pelilauta kuvataan 3-ulotteisena taulukkona, jolloin myllyjen tarkistus on aivan äärimmäisen yksinkertaista ja mielestäni paljon selvempää ja tyylikkäämpää kuin sinun viritelmässäsi.

jalski kirjoitti:

Harmi, ettei Linuxille löydy kattavaa PL/I-kääntäjän toteutusta.

Mille käyttöjärjestelmälle sitten löytyy, ja mikä kääntäjä?

jalski [18.01.2014 13:54:24]

#

Metabolix kirjoitti:

Aiemmin sanoit, että pitää tarkistaa 22 siivua taulukosta. En ymmärrä kummankaan luvun alkuperää, kun pelissä on 20 myllyn paikkaa.

Tarvittavat tarkistuksethan ovat:

all(square1(1,*));
all(square1(3,*));

all(square2(1,*));
all(square2(3,*));

all(square3(1,*));
all(square3(3,*));

all(top1);
all(top2);
all(top3);

all(mid1);
all(mid3);

all(bottom1);
all(bottom2);
all(bottom3);

dcl result bit(9);
dcl num_result fixed bin(31);

/* Viimeiset kuusi myllyjen tarkistusta kerralla */
result = string(boards(1,*)) & string(boards(2,*)) & string(boards(3,*));
num_result =  tally(result, '1'b);

Metabolix kirjoitti:

jalski kirjoitti:

pelisiirrot saan tehtyä suoraan 2-ulotteiseen taulukkoon.

Hieno homma, entä sitten? Oletko edes lukenut sääntöjä ja katsonut esimerkkiohjelmia: esimerkissä pelilauta kuvataan 3-ulotteisena taulukkona, jolloin myllyjen tarkistus on aivan äärimmäisen yksinkertaista ja mielestäni paljon selvempää ja tyylikkäämpää kuin sinun viritelmässäsi.

Itse nyt vaan halusin käsitellä jokaista kehää omana taulukkonaan. Eikö mieleesi tule yhtään tapausta, joissa PL/I:n iSUB määrittely olisi hyödyllinen?

Oletko käsitellyt C:llä tietoa, mikä on tallennettu column-major järjestyksessä? PL/I:llä saan tuon muunnettua automaattisesti. Sama, jos on tarvetta matriisin transpoosille.

dcl Tmatrix(4, 4) def matrix(2sub, 1sub);

Yksi mielenkiintoinen määrittely, mikä on kirjassa tullut vastaan, on määrittely Sudoku ongelmien ratkaisua varten:

define alias bits bit(9) aligned;
dcl total(81) type bits;
dcl matrix(9, 9) type bits based(addr(total));
dcl box(9, 3, 3) type bits
                 def total(trunc((1sub-1)/3)*27 + mod(1sub-1, 3)*3
                           + (2sub-1)*9 + 3sub);

dcl posbit(0:9) type bits
           init ('000000000'b, '100000000'b,
                 '010000000'b, '001000000'b,
                 '000100000'b, '000010000'b,
                 '000001000'b, '000000100'b,
                 '000000010'b, '000000001'b );

Mielestäni tuo on hieno...

Metabolix kirjoitti:

jalski kirjoitti:

Harmi, ettei Linuxille löydy kattavaa PL/I-kääntäjän toteutusta.

Mille käyttöjärjestelmälle sitten löytyy, ja mikä kääntäjä?

Linuxille ja OS/2:lle löytyy kyllä tällä hetkellä ilmainen Iron Spring PL/I kääntäjä, mutta se on vasta beta-asteella ja siitä puuttuu vielä paljon IBM:n kääntäjän tukemia ominaisuuksia. Itselläni on käytössä vanha myynnistä poistunut IBM:n Windows kääntäjä. z/OS, AIX, VMS ja vanhemmille MVS järjestelmille kyllä löytyy erinomaisia kääntäjiä.

Metabolix [18.01.2014 17:44:49]

#

jalski kirjoitti:

Mielestäni tuo on hieno...

Mielestäni voin toteuttaa ihan vastaavan toiminnallisuuden C++:n luokilla, mutta se ei tietenkään ole niin hienoa, kun silloin ei käytetä PL/I:n tajuttoman mahtavia ominaisuuksia.

Jos kerran PL/I on niin ylivertainen, kokeilepa tehdä sillä kunnollinen tekoäly ja lähetä koodin lisäksi Windows-binääri. Jos se toimii Winellä ongelmitta, voin kelpuuttaa sen kisaan. Sittenpä nähdään, onko tuolla teknisellä nipotuksella mitään tekemistä tekoälyohjelmoinnin kanssa.

jalski [19.01.2014 11:12:11]

#

Metabolix kirjoitti:

Jos kerran PL/I on niin ylivertainen, kokeilepa tehdä sillä kunnollinen tekoäly ja lähetä koodin lisäksi Windows-binääri. Jos se toimii Winellä ongelmitta, voin kelpuuttaa sen kisaan. Sittenpä nähdään, onko tuolla teknisellä nipotuksella mitään tekemistä tekoälyohjelmoinnin kanssa.

En väittänyt PL/I:tä ylivertaiseksi, vaan mielestäni se antaa mahdollisuuden tehdä monimutkaisia asioita declare lausekkeessa ja pitää sitten muu ajettava koodi yksinkertaisena.

Voin kyllä yrittää ehtiä saamaan jonkunlaisen kilpailuohjelman kasaan. Oma aika kylläkin on joulusta lähtien ollut hiukan vähissä, kun olen nykyään pienen poikavauvan isä ja töissäkin pitää hoppua.

Kuinka hyvin tuo Wine toimii? Koodivinkeissä on Miinaharavan kommenteissa PL/I-versio. Pystyykö tuota ajamaan Wine:n kautta? Voin kyllä käyttää tarvittaessa aiemmin mainitsemaani Iron Spring PL/I kääntäjääkin. Tuossa kääntäjässä on vielä rajoituksia, mutta tulen niiden kanssa kyllä toimeen ja olen tuota käytellyt OS/2 alustalla.

Metabolix [19.01.2014 11:41:58]

#

jalski kirjoitti:

En väittänyt PL/I:tä ylivertaiseksi, vaan mielestäni se antaa mahdollisuuden tehdä monimutkaisia asioita declare lausekkeessa ja pitää sitten muu ajettava koodi yksinkertaisena.

En edelleenkään ymmärrä, miten tämä olisi täysin eri asia kuin muissa kielissä, joissa myös voi tehdä monimutkaisia asioita kussakin tavallaan (makroilla, funktioilla, luokilla, templaateilla) ja pitää sitten muun ajettavan koodin yksinkertaisena. Ihan yhtä lailla mielestäni niissäkin ”kääntäjä hoitaa laskemisen suoraan”, ja luultavasti tulos on monessa tapauksessa vielä tehokkaampi kuin PL/I:llä.

Yhden bitin hienosteluissasi et näytä myöskään huomioineen, että pelissä on kaksi pelaajaa, vai ajattelitko pitää pelaajat eri laudoilla?

jalski kirjoitti:

Kuinka hyvin tuo Wine toimii? Koodivinkeissä on Miinaharavan kommenteissa PL/I-versio. Pystyykö tuota ajamaan Wine:n kautta?

Aika hyvin toimii, ja ajaa myös miinaharavasi. Ajankäyttöön tulee toki pieni sakko käynnistyksestä, arviolta 0,1 sekuntia, mutta tämä tuskin vaikuttaa lopputulokseen. Staattinen linkitys ja strippaus olisivat plussaa, jos ympäristö sallii eikä ohjelma paisu käsittämättömästi.

ajv [19.01.2014 23:49:55]

#

Tänään ehdin vähän perehtyä tähän. Lähinnä sain koodattua jonkunlaisen oman laudan, jolla voi pelata tekoälyä vastaan. Pakko nyt on joku "äly" saada aikaiseksi, kun aloittikin, aikaa ja energiaa ei vaan 4 lapsen paimentamisen ja työreissujen jälkeen juurikaan jää :)

jalski [20.01.2014 09:54:34]

#

Metabolix kirjoitti:

Yhden bitin hienosteluissasi et näytä myöskään huomioineen, että pelissä on kaksi pelaajaa, vai ajattelitko pitää pelaajat eri laudoilla?

Itse asiassa, alustavasti ajattelin käyttää useampaa bittilautaa. Ajatus olisi järjestää tieto siten, että saisin bitti-operaatioilla selvitettyä siirto mahdollisuudet aina mahdollisimman monta kerrallaan. Lisäksi tarvitsen tietysti erillisen taulukon, mihin pisteyttää siirrot. Loppu onkin sitten bittimerkkijonosta hakua ja pisteytyksen vertailua.

Metabolix [24.01.2014 22:54:20]

#

Pari tekoälyä on nyt saapunut. Muistutan eräistä asioista:

Testatkaa tekoälyjänne edes pari kertaa. On aika hassua, jos tekoälyn kaikki pelit päättyvät laittomaan siirtoon tai kaatumiseen.

Kilpailukone on melko hidas, joten jos tekoäly ei ole selvästi todella nopea, kannattaa lähettää siitä jokin versio hyvissä ajoin ajankäytön arviointia varten.

Metabolix [27.01.2014 18:14:55]

#

Esimerkkiin oli jäänyt yhä bugi pelitilanne-luokan siirra-funktioon purettujen myllyjen suhteen: jos siirrolla ei muodostunut uutta myllyä, puretut myllyt jäivät nollaamatta. Suosittelen virheen korjaamista myös omista tekoälyistä. Samalla korjasin esimerkistä pari kirjoitusvirhettä. Lisäksi testausohjelmassa oli bugi, jonka vuoksi se ei huomioinut lentovaihetta, kun tarkisti, onko laillisia siirtoja vielä jäljellä.

Vielä yksi ehdotus: jos haluaa voittaa ottelun, ei kannata jäädä silmukkaan, jossa molemmat tekoälyt vain tekevät samaa siirtoa edestakaisin; tällä hetkellä joka kuudes ottelu päättyy tasapeliin näissä merkeissä.

jalski [29.01.2014 08:56:41]

#

Vapaa-aika ollut vähissä viime aikoina, mutta edistystä tapahtuu pienin askelin...

Tällä hetkellä kilpailuohjelma koostuu lähinnä taulukoista: Pelilauta esitetään bittitaulukkona, jota voi käsitellä kolmiulotteisena ja yksiulotteisena taulukkona. Esitän pelilaudan kehät 3x3 bittitaulukona, josta keskimmäisen rivin keskimmäinen ruutu ei ole sallittu. Kokonaisuudessaan pelilauta esitetään siis 27 bitillä.

Molemmat pelaajat tallentavat siirtonsa omiin taulukkoihinsa ja lisäksi tarvitaan yksi taulukko, missä on tallennettuna kaikki sallitut paikat pelilaudalla. Pelilaudan jokaista ruutua vastaavat siirtomahdollisuudet on myös tallennettu bittimerkkijonoina taulukkoon. Kaikki siirtomahdollisuudet saadaan käytyä läpi erittäin nopeasti käyttämällä boolean operaatioita ja merkkijonohakua.

Pelilaudan kaikkien myllyjen tarkistuksen sain rutistettua muutamaan bittimerkkijonojen liittämiseen ja boolean operaatioon.

Vaikein osuus ohjelmasta tosin puuttuu, eli saada se pelaamaan järkevästi...

Apodus [02.02.2014 13:07:24]

#

Joko on kaikilla taskut täynnä virheettömästi pelaavia kyborgeja? Onko kukaan hyödyntänyt sitä yhden megan datafileä?

Nyt tuo oma botti tuntuu pelaavan jotenkuten järkevästi, vaikka en PL/I:tä käyttänytkään. Mutta vaikea arvioida kuinka hyvin, kun olen itse niin surkea tässä pelissä. Aika tavanomainen alpha-beta siitä lopulta tuli, parilla lisävirityksellä höystettynä.

jalski [02.02.2014 18:17:55]

#

Apodus kirjoitti:

Nyt tuo oma botti tuntuu pelaavan jotenkuten järkevästi, vaikka en PL/I:tä käyttänytkään. Mutta vaikea arvioida kuinka hyvin, kun olen itse niin surkea tässä pelissä.

Heh, pistä se kokeeksi pelaamaan tätä vastaan. Tuo tekee siirtonsa ainakin nopeasti, vaikkei ehkä oikeasti pelata osaakaan. Käyttää yksinkertaista merkkijonohakua ja bittimerkkijonoja seuraavan siirron valintaan. Syötteen -ja virheentarkistus minimaalinen, eli sitä ei käytännössä siis ole...

Apodus [02.02.2014 18:49:02]

#

Tuo ohjelma meni täällä ajettuna ilmeisesti vähän jojoon:

(fatal error: load of message file failed)

Lisäys: Tuo virhe näyttäisi tapahtuvan kun tekoälyllä on jäljellä kolme lehmää ohjattavana.

jalski [02.02.2014 19:56:34]

#

Apodus kirjoitti:

Tuo ohjelma meni täällä ajettuna ilmeisesti vähän jojoon:

(fatal error: load of message file failed)

Lisäys: Tuo virhe näyttäisi tapahtuvan kun tekoälyllä on jäljellä kolme lehmää ohjattavana.

Kokeile ladata tiedosto uudelleen. Löysin antamasi tiedon avulla heti kirjoitus virheen koodista: Olin kirjoittanut 'moves' nimisen muuttujan nimellä 'move' IF-lauseeseen. Kääntäjä ei tuota huomannut, koska 'move' niminen muuttuja on myös määritelty...

Apodus [02.02.2014 20:05:57]

#

Juu nyt pelasi pelin onnistuneesti loppuun saakka.
Ei kuitenkaan aivan yltänyt voittoon aloittaessaan.

Lisäys:

Voit kokeilla vaikka tätä vastaan devatessa:
https://drive.google.com/file/d/0BynQ22YM8ugQQUpTeXl6cFZZZ1U/edit?usp=sharing

Metabolix [02.02.2014 20:35:26]

#

Kokeilinpa itsekin tuota jalskin ohjelmaa. Nyt se näyttää muuten toimivan, mutta jostain syystä kakkospelaajana se usein palauttaa virhekoodin 232 pelin päättyessä.

Kisan tulokset näyttävät tässä vaiheessa hassuilta, koska listan häntäpäässä on pari hyvää mutta liian hidasta tekoälyä: monta voittoa, vain pari häviötä, negatiiviset kokonaispisteet. >:)

Oskuz [02.02.2014 21:48:58]

#

Pitäiskö tehä brainfuck versio kun on vielä viikko aikaa? :)

FooBat [03.02.2014 02:01:09]

#

Käytetäänkö muuten tätä javalla tehtyä testausohjelmaa kilpailussa ohjelmien aikojen mittaamiseen?

Siinä nimittäin on sellainen bugi ajanotossa, että jos ensimmäinen pelaaja ei sulje itseään, TOISEN pelaajan aikaan lisätään noin 2 sekuntia. Jos toinen pelaaja ei sulje itseään, se ei vaikuta kummankaan ajanottoon. Tätä voi helposti testata esimerkkiohjelmalla tekemällä siitä toisen version, jonka lopussa on while(1);

jalski [03.02.2014 08:01:33]

#

Metabolix kirjoitti:

Kokeilinpa itsekin tuota jalskin ohjelmaa. Nyt se näyttää muuten toimivan, mutta jostain syystä kakkospelaajana se usein palauttaa virhekoodin 232 pelin päättyessä.

Ajat ilmeisesti linuxin päällä, Windows nimittäin antaa exit-koodiksi 1000. Muutin nyt ohjelman siten, että ei enää anna tuota. Johtui siitä, että lopetin ohjelman STOP käskyllä ennenaikaisesti, jos siirto mahdollisuksia ei enää ollut.

Lisäys:

FooBat kirjoitti:

Siinä nimittäin on sellainen bugi ajanotossa, että jos ensimmäinen pelaaja ei sulje itseään, TOISEN pelaajan aikaan lisätään noin 2 sekuntia. Jos toinen pelaaja ei sulje itseään, se ei vaikuta kummankaan ajanottoon. Tätä voi helposti testata esimerkkiohjelmalla tekemällä siitä toisen version, jonka lopussa on while(1);

Tarkista aina tekoälyssäsi sille tuleva syöte, jos se on: '0 0 0 0 0 0 0 0 0', niin lopeta ohjelma.

Metabolix [03.02.2014 15:45:58]

#

FooBat kirjoitti:

Käytetäänkö muuten tätä javalla tehtyä testausohjelmaa kilpailussa ohjelmien aikojen mittaamiseen?

Ei, kilpailussa ajat mitataan time-komennolla, joka antaa tarkemman tuloksen. Korjaanpa silti myös tuota testausohjelmaa.

jalski kirjoitti:

Ajat ilmeisesti linuxin päällä, Windows nimittäin antaa exit-koodiksi 1000.

Oliko Linux jotenkin yllätys, kun se lukee säännöissäkin, ja onko mielestäsi 1000 jotenkin parempi kuin 232 (joka muuten on 1000 modulo 256)? Yleinen käytäntö on, että ohjelmat palauttavat koodin 0, jos suorituksessa ei tapahdu virhettä.

Apodus [03.02.2014 17:26:24]

#

Kyseessä lienee vain mielenkiintoinen havainto, että ne palauttavat eri arvot eri platoilla. Ja se että kisa ajetaan linuksilla ei varmaankaan tarkoita että jokainen hupitesti pakottavasti ajetaan linuksilla :)

Alkaa kyllä ideat loppua kesken, että mitä kelmeilyjä tuo AI vielä voisi oppia! Toivottavasti tulee vaikean tasokas kilpailu.

jalski [03.02.2014 18:25:28]

#

Apodus kirjoitti:

Kyseessä lienee vain mielenkiintoinen havainto, että ne palauttavat eri arvot eri platoilla. Ja se että kisa ajetaan linuksilla ei varmaankaan tarkoita että jokainen hupitesti pakottavasti ajetaan linuksilla :)

Aivan, mainitsin ohjelman palauttavan arvon 1000 Windows alustalla arvon 232 sijaan, jotta olisi helpompi hahmottaa sen alkuperä. PL/I tulee mainframe puolelta ja esim. Z/OS-käyttöjärjestelmässä ajettavan PL/I-ohjelman palautus koodit ovat:

Normal application termination        : 0
Termination_Imminent due to STOP      : 1000
Error — abnormal termination          : 2000
Severe error — abnormal termination   : 3000
Critical error — abnormal termination : 4000

On tietysti mahdollista asettaa user return code PL/I-ohjelmassa PLIRETC-kutsulla, mutta tällöinkin sen arvo lisätään johonkin ylläolevista arvoista riippuen ohjelman tilasta.

Jos tuo 1000 ohjelman palautusarvona kiusaa, niin STOP komennon voi aina vaihtaa SIGNAL FINISH komentoon. Itse korvasin sen vain GOTO komennolla.

Metabolix [06.02.2014 20:14:01]

#

jalski: Hieno juttu, mutta eikö silti normaali päättyminen ole ilmiselvästi tavoiteltavampi asia kuin äkillinen päättyminen STOP-komentoon?

Nyt on enää pari päivää jäljellä, joten koettakaahan kirjoittaa tekoälyjä! Kisassa on vielä monta hyvää sijoitusta jaossa. ;)

ajv [06.02.2014 21:42:44]

#

Mulla jää valitettavasti osallistuminen väliin. Kuvittelin kirjoittelevani tätä iltaisin hotellilla, kun olin pari viikkoa työreissussa, mutta ei oikeen puhti sitten riittänyt 10-12h työpäivien (=koodaamista) jälkeen :)

Metabolix [09.02.2014 18:00:00]

#

Kilpailu on ohi!

Kilpailu on nyt päättynyt ja tulokset on julkaistu. Kilpailun voitti FooBat tekoälyllään CowKing. Onneksi olkoon!

FooBat [09.02.2014 18:07:20]

#

Wohoo!

Metabolix [21.02.2014 20:04:31]

#

Jälkihuomiona kisasta täytyy sanoa, että pistelaskun käyttö aikarajana toimi hyvin ja on varmaan käytössä jatkossakin mutta pelin säännöt olivat selvästi liian monimutkaiset ainakin tuon saman myllyn purkamis- ja palautussäännön osalta.

Chiman [22.02.2014 16:08:17]

#

Metabolix kirjoitti:

pelin säännöt olivat selvästi liian monimutkaiset

Sääntöjen monimuotoisuus ratkaisi oman osallistumattomuuteni tällä kertaa. Ensin lehmien asetteluvaihe, sitten siirtäminen, myllyn purku- ja palautussääntö ja lopuksi kolmen lehmän lentäminen. Mikään näistä ei ole vaikea toteuttaa ohjelmallisesti, mutta kokonaisvaiva vaikutti.

Taannoinen Kivi, sakset, paperi -kisa oli erinomainen juuri yksinkertaisten sääntöjen takia. Siinä pystyi keskittymään tekoälyyn, jolla olikin yllättävän iso merkitys.

Kiitos kuitenkin kisojen järjestämisestä ja onnittelut voittajalle!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta