Kurssin viimeisimmän version löydät täältä: O1: 2024
- CS-A1110
- Kierros 11
- Luku 11.3: Kamppailevia robotteja
Luku 11.3: Kamppailevia robotteja
Tästä sivusta:
Pääkysymyksiä: Tehtäisiinkö ohjelma, joka käsittelee ohjelmia? Voisivatko virtuaalirobottimme toimia jotenkin yhteen?
Mitä käsitellään? Toinen ohjelmointikieli osana tietokoneohjelmaa; "virtuaalikoneet". Pino kokoelmatyyppinä; yksinkertaisen kutsupinon toteuttaminen. Lisäharjoitusta aiemmista aiheista.
Mitä tehdään? Tutustutaan annettuun ohjelmaan ja täydennetään sitä.
Suuntaa antava työläysarvio:? Neljä tuntia? Omaa koodattavaa on melko vähän, mutta kokonaisuuteen perehtyminen vie aikaa.
Pistearvo: C95.
Oheisprojektit: RobotTribes (uusi), joka tarvitsee myös Robots-projektin.
Johdanto
Tässä luvussa jatketaan aiemman kierroksen robottiteemaa ja toteutetaan keskenään nahistelevia "robottiheimoja".
Jokaisella robottiheimolla on erillinen ohjelmakoodinsa, joka määrää, miten heimon jäsenet käyttäytyvät. Kunkin heimon koodi on omassa tekstitiedostossaan, joka ei sisällä Scalaa vaan juuri tähän tarkoitukseen suunniteltua RoboSpeak-kieltä. RoboSpeak-kielinen ohjelma koostuu yksinkertaisista robottien toimintaa säätelevistä käskyistä. Esimerkiksi seuraava pieni RoboSpeak-ohjelma määrää robotin kävelemään ruudukossa pientä neljän ruudun kokoista neliötä myötäpäivään:
1 2 3 | move # liiku yksi ruutu eteenpäin
spin # käänny myötäpäivään
goto 1 # siirry riville 1
|
RobotTribes-projektin sisältämä Scala-sovellusohjelma lukee RoboSpeak-kielisiä ohjelmia tiedostoista, tulkitsee RoboSpeak-käskyt, tallentaa ne Scala-olioina ja ohjaa heimorobotteja käskyjen mukaisesti. Uusia heimoja voi määritellä luomalla uusia RoboSpeak-ohjelmia; Scala-koodiin ei tätä varten kosketa.
Sen lisäksi, että heimorobotit osaavat noudattaa heimonsa RoboSpeak-ohjelmaa, ne osaavat "häkätä" toisten heimojen jäseniä liittymään omaansa ja tekevätkin tätä innokkaasti. Tästä seuraa, että samaan robottimaailmaan sijoitetut heimot taistelevat eloonjäämisestä kunkin heimon yrittäessä rekrytoida lisää jäseniä toisista. Alakynteen jäänyt heimo katoaa helposti tyystin, kun sen viimeisetkin jäsenet loikkaavat vahvempaan heimoon. Näet esimerkkejä heimojen välisistä kamppailuista hieman myöhemmin.
Tämän luvun rakenne
Tämän luvun pohjana on RobotTribes-oheisprojekti. Tutuksi tulleeseen tapaan projektista on annettu lähes toimintakuntoinen versio, jossa on kuitenkin ratkaisevia puutteita. Tämä luku sisältää monivaiheisen ohjelmointitehtävän, jossa pääset korjaamaan nämä puutteet.
Aloitetaan yleiskuvalla RobotTribes-projektista.
RobotTribes-projekti
Robots-projektista
RobotTribes-projekti on johdettu lukujen 8.1, 8.2 ja 8.3 Robots-projektista. Jos kasikierroksen sisältö ei ole tuttua, perehdy siihen nyt. Se on välttämätöntä esitietoa tälle luvulle.
Jos et tehnyt Robots-tehtäviä, tee ne tai käytä esimerkkiratkaisuja.
RobotTribes jakautuu kahteen pakkaukseen:
o1.robots.tribal
-pakkauksen sisältö laajentaao1.robots
-pakkauksen sisältöä heimoilla ja heimoihin kuuluvilla roboteilla.o1.robots.gui
määrittelee graafisen sovelluksen, joka on heimoilla laajennettu versio alkuperäisestäRobotApp
-sovelluksesta. Käyttöliittymä on annettu valmiina, eikä sitä käsitellä tässä sen tarkemmin.
Alla on taulukoitu o1.robots.tribal
-pakkauksen keskeisin sisältö.
Komponentti | Kuvaus | Tila |
---|---|---|
luokka TribalBot |
Robots-projektin luokan RobotBrain aliluokka. Kuvaa
heimoihin kuuluvia robotteja, jotka toimivat heimonsa
RoboSpeak-ohjelman mukaisesti. |
annettu puutteellisena |
luokka Tribe |
Kuvaa robottiheimoja. Kukin Tribe -olio osaa lukea
heimon RoboSpeak-ohjelmakoodin tiedostosta ja tulkita
sen kyseistä ohjelmaa vastaaviksi
Instruction -olioiksi. |
valmis |
piirreluokka
Instruction |
Kuvaa yksittäisiä RoboSpeak-ohjelman käskyjä.
Kullakin näistä on execute -metodi, jota kutsumalla
robotti suorittaa kyseisen käskyn. Erilaiset käskyt on
toteutettu Instruction in alikäsitteinä; näitä
konkreettisia luokkia ei tarvitse tässä tehtävässä
tuntea tarkemmin. |
valmis |
luokka Stack |
Kuvaa kutsupinoa, jollaisessa kukin RoboSpeak-ohjelmaa suorittava robotti pitää kirjaa aliohjelmakutsuista. (Tätä luokkaa tarvitaan vasta viimeisissä vaiheissa, eikä se löydy alla olevasta kaaviosta.) | puuttuu lähes kokonaan |
luokka Frame |
Kuvaa yksittäistä kehystä robotin kutsupinossa. (Tätä luokkaa tarvitaan vasta viimeisissä vaiheissa, eikä se löydy alla olevasta kaaviosta.) | valmis |
Vaihe 1/9: tutustu RoboSpeakiin
- RoboSpeak-kieli on kuvattu luokan
Tribe
Scaladoc-dokumentaation alussa. Lue sieltä nyt ensimmäiset seitsemän kappaletta: RoboSpeak, Action Instructions, An Introductory Example, Basic Logic, Labels, Comments and Whitespace ja Pacifist Tribes. Loput kappaleet voit jättää toistaiseksi lukematta. - Vastaa seuraaviin kysymyksiin. Valitse kussakin kohdassa ne vaihtoehdot, jotka vastaavat kyseisen RoboSpeak-ohjelman kuvaaman heimon toimintaa.
Vaihe 2/9: heimot liikkeelle
- Tutustu huolellisesti
TribalBot
-luokan dokumentaatioon ja ohjelmakoodiin sekä piirreluokanInstruction
dokumentaatioon. - Toteuta puuttuvista osista tässä vaiheessa
moveBody
-metodi.- Käytä apuna
TribalBot
-luokannextInstruction
-muuttujaa. - Huomaa hyödyntää
Instruction
-olionexecute
-metodin palauttamaa arvoa. - Sijoita metodiin jo myös asiaankuuluva
hack
-metodin kutsu. Se ei tosin vielä tee mitään, koska tuon metodin toteutus on tyhjä.
- Käytä apuna
Vaihe 3/9: testaillaan
Nyt on käypä aika kokeilla RoboSpeak-ohjelmia käytännössä.
- Käynnistä
TribalApp
-sovellus ja luo erilaisia robotteja valmiina tarjolla olevista heimoista.- Samalla kun kokeilet niitä, tutustu niiden
RoboSpeak-koodiin, joka löytyy
tribes
-kansiosta projektin sisältä. - Huomaa: robotit liikkuvat mutta eivät vielä hyökkää toisten heimojen kimppuun. (Valmiista heimoista Patrolman-heimo ei myöskään liiku oikein, koska aliohjelmakutsuja ei ole vielä toteutettu.)
- Samalla kun kokeilet niitä, tutustu niiden
RoboSpeak-koodiin, joka löytyy
- Kokeile itse luoda pikkuinen RoboSpeak-koodinpätkä:
- Kirjoita joitakin RoboSpeak-käskyjä (esim.
move, spin, uturn, goto)
tribe
-päätteiseen tiedostoontribes
-kansioon. - Jos haluat valita robotille kuvan, sijoita
samaan kansioon myös vastaava PNG-kuvatiedosto.
Joitakin valmiita kuvavaihtoehtoja löytyy
extra_pics
-alikansiosta, mutta muitakin saa käyttää.
- Kirjoita joitakin RoboSpeak-käskyjä (esim.
move, spin, uturn, goto)
Vaihe 4/9: Lisää toiminnallisuutta
- Jos et ole vielä lukenut
Tribe
-luokan Scaladocista kappaleita Using Memory Slots, Radar Commands ja Hacking and Talking, niin lue ne nyt. - Toteuta
TribalBot
-luokkaan metodidetermineTribe
. Luokan muut metodit tarvitsevat sitä pystyäkseen erottamaan vihollisen ystävästä.- Huomaa, että parametrina voi olla mikä
tahansa
RobotBrain
mutta kaikillaRobotBrain
eillä ei oletribe
-muuttujaa. - Metodin voi toteuttaa esimerkiksi
match
-käskyllä, joka tutkii parametrin dynaamista tyyppiä; vrt. luku 7.2.
- Huomaa, että parametrina voi olla mikä
tahansa
- Toteuta metodi
isFriend
.- Käytä
determineTribe
ä ja etsi hyödyllisiä välineitäTribalBot
-luokasta muutenkin. - Tämän tehtyäsi robottien pitäisi pysähtyä vihollisen kohdalla, mutta ne eivät tee vastaantulijalle mitään.
- Käytä
- Saata robotin tutka ja talk-komento toimimaan: täydennä
metodit
longRadar
jatalk
.
talk
-metodinkin toteuttamiseen löytyy apuneuvojaTribalBot
-luokasta itsestään. Käytä luokkaan valmiiksi toteutettuja metodeita, niin toteutuksesta tulee hyvin yksinkertainen.- Millä luvun 6.2 kokoelmametodeista
longRadar
on hyvin helppo toteuttaa, kunhan ensin pyydät robottimaailmalta luettelon kaikista sen sisältämistä roboteista?
Voit nyt kokeilla RoboSpeak-ohjelmissasi käskyjä talk, shout, enemiesnear, friendsnear, foddernear, fodderleft, score, friendsdir ja enemiesdir, joihin tekemäsi muutokset vaikuttavat.
Vaihe 5/9: häkkääminen
- Toteuta
hack
-metodi. Käytä taas apuna muitaTribalBot
-luokasta löytyviä metodeita. - Kokeile
TribalApp
-ohjelman käyttöä uudestaan. Havainnoi, miten heimot kamppailevat keskenään. Kokeile erilaisia skenaarioita yläreunan valikosta. Kamppailuta esimerkiksi Tiger- ja Guardian-heimoja vastakkain.
Vaihe 6/9: aliohjelmakutsut: pohjustus
RoboSpeak-käskyt callsub ja return eivät vielä toimi, mutta pian pääset korjaamaan
asian. Tutustu ensin aiheeseen lukemalla Tribe
-luokan Scaladoc-dokumentaatiosta kohta Subprograms ja vastaa alla oleviin
heimontulkintakysymyksiin.
Jotta saat metodit toteutettua, on tarpeen lisätä kullekin heimorobotille oma kutsupino, jossa se voi pitää kirjaa siitä, mitkä aliohjelmakutsut ovat käynnissä ja mihin kohtaan kustakin kutsusta palataan.
TribalBots-projektissa on valmiina tarjolla luokka Frame
, joka kuvaa yksinkertaisia
kutsupinon kehyksiä. Tutustu siihen.
Periaatteessa voisimme kuvata kutsupinoa esimerkiksi Buffer[Frame]
-tyyppisellä
kokoelmalla. Käytetään nyt kuitenkin kokoelmatyyppiä, joka sopii vielä täsmällisemmin
juuri pinorakenteen kuvaamiseen.
Vaihe 7/9: Stack
-luokka
Kutsupino on esimerkki yleisemmästä pinon (stack) käsitteestä. Pino noudattaa LIFO-periaatetta (last in, first out):
- lisäys tehdään laittamalla uusi alkio "pinon päälle",
- poisto tehdään poistamalla "pinon päältä" viimeiseksi lisätty alkio.
Pinojen yhteydessä lisäämisestä käytetään usein termiä push ja poistamisesta termiä
pop. Sen nimiset metodit on määrätty toteutettavaksi myös projektimme luokalle Stack
;
lue sen dokumentaatio. Kuitenkin Stack
-luokka
on vasta alkutekijöissään tiedostossa Stack.scala
.
Toteuta Stack
-luokka. Käytä apuna yksityistä muuttujaa, joka viittaa pinon alkiot
sisältävään kokoelmaan. Tuo kokoelma voi olla esimerkiksi puskuri tai vektori, mutta
suosittelemme, että tutustut alla lyhyesti esiteltyyn List
-kokoelmatyyppiin, joka
sopii tarkoitukseen hyvin ja on muutenkin sivistävä tuttavuus.
Vähän List
-luokasta
Lista (list) on muuttumaton alkiokokoelma ja muistuttaa sikäli muun muassa vektoreita. Toteutustekniikastaan johtuen listat sopivat tehokkuusominaisuuksiltaan erityisesti tilanteisiin, joissa käsitellään nimenomaan kokoelman alkupään alkioita tai käydään kokoelmaa läpi järjestyksessä. Toisaalta lista ei yleensä ole hyvä valinta, jos tarkoitus on poimia mielivaltaisia alkioita jostakin päin kokoelmaa esimerkiksi indeksin perusteella.
Scalassa listoja kuvaa tietotyyppi scala.List
.
Listaa käytetään pitkälti niin kuin ennestään tuttuja kokoelmia. Uuden listan luominen käy esimerkiksi näin:
val tyhjaLista = List[Int]()tyhjaLista: List[Int] = List() var sanalista = List("eka", "toka", "kolmas")sanalista: List[String] = List(eka, toka, kolmas)
Tutut metodit ovat tarjolla:
sanalista.sizeres0: Int = 3 sanalista.tailres1: List[String] = List(toka, kolmas) sanalista.map( _.length )res2: List[Int] = List(3, 4, 6)
Operaattoria ::
käytetään nimenomaan listoja käsiteltäessä. Se muodostaa
uuden listan, jonka alussa on lisäalkio, ja vastaa siis kokoelmien yleistä
operaattoria +:
(luku 4.1) ja virtojen operaattoria #::
(luku 7.1).
sanalista = "alkuun" :: sanalistasanalista: List[String] = List(alkuun, eka, toka, kolmas)
Pinon toteuttamiseen lista sopii hyvin: voidaan pitää pinon päällimmäistä alkiota listan alussa ja pohjimmaista lopussa. Kaikki lisäykset ja poistot kohdistuvat pinon päälle eli listan alkuun.
Listat ovat erityisesti funktionaalisessa ohjelmoinnissa yleisiä. Niitä käytetään monissa Scala-ohjelmissa. Mm. kurssilla Ohjelmointi 2 ne ovat merkittävässä roolissa.
Vaihe 8/9: kutsupino käyttöön
TribalBot
-luokkaan on jo määritelty callStack
-muuttuja, joka on tyyppiä Stack[Frame]
eli kehyksiä sisältävä pino. Annettu koodi ei kuitenkaan hyödynnä sitä.
Toteuta metodit callSubprogram
ja returnFromSubprogram
. Käytä apuna
callStack
-muuttujaa ja sen osoittamaa Stack[Frame]
-oliota
Voit sitten kokeilla toteutuksesi toimivuutta Patrolman-heimolla tai jollakin itse laatimallasi RoboSpeak-ohjelmalla.
Vaihe 9/9: loppu
- Pohdi, mitä yhteistä on RobotTribes-projektilla ja virtuaalikoneilla (luku 5.2). Voit myös pohtia, millä tavoin RoboSpeak muistuttaa konekieliä. Selvitä internetistä vaikkapa, millaisia hyppykäskyjä konekielissä on.
- Palauta täydentämäsi RobotTribes-toteutus.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Lisätehtäviä
Pieni lisätehtävä täsmäkielistä
RoboSpeakia voi kutsua täsmäkieleksi eli DSL:ksi
(domain-specific language). Selvitä, mitä tällä tarkoitetaan.
Millaisiin tarkoituksiin täsmäkieliä käytetään? Onko RoboSpeak
sisäinen (internal) vai ulkoinen (external) DSL? Voisiko
play
-funktiolle välitettäviä merkkijonoja kutsua täsmäkielisiksi?
collect
-metodi
Metodissa shout
on käytetty collect
-nimistä kokoelmien metodia.
Selvitä internetin avulla, mitä tuo metodi tekee ja miten sitä on
tässä käytetty.
Haastavia lisätehtäviä robottiheimoista
- Tutustu
Tribe.scala
-tiedoston sisältöön. Selvitä, miten RoboSpeak-rivien jäsentäminen toimii sekä millaisen käsitehierarkian erilaisetInstruction
-tyypin alatyypit muodostavat. Apuna voit käyttää Kirjoja ja linkkejä -sivullakin mainittua kirjaa Programming in Scala, Third Edition ja erityisesti sen lukua 33, Combinator Parsing. - Ideoi ja toteuta jokin oma uusi käsky RoboSpeakiin. Lisää
käskysi RoboSpeakin kielioppiin ja kirjoita sitä kuvaava
Instruction
-alatyyppi. - Lisää roboteille mahdollisuus käyttää aliohjelmissa
paikallisia muuttujia, joiden arvoista pidetään kirjaa
robotin kutsupinon kehyksissä eli
Frame
-olioissa.
Palaute
Huomaathan, että tämä on henkilökohtainen osio! Vaikka olisit tehnyt lukuun liittyvät tehtävät parin kanssa, täytä palautelomake itse.
Tekijät
Tämän oppimateriaalin kehitystyössä on käytetty apuna tuhansilta opiskelijoilta kerättyä palautetta. Kiitos!
Kierrokset 1–13 ja niihin liittyvät tehtävät ja viikkokoosteet on laatinut Juha Sorva.
Kierrokset 14–20 on laatinut Otto Seppälä. Ne eivät ole julki syksyllä, mutta julkaistaan ennen kuin määräajat lähestyvät.
Liitesivut (sanasto, Scala-kooste, usein kysytyt kysymykset jne.) on kirjoittanut Juha Sorva sikäli kuin sivulla ei ole toisin mainittu.
Tehtävien automaattisen arvioinnin ovat toteuttaneet Riku Autio, Jaakko Kantojärvi, Teemu Lehtinen, Timi Seppälä, Teemu Sirkiä ja Aleksi Vartiainen.
Lukujen alkuja koristavat kuvat ja muut vastaavat kuvituskuvat on piirtänyt Christina Lassheikki.
Yksityiskohtaiset animaatiot Scala-ohjelmien suorituksen vaiheista ovat suunnitelleet Juha Sorva ja Teemu Sirkiä. Niiden teknisen toteutuksen ovat tehneet Teemu Sirkiä ja Riku Autio käyttäen Teemun toteuttamia Jsvee- ja Kelmu-työkaluja.
Muut diagrammit ja materiaaliin upotetut vuorovaikutteiset esitykset on laatinut Juha Sorva.
O1Library-ohjelmakirjaston ovat kehittäneet Aleksi Lukkarinen ja Juha Sorva. Useat sen keskeisistä osista tukeutuvat Aleksin SMCL-kirjastoon.
Opetustapa, jossa käytämme O1Libraryn työkaluja (kuten Pic
) yksinkertaiseen graafiseen
ohjelmointiin on saanut vaikutteita tekijöiden Flatt, Felleisen, Findler ja Krishnamurthi
oppikirjasta How to Design Programs sekä Stephen Blochin oppikirjasta Picturing Programs.
Oppimisalusta A+ on luotu Aallon LeTech-tutkimusryhmässä pitkälti opiskelijavoimin. Pääkehittäjänä toimii tällä hetkellä Jaakko Kantojärvi, jonka lisäksi järjestelmää kehittävät useat tietotekniikan ja informaatioverkostojen opiskelijat.
Kurssin tämänhetkinen henkilökunta on kerrottu luvussa 1.1.
sanalista
-muuttujan vanhan arvon viittauksella uuteen, pidempään listaan. Samasta ajatuksesta voi olla hyötyä myösStack
-luokkaa toteuttaessasi.