C++-harjoitustyön raportti: Musta maija Eino Malinen (67203) metmal@utu.fi Tietojenkäsittelytieteet Turun yliopisto Palautus: 22.1.2007 Osallistunut kursille: syksy 2006
Sisällysluettelo Kuvaus ongelman ratkaisusta...3 Käytetyt luokat ja niiden jäsenet...4 Pelaaja...4 Ihmispelaaja...5 AIPelaaja...5 Pelipoyta...6 Kortti...7 Käännöskomento ja käyttöohje...8 Käännös...8 Pelin aloittaminen...8 Haasteen asettaminen...8 Haasteeseen vastaaminen...9 Nostopakan koko ja pelin loppuminen...10 Koeajot...11 Näppäimistösyöttö...11 Haasteen ja vastauksen käsittely...12 Pelin loppuminen...14 Pohdintaa...15 2/15
Kuvaus ongelman ratkaisusta Musta maija -korttipelin ohjelmallinen toteutus koostuu luokista ja peliä suorittavasta osasta, joka käyttää luokkia. Peliä suorittava osa alustaa aluksi pelin, jonka jälkeen se aloittaa suorituksen. Peliä suoritetaan haasteina ja vastauksina (ks. kuva 1). Vuorossa oleva pelaaja antaa haasteen eli sijoittaa pelipöydälle kortteja kaadettavaksi. Viereinen pelaaja antaa vastauksen haasteeseen eli pyrkii kaatamaan pöydällä olevia kortteja. Kuva 1. Musta maija -pelin eteneminen. Musta maija -pelistä on abstrahoitu pelaaja, pelipöytä ja kortti. Näihin abstraktioihin päädyttiin selvittämällä sellaiset tietotyypit, jotka ovat itsenäisiä verrattuna muihin tietotyyppeihin. Pelin suunnitteluvaiheessa mukana oli lisäksi nostopakka, mutta toteutusvaiheessa kyseinen tyyppi siirtyi pelipöydän ominaisuudeksi. 3/15
Käytetyt luokat ja niiden jäsenet Pelissä on viisi luokkaa (ks. kuva 2), jotka noudattelevat suunnitteluvaiheen tietoabstraktioita identtisesti. Pelaaja-luokka on lisäksi jakaantunut ihmispelaajaksi (Ihmispelaaja) ja tietokonepelaajaksi (AIPelaaja). Kuva 2. Musta maija -pelin luokat. Pelaaja Pelaaja-luokka (ks. kuva 3) edustaa pelaajaa, jolla on kädessään kortteja. Pelin toteutuksessa Pelaaja-luokka on abstrakti luokka annakortit()-metodin kautta, jolloin siitä ei voi luoda olioita. Luokan kaikki muut piirteet, annakortit()-metodia lukuunottamatta on toteutettu. Luokka käyttää asiakassuhdetta Kortti-luokkaan nähden. Pelaaja-luokalla on vektorimuuttuja kortit_ ja merkkijonotyyppinen muuttuja nimi_. Näistä ensimmäisessä säilytetään käsikortteja osoituksina Kortti-luokan olioihin. Jälkimmäinen kertoo pelaajan nimen. Molemmat muuttujat ovat tyypiltään suojattuja. Luokan konstruktori ottaa vastaan merkkijonotyyppisen muuttujan, jonka se tallettaa nimi_- muuttujaan. Kuva 3. Pelaaja-luokan jäsenet. 4/15
Pelaaja-luokan muut metodit jakaantuvat pyyntö-, tulostus- ja sijoitusmetodeihin. Pyyntömetodeja ovat korttienmaara(), joka palauttaa käsikorttien määrän, sekä annanimi(), joka palauttaa pelaajan nimen. Näiden lisäksi metodilla annakortit() pyydetään pelaajalta kortteja joko haasteeseen tai vastaukseen, ja se ottaa parametreina boolean-tyyppisen tiedon haasteesta, pelissä käytettävän valttimaan sekä vastausta varten haastekortit. Metodi annakortit() palauttaa vektorina kortit haasteeseen tai vastaukseen. Ainoa tulostusmetodi on naytakortit(), joka tulostaa kasikortit ruudulle, ja sen parametrina välitetään tieto valttimaasta, jota tarvitaan tulostuksessa. Sijoitusmetodilla lisaakortit() pelaajan käsikortteihiin lisätään metodin parametrina annetut kortit. Ihmispelaaja Ihmispelaaja-luokka (ks. kuva 4) perii Pelaaja-luokasta antaen samalla toteutuksen annakortit()-metodille. Tämän piirteen lisäksi luokassa on ainoastaan konstruktori, joka ottaa vastaan merkkijonon, jonka se sijoittaa yläluokan nimi_-muuttujaan. Metodin annakortit() toteutuksessa tulostetaan tekstiä ja luetaan näppäimistöltä. Kuva 4. Ihmispelaaja-luokan jäsenet. Kuva 5. AIPelaaja-luokan jäsenet. AIPelaaja AIPelaaja-luokka (ks. kuva 5) perii Pelaaja-luokasta antaen toteutuksen annakortit()- metodille. Toteutettu tietokonepelaaja on hyvin yksinkertainen. Haasteeseen arvotaan maata, jota on on tietokonepelaajan käsikorteissa. Haasteeseen annettavaan vastaukseen selvitetään käsikorteissa olevat haastemaata sekä valtteja vastaavat kortit. Tämän jälkeen tietokonepelaaja valitsee haastemaata vastaavista korteista ne, jotka pystyvät kaatamaan haastekortit. Lopuksi valteilla paikataan ylijääneitä haastekortteja. Muut piirteet ovat yhteneväisiä Ihmispelaaja-luokan kanssa. 5/15
Pelipoyta Pelipoyta-luokka (ks. kuva 6) edustaa musta maija -pelissä pöytää, jossa on nostopakka sekä haaste- ja vastauskortit. Lisäksi pöydällä ovat pelaajat. Pöytä käyttää asiakassuhdetta Korttiluokkaan ja Pelaaja-luokkiin nähden. Konstruktorissa luodaan kortit ja sekoitettu nostopakka. Destruktorissa tuhotaan muuttujien sisältö keosta. Pelipoyta-luokan yksityisiä muuttujia ovat osoittimia sisältävät vektorit haastekortit_, nostopakka_ ja pelaajat_. Lisäksi sillä on Kortti-tyyppinen osoitin valtti_, jota käytetään pelissä valttimaan merkkinä. Luokassa on kuusi pyyntömetodia. Metodi annavaltti() palauttaa valtti_-muuttujan. Metodi annapelaaja() palauttaa parametrina olevaa kokonaislukua vastaavan pelaajan kohdan pelaajat_-muuttujasta. Metodit montanostokorttia() ja montahaastekorttia() palauttavat vastaavasti nostopakan koon ja haastekorttien määrän. Metodi annahaastekortit() palauttaa pöydällä olevat haastekortit. Lopuksi jaakortteja()-metodi palauttaa nostopakasta parametrina annetun määrän kortteja. Lisäysmetodeja on kaksi. Metodi lisaapelaaja() saa parametrina osoituksen pelipöydälle lisättävään Pelaaja-olioon. Metodi haaste() lisää pöydälle haastekortit. Kuva 7. Kortti-luokan jäsenet. Kuva 6. Pelipoyta-luokan jäsenet. Luokassa on myös metodi vastaus(), jonka parametrina on haasteeseen annettavat vastauskortit. Metodi tarkistaa vastauksen ja palauttaa Kortti-vektorin, jossa on epäonnistuneet vastauskortit ja niitä vastaavat haastekortit. 6/15
Kortti Kortti-luokka (ks. kuva 7) edustaa yhtä pelikorttia ja sillä on kolme yksityistä muuttujaa. Muuttuja maa_ on yksi luetellun tyypin Maa muuttujista: HERTTA, RUUTU, RISTI, PATA, VAPAA. Kokonaislukutyyppisistä muuttujista nro_ ilmaisee kortissa olevan numeron yhdestä kolmeentoista ja arvo_ ilmaisee kortin pelissä olevan arvon. Ässät ovat arvoltaan neljätoista ja musta maija (PATA 12) on arvoltaan sata. Luokan konstruktori saa parametreina arvot kaikille kortin muuttujille. Oletusparametrit luovat Maatyyppiä VAPAA olevan kortin, jonka muuttujat nro_ ja arvo_ ovat arvoltaan miinus yksi. Muut luokan metodit ovat kaikkien muuttujien arvojen palautukseen. Tiedostossa Kortti.h on toteutettu luokan lisäksi aiemmin mainittu lueteltu tyyppi Maa ja korttien arvon vertailuun tarvittava vertaakortteja()-metodi, joka saa syötteeksi kaksi Kortti-oliota. Vertailua käytetään ohjelmassa sort()-metodin parametrina. 7/15
Käännöskomento ja käyttöohje Musta maija -peli on toteutettu C++-kielellä ja siinä on käytetty ainoastaan standardikirjastoa. Ohjelmointiympäristönä oli GNU/Linux, mutta käännös pitäisi onnistua myös muissa käyttöjärjestelmissä. Käännös Ohjelma kääntyy ainakin Free Software Foundationin GCC-julkaisuun kuuluvalla g++-kääntäjällä. Ohjelman lähdekoodi sijaitsee kansiossa src. Käännös tapahtuu kirjoittamalla konsoliin: g++ -ansi -pedantic -Wall -c *.cpp ja tämän jälkeen: g++ -ansi -pedantic -Wall *.o -o mustamaija Pelin aloittaminen Ohjelma käynnistetään komennolla:./mustamaija Käynnistyksen jälkeen ruutuun tulee valikko, josta valitaan halutut pelaajat: ------------------------------- Tervetuloa musta maija -peliin! ------------------------------- ------------------------------- Valitse pelaajat: 1) Ihminen vs. ihminen 2) Ihminen vs. tietokone ------------------------------- >>> Valintasi: Haasteen asettaminen Peli vuorottelee haasteiden ja haasteisiin annettavien vastausten välillä. Jos vuorossa olevan pelaajan pitää antaa haaste, ohjelma tulostaa ruudulle: 8/15
---------------KASIKORTIT-------------- a: HERTTA 2 b: RUUTU 10 c: RISTI 6* d: RISTI 12* e: PATA 13 --------------------------------------- >>> Ihmispelaaja 1, anna haastekortti (lopettaaksesi valitse 0): Haastekortit valitaan yksi kerrallaan kirjoittamalla kortin vieressä oleva kirjain. Huomaa lisäksi, että valttikortit on merkitty tähdellä. Valitut kortit tulevat näkyviin: -------------HAASTEKORTIT------------- HERTTA 2 --------------------------------------- ---------------KASIKORTIT-------------- a: RUUTU 10 b: RISTI 6* c: RISTI 12* d: PATA 13 --------------------------------------- >>> Ihmispelaaja 1, anna haastekortti (lopettaaksesi valitse 0): Haastekorttien lisäämistä jatketaan niin kauan kunnes valitaan numero 0. Valittuihin haastekortteihin ei voi lisätä haastemaasta poikkeavaa. Jos pelaaja ei valitse yhtään haastekorttia ennen lopetusta, siirtyy vuoro suoraan seuraavalle pelaajalle. Haasteeseen vastaaminen Jos olet vastaamassa haasteeseen, ohjelma tulostaa ruudulle: 9/15
--------------HAASTEKORTIT------------- 1: HERTTA 2 --------------------------------------- ---------------KASIKORTIT-------------- a: RUUTU 6 b: HERTTA 11 c: PATA 4 d: HERTTA 1 e: PATA 6 --------------------------------------- >>> Ihmispelaaja 2, minka kortin haastat (lopettaaksesi valitse 0): Pelaaja valitsee ensin haastettavan kortin kirjoittamalla haastekortin vieressä olevan numeron tai valitsemalla numeron nolla. Jos yhtään korttia ei ole haastettu, haastekortit lisätään vastaavalle pelaajalle ja vuoro säilyy haastajalla. Kun pelaaja on valinnut haastekortin, ohjelma tulostaa: >>> Milla kortilla haluat vastata (lopettaaksesi valitse 0): Tällöin käsikorteista valitaan kortti kirjoittamalla sen vieressä olevan kirjain tai valitsemalla numeron 0, jolloin ohjelma palaa takaisin kysymään haastettavaa korttia. Vastauskortin pitää olla samaa maata kuin haaste tai valtti. Pelaaja ei voi lyödä mustalla maijalla (PATA 12). Kun vastauskortit on valittu, valitaan numero 0, jonka jälkeen ohjelma tarkistaa kaadot. Jos haasteeseen vastaa tietokonepelaaja, tulostuu ruudulle tietokoneen vastaus haastekortteihin: ----TIETOKONEEN VASTAUS HAASTEESEEN---- RISTI 4 <- RISTI 9 --------------------------------------- Nostopakan koko ja pelin loppuminen Ohjelma tulostaa ihmispelaajan ruudulle ennen haasteen tai vastauksen antamista nostopakan koon: >>> NOSTOPAKKA: 40 KORTTIA <<< Peli loppuu kunnes nostopakka on tyhjä ja jommankumman pelaajan käsikortit ovat loppuneet. Tällöin ruudulle tulostuu: >>> Pelin voitti Tietokonepelaaja. Pelin voi lopettaa kesken painamalla yhtäaikaa CTRL ja C. 10/15
Koeajot Koeajoissa testattiin näppäimistösyöttöä, haasteen ja vastauksen käsittelyä sekä pelin loppumista. Koeajon aikana havaitut virheet korjattiin ja koeajo suoritettiin uudelleen, mutta tekstissä käytetään ainoastaan onnistuneiden ajojen tuloksia. Näppäimistösyöttö Näppäimistösyöttöä testattiin kaikissa syöttöä vaadittavissa kohdissa. Näitä olivat pelaajien valinta sekä ihmispelaajan haasteen ja vastauksen asettaminen. Yhteensä ohjelmassa suoritetaan näppäimistön lukuoperaatioita neljässä eri kohdassa. Testauksessa syötteeksi annetaan virheellinen syöte. Jos kysytty syöte on kirjain, annetaan numero ja päinvastoin. Lisäksi syöte voi olla valintamahdollisuuksien ulkopuolella, kuten jos valittavana on kirjaimet a:sta c:hen, annettaan syötteeksi d. Kuva 8. Näppäimistösyötteen testaamista. Pelaajan valinnassa syötteeksi vaaditaan numeroa 1 tai 2. Testauksessa syötteeksi annetaan kirjain a ja numero 3, joita kumpaakaan ohjelma ei hyväksy. Numeron 1 tai 2 valinta jatkaa ohjelma 11/15
suoritusta varsinaiseen peliin. Haasteen valinnassa oikea syöte on kirjaimet alkaen a:sta tai numero 0. Testauksessa syötteeksi annetaan viimeistä valintaa seuraava kirjain f ja numero 1, joita ohjelma ei hyväksy. Peli jatkuu kunnes annetaan syöte a:sta e:hen tai numero 0. Haasteelle annettavan vastauksen koostuu kahdesta näppäimistösyötteestä. Ensin valitaan haastettava kortti, jota vastaa syötettä numerosta 1 alkaen. Testisyötteeksi annetaan kirjain a ja numero 2. Ohjelma ei hyväksy syötteitä ennen kuin annetaan oikea syöte. Koeajoissa virheellinen syöte tunnistettiin, ja ohjelma pyysi käyttäjää yrittämään uudelleen. Ohjelma jatkaa kunnes annetaan oikea syöte. Haasteen ja vastauksen käsittely Haasteen ja vastauksen käsittely testattiin kahden ihmispelaajan sekä ihmispelaajan ja tietokonepelaajan pelatessa. Testaus koski haasteen vastaanoton sekä haasteeseen annettavan vastauksen onnistumista. Lisäksi testattiin mustan maijan (PATA 12) käsittelyä. Kuva 9. Haasteen antaminen. 12/15
Kahden ihmispelaajan haasteen käsittelyssä testattiin syötteen onnistumista. Ensimmäinen pelaaja antaa haasteeksi yhden kortin (RISTI 11), jonka jälkeen valitaan numero 0. Toiselle pelaajalle annetaan vastausvuoro. Haastekortti tulostuu toiselle pelaajalle ja korttiin voidaan antaa vastaus. Haasteen antamisessa testattiin myös virheellisen maakortin antamista. Haasteeseen oli sijoitettu jo yksi kortti (PATA 6), jonka jälkeen yritettiin lisätä muita maita (RISTI 6*, RUUTU 8). Ohjelma tunnisti virheellisen sijoituksen. Kahden pelaajan haasteeseen annettavan vastauksen käsittelyssä vastauksen annettiin samaa maata oleva (RUUTU 7 RUUTU 11) sekä toisessa testissä valttikortti (PATA 7 RUUTU 4*). Ohjelma hyväksyi molemmat vastaukset. Ihmispelaajan ja tietokonepelaajan pelatessa tietokonepelaajalle annettiin haastekortti. Tietokonepelaaja pystyi antamaan vastauksen haasteeseen. Lisäksi tietokonepelaaja jatkoi antamalla ihmispelaajalle haastekortin (ks. kuva 10). Kuva 10. Tietokonepelaaja vastaa haasteeseen ja antaa oman haasteensa. Mustan maijan (PATA 12) käsittelyä testattiin yrittämällä antaa se vastaukseksi haasteeseen tai yrittämällä kaataa musta maija. Ohjelma tunnisti molemmat tilanteet virheellisiksi ja pyysi yrittämään uudelleen. 13/15
Kaikissa koeajoissa haaste ja vastaus tunnistettiin onnistuneesti. Pelin loppuminen Pelin loppumista testattiin sekä kahdella ihmispelaajalla että ihmispelaajalla ja tietokoneella. Kahden ihmispelaajan peli loppui onnistuneesti. Ihmispelaajan ja tietokonepelaajan testaus suoritettiin siten, että molemmat saivat voittaa. Tietokoneen annettiin voittaa ottamalla kaikki tietokoneen haastekortit, jolloin lopussa kädessä oli 48 korttia, haasteessa 3 ja valttina yksi kortti eli yhteensä 52 korttia. Ihmispelaaja voitti tietokoneen pelaajan myös onnistuneesti. Kuva 11. Ihmispelaaja voittaa pelin. 14/15
Pohdintaa Jotkut luokkien metodit lukevat näppäimistöltä ja tulostavat sivuvaikutuksena ruudulle. Tämä ei ole hyvän ohjelmointitavan mukaista, sillä lähdekoodin uudelleenkäytettävyys kärsii. Jos pelin haluaisi nyt toteuttaa graafisella käyttöliittymällä, olisi metodit muokattava. Pelin malli, tietosisältö ja sen käyttöliittymä on hyvä erottaa toisistaan. Ohjelman tekstipohjaista käyttöliittymää ei ole myöskään helppo laajentaa. Mahdollisia lisättäviä piirteitä voisivat olla pelin lopettaminen kesken muutoin kuin painamalla CTRL ja C. Peli voisi myös arpoa aloittavan pelaajan. Lisäksi virheellisten korttisijoitusten peruuttamiseen pitäisi olla mahdollisuus. 15/15