Tämä kurssi on jo päättynyt.

Kurssin viimeisimmän version löydät täältä: O1: 2024

Luku 11.2: 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ä, viisi, kuusi tuntia? Omaa koodattavaa on melko vähän, mutta kokonaisuuteen perehtyminen vie aikaa.

Pistearvo: C115.

Oheismoduulit: RobotTribes (uusi), joka tarvitsee myös Robots-moduulin.

../_images/person07.png

Johdanto

../_images/robottribes.png

Kaksi robottiheimoa kamppailevat. "Vartijat" ovat muodostaneet tiiviin ryhmän. "Tiikerit" etsivät saalista.

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-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ä 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-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.1, 8.2 ja 8.3 Robots-moduulin varaan. 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ö laajentaa o1.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-moduulin 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. (Apunaan se käyttää RoboSpeakGrammar-luokkaa.) 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 Instructionin alikäsitteinä; näitä konkreettisia luokkia ei tarvitse tässä tehtävässä tuntea tarkemmin. valmis
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

  1. 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.
  2. Vastaa seuraaviin kysymyksiin. Valitse kussakin kohdassa ne vaihtoehdot, jotka vastaavat kyseisen RoboSpeak-ohjelman kuvaaman heimon toimintaa.
1
2
spin
goto 1
1
2
3
4
5
6
7
8
iffriend 7
ifwall 5
move
goto 1
spin
goto 1
spin
goto 7
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
start:
  ifnempty turn
  move
  goto start

turn:
  ifrandom noswitch
  switch
noswitch:
  spin
  goto start

Vaihe 2/9: heimot liikkeelle

  1. Tutustu huolellisesti TribalBot-luokan dokumentaatioon ja ohjelmakoodiin sekä piirreluokan Instruction dokumentaatioon.
  2. Toteuta puuttuvista osista tässä vaiheessa moveBody-metodi.
    • Käytä apuna TribalBot-luokan nextInstruction-muuttujaa.
    • Huomaa hyödyntää Instruction-olion execute-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ä.

Vaihe 3/9: testaillaan

Nyt on käypä aika kokeilla RoboSpeak-ohjelmia käytännössä.

  1. 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ä.
    • 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.)
  2. Kokeile itse luoda pikkuinen RoboSpeak-koodinpätkä:
    • Kirjoita joitakin RoboSpeak-käskyjä (esim. move, spin, uturn, goto) tribe-päätteiseen tiedostoon tribes-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ää.

Vaihe 4/9: Lisää toiminnallisuutta

  1. Jos et ole vielä lukenut Tribe-luokan Scaladocista kappaleita Using Memory Slots, Radar Commands ja Hacking and Talking, niin lue ne nyt.
  2. Toteuta TribalBot-luokkaan metodi determineTribe. Luokan muut metodit tarvitsevat sitä pystyäkseen erottamaan vihollisen ystävästä.
    • Huomaa, että parametrina voi olla mikä tahansa RobotBrain mutta kaikilla RobotBraineillä ei ole tribe-muuttujaa.
    • Metodin voi toteuttaa esimerkiksi match-käskyllä, joka tutkii parametrin dynaamista tyyppiä; vrt. luku 7.2.
  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.
  4. Täydennä metodi talk
    • Käytä samaan luokkaan valmiiksi toteutettuja metodeita, niin toteutuksesta tulee hyvin yksinkertainen.
  5. Toteuta longRadar.
    • Millä luvun 6.3 kokoelmametodeista tuo metodi on hyvin helppo toteuttaa, kunhan ensin pyydät robottimaailmalta luettelon kaikista sen sisältämistä roboteista?
  6. Toteuta directedRadar.
    • Sen voi toteuttaa esimerkiksi suodattamalla shortRadarin 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

  1. Toteuta hack-metodi. Käytä taas apuna muita TribalBot-luokasta löytyviä metodeita.
  2. 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.
  3. 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 ensin aiheeseen lukemalla Tribe-luokan Scaladoc-dokumentaatiosta kohta Subprograms ja vastaa alla oleviin heimontulkintakysymyksiin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
set hackline 4
callsub 8
goto 2
switch
set hackline 1
callsub 8
goto 6
move
spin
return
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
label1:
  callsub check
  goto mem
  move
  ifrandom 7
  spin
  goto label1
  ifwall label2
  iffriend label2
  move
  goto label1

label2:
  spin
  goto label2

check:
  score
  iflt radar -3 22
  set mem 4
  return
  set mem 8
  return

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-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 kokeille REPLissä itse.

import scala.collection.mutable.Stackimport scala.collection.mutable.Stack
val sanapino = new 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 Patrolman-heimolla tai jollakin itse laatimallasi RoboSpeak-ohjelmalla.

Vaihe 9/9: loppu

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

Haastavia lisätehtäviä robottiheimoista

  1. Tutustu Tribe.scala-tiedoson sisältöön. Selvitä, millaisen käsitehierarkian sinne kirjatut Instruction-tyypin alatyypit muodostavat.
  2. Tutustu RoboSpeakGrammar-tiedoston sisältöön. Selvitä, miten RoboSpeak-rivien jäsentäminen toimii. Apuna voit käyttää Kirjoja ja linkkejä -sivullakin mainittua kirjaa Programming in Scala, Third Edition ja erityisesti sen lukua 33, Combinator Parsing.
  3. Ideoi ja toteuta jokin oma uusi käsky RoboSpeakiin. Lisää käskysi RoboSpeakin kielioppiin ja kirjoita sitä kuvaava Instruction-alatyyppi.
  4. 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, Joonatan Honkamaa, Jaakko Kantojärvi, Niklas Kröger, Teemu Lehtinen, Strasdosky Otewa, 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 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 ja Juha Sorva. 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. Pääkehittäjänä on tällä hetkellä Markku Riekkinen, jonka lisäksi A+:aa 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 ovat luoneet Nikolai Denissov, Olli Kiljunen ja Nikolas Drosdek yhteistyössä Juha Sorvan, Otto Seppälän, Arto Hellaksen ja muiden 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ä.

Viljami Nurminen ja Rune Pönni kehittivät RoboSpeakiin lisäkäskyjä opiskelijapalautteen perusteella.

a drop of ink
Palautusta lähetetään...