- CS-A1110
- Kierros 10
- Luku 10.3: Kamppailevia robotteja
Luku 10.3: Kamppailevia robotteja
Johdanto
Tässä luvussa jatketaan aiempaa 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:
1move # liiku yksi ruutu eteenpäin
2spin # käänny myötäpäivään
3goto 1 # siirry riville 1
RobotTribes-moduulin 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ä 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-oheismoduuli. Tutuksi tulleeseen tapaan ohjelmasta on annettu lähes toimintakuntoinen versio, jossa on kuitenkin ratkaisevia puutteita. Luku sisältää monivaiheisen ohjelmointitehtävän, jossa pääset korjaamaan nämä puutteet.
Aloitetaan yleiskuvalla RobotTribes-ohjelmasta.
RobotTribes-moduuli
Robots-moduulista
RobotTribes on rakennettu lukujen 8.2, 8.3 ja 9.1 Robots-moduulin varaan. Jos tuo 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 |
Robots-moduulin luokan |
annettu puutteellisena |
luokka |
Kuvaa robottiheimoja. Kukin |
valmis |
piirreluokka
|
Kuvaa yksittäisiä RoboSpeak-ohjelman käskyjä.
Kullakin näistä on |
valmis |
luokka |
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. Vastaa sen mukaan, miten annettu koodi toimii; älä huomioi mahdollisuutta että toimiva robotti itse saattaa tulla "häkätyksi" ja vaihtaa heimoa.
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.Kirjoita metodiin jo myös asiaankuuluva
hack
-metodin kutsu. Se ei tosin vielä tee mitään, koska tuon metodin toteutus on tyhjä.
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 moduulin sisältä.Robotit liikkuvat mutta eivät vielä hyökkää toisten heimojen kimppuun. (Valmiista heimoista Patroller-heimo ei myöskään liiku oikein, koska aliohjelmakutsuja ei ole vielä toteutettu.)
Kokeile itse luoda pikkuinen RoboSpeak-koodinpätkä:
Kirjoita joitakin RoboSpeak-käskyjä (esim. move, spin, uturn, goto)
mytribe.tribe
-nimiseen tiedostoontribes
-kansioon.Jos haluat valita robotille kuvan, sijoita samaan kansioon myös vastaava PNG-kuvatiedosto nimellä
mytribe.png
. Joitakin valmiita kuvavaihtoehtoja löytyyextra_pics
-alikansiosta, mutta muitakin saa käyttää.
Palauta ratkaisusi ennen kuin jatkat seuraaviin vaiheisiin.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Vaihe 4/9: Lisää toiminnallisuutta
Jos et ole vielä lukenut
Tribe
-luokan Scaladocista kappaleita 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
. Kuitenkaan kaikillaRobotBrain
eillä ei oletribe
-muuttujaa.Metodin voi toteuttaa esimerkiksi
match
-käskyllä, joka tutkii parametrin dynaamista tyyppiä; vrt. luku 7.3.
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.
Täydennä metodi
talk
Käytä samaan luokkaan valmiiksi toteutettuja metodeita, niin tästä metodista tulee hyvin yksinkertainen.
Toteuta
longRadar
.Mitä luvun 6.3 kokoelmametodeista voit kutsua tuottaaksesi yksinkertaisen toteutuksen tälle? (Kunhan ensin pyydät robottimaailmalta luettelon kaikista sen sisältämistä roboteista.)
Toteuta
directedRadar
.Sen voi toteuttaa esimerkiksi suodattamalla
shortRadar
in palauttamia robotteja niin, että vain sopivat jäävät.
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.Palauta ohjelmasi ja jatka sitten tehtävän seuraaviin vaiheisiin.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Vaihe 6/9: Aliohjelmakutsut: pohjustus
RoboSpeak-käskyt callsub ja return eivät vielä toimi, mutta pian pääset korjaamaan
asian. Tutustu aiheeseen lukemalla Tribe
-luokan Scaladoc-dokumentaatiosta
kohta Subprograms ja vastaa sitten seuraaviin heimontulkintakysymyksiin.
Jotta saat metodit toteutettua, on tarpeen lisätä kullekin heimorobotille oma kutsupino. Kutsupinossa robotti pitää kirjaa siitä, mitkä aliohjelmakutsut ovat käynnissä ja mihin kohtaan kustakin kutsusta palataan.
TribalBots-moduulissa 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: Johdanto Stack
-luokkaan
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.
Tutustu Scalan Stack
-luokkaan lukemalla seuraava esimerkki. Voit tietysti myös
kokeilla REPLissä itse.
import scala.collection.mutable.Stackval sanapino = Stack[String]()sanapino: Stack[String] = Stack() sanapino.push("eka")res0: Stack[String] = Stack(eka) sanapino.push("toka")res1: Stack[String] = Stack(toka, eka) sanapino.push("kolmas")res2: Stack[String] = Stack(kolmas, toka, eka) sanapino.pop()res3: String = kolmas sanapino.pop()res4: String = toka sanapino.push("neljäs")res5: Stack[String] = Stack(neljäs, eka) sanapino.pop()res6: String = neljäs sanapino.pop()res7: String = eka sanapino.pop()java.util.NoSuchElementException: empty collection ... sanapino.isEmptyres8: Boolean = true
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 Patroller-heimolla tai jollakin itse laatimallasi RoboSpeak-ohjelmalla.
Vaihe 9/9: Loppu
Pohdi, mitä yhteistä on RobotTribes-ohjelmalla ja virtuaalikoneilla (luku 5.4). Voit myös pohtia, millä tavoin RoboSpeak muistuttaa konekieliä. Selvitä internetistä vaikkapa, millaisia hyppykäskyjä konekielissä on.
Palauta ratkaisusi.
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.
Hankalia lisätehtäviä robottiheimoista
Tutustu
Tribe.scala
-tiedoston sisältöön. Selvitä, millaisen käsitehierarkian sinne kirjatutInstruction
-tyypin alatyypit muodostavat.Tutustu
RoboSpeakGrammar
-tiedoston sisältöön. Selvitä, miten RoboSpeak-rivien jäsentäminen toimii. Apuna voit käyttää Scala Parser Combinators -kirjaston dokumentaatiota (jonka esimerkit on harmi kyllä toistaiseksi kirjoitettu Scala 2:lla).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!
Materiaalin luvut tehtävineen ja viikkokoosteineen on laatinut Juha Sorva.
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: (aakkosjärjestyksessä) Riku Autio, Nikolas Drosdek, Kaisa Ek, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Onni Komulainen, Niklas Kröger, Kalle Laitinen, Teemu Lehtinen, Mikael Lenander, Ilona Ma, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, Joel Toppinen, Anna Valldeoriola Cardó ja Aleksi Vartiainen.
Lukujen alkuja koristavat kuvat ja muut vastaavat kuvituskuvat on piirtänyt Christina Lassheikki.
Yksityiskohtaiset animaatiot Scala-ohjelmien suorituksen vaiheista suunnittelivat Juha Sorva ja Teemu Sirkiä. Teemu Sirkiä ja Riku Autio toteuttivat ne apunaan Teemun aiemmin rakentamat työkalut Jsvee ja Kelmu.
Muut diagrammit ja materiaaliin upotetut vuorovaikutteiset esitykset laati Juha Sorva.
O1Library-ohjelmakirjaston ovat kehittäneet Aleksi Lukkarinen, Juha Sorva ja Jaakko Nakaza. Useat sen keskeisistä osista tukeutuvat Aleksin SMCL-kirjastoon.
Tapa, jolla 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+ luotiin alun perin Aallon LeTech-tutkimusryhmässä pitkälti opiskelijavoimin. Nykyään tätä avoimen lähdekoodin projektia kehittää Tietotekniikan laitoksen opetusteknologiatiimi ja tarjoaa palveluna laitoksen IT-tuki; sitä ovat kehittäneet kymmenet Aallon opiskelijat ja muut.
A+ Courses -lisäosa, joka tukee A+:aa ja O1-kurssia IntelliJ-ohjelmointiympäristössä, on toinen avoin projekti. Sen suunnitteluun ja toteutukseen on osallistunut useita opiskelijoita yhteistyössä O1-kurssin opettajien kanssa.
Kurssin tämänhetkinen henkilökunta löytyy luvusta 1.1.
Lisäkiitokset tähän lukuun
Luvussa käytetty ajatus ruudukolla keskenään taistelevista ohjelmoitavista "lajeista" on pummittu Nick Parlanten suunnittelemasta evoluutioharjoitustehtävästä.
Onni Miettinen, Niklas Koskela, Viljami Nurminen ja Rune Pönni laativat RoboSpeakiin lisäkäskyjä ja muutenkin paransivat tehtävää mm. opiskelijapalautteen perusteella.