(H) Korttien siirtelyä¶
Tavoite: Opin dynaamista muistinhallintaa ja osoittimien käsittelemistä.
Ohjeita:
Hae ohjelmakoodipohja: templates/09/cards/
-> student/09/cards/
.
Attention
Voit palauttaa tehtävän, vaikka et olisi saanut kaikkia
metodeja toteutettua.
Osapisteitä saa, jos toteutettuna on vähintään metodit
add
ja remove
.
Jotta läpäiset automaattitestit, sinun täytyy kuitenkin toteuttaa tyhjät
dummy-toteutukset kaikille metodeille.
Tämä onnistuu Qt Creatorissa helposti, kun klikkaat hiiren oikealla
näppäimellä metodin nimeä luokan .hh
-tiedostossa ja tutkit
valikon “Refactor” sisältöä.
Eräässä korttipelissä kortteja siirrellään korttipinoon ja pois pinosta tiettyjen sääntöjen mukaan. Toteutetaan luokka, joka antaa siirrellä kortteja pinossa vain pelin sääntöjen mukaisesti ja mahdollistaa pinon sisällön tulostamisen. Yksinkertaistetaan tehtävää siten, että kortit on numeroitu, ja jokaiseen korttiin viitataan sen numerolla, niin voimme keskittyä itse tietorakenteeseen ilman syötteenkäsittelyn yksityiskohtia.
Toteutamme siis tietorakenteen, johon voi tallentaa kokonaislukuja.
Tiedostoon cards.hh
on määritelty toteutettavan luokan rajapinta,
jota ei saa muuttaa.
Tämä tarkoittaa, että luokan julkista osaa ei saa muuttaa, mutta luokan
yksityisiä metodeja ja jäsenmuuttujia saa halutessaan muokata.
Koska harjoittelemme dynaamista muistinhallintaa, tehtävänäsi on toteuttaa
luokka ilman, että käytät STL:n säiliöitä, string
-tyyppiä tai
C++:n taulukkoa.
Säännöt¶
Korttipino on aluksi tyhjä. Kortteja voi siirtää neljällä eri tavalla:
- Korttipinon päällimmäiseksi voi lisätä uuden kortin, jonka numero välitetään lisäysoperaatiolle parametrina.
- Korttipinosta voi poistaa päällimmäisen kortin.
Tämän päällimmäisen kortin numero välitetään metodista kutsujalle
(viiteparametrissa
id
). - Korttipinon alimmaisen kortin voi siirtää päällimmäiseksi.
- Korttipinon päällimmäisen kortin voi siirtää pinon alimmaiseksi.
Jokaiselle edellä mainitulle toimenpiteelle toteutetaan oma metodinsa, joka on määritelty luokan rajapintaan valmiiksi.
Lisäksi testaamisen helpottamiseksi on määritelty metodi korttipinon
tulostamista varten (print_from_top_to_bottom
).
Kaikkein innokkaimmilla on lisäksi mahdollisuus joko harjoitella
enemmän osoittimien käsittelemistä tai kerrata rekursiota toteuttamalla
toinen, hiukan haastavampi tulostusmetodi (print_from_bottom_to_top
).
Luokan testaaminen¶
Luokalle on toteutettu yksinkertainen testaus tiedostossa main.cpp
.
Alla on esimerkki siitä, miten luokan pitää toimia annetulla
testipääohjelmalla:
constructor
Enter amount of test cards: 5
print_from_top_to_bottom (deck is empty)
add * n
print_from_top_to_bottom
1: 4
2: 3
3: 2
4: 1
5: 0
bottom_to_top * 2
print_from_top_to_bottom
1: 1
2: 0
3: 4
4: 3
5: 2
top_to_bottom * 1
print_from_top_to_bottom
1: 0
2: 4
3: 3
4: 2
5: 1
print_from_bottom_to_top
1: 1
2: 2
3: 3
4: 4
5: 0
remove 0
remove 4
remove 3
remove 2
remove 1
destructor
Valmiiksi toteutettu testaus ei ole kattava, mutta pääset sen avulla alkuun. Saat vapaasti muokata testipääohjelmaa, ja kattavampi testaaminen auttaa ohjelman toteuttamisessa. Automaattitarkastus testaa toteuttamasi luokan toimintaa ilman pääohjelmaa, eli tarkastin ei välitä siitä, mitä omassa testipääohjelmassasi tehdään. Kannattaa kuitenkin ehkä pitää osa alkuperäisistä testeistä tallella, että voit vertailla niidenkin tulosteita yllä olevaan mallitulosteeseen.
Vinkkejä tehtävän tekemiseen:
- Tutustu ensimmäiseksi valmiina annettuun pääohjelmaan.
- Toteuta aluksi vain kaksi välttämättömintä metodia (toinen
muokkaa korttipinoa ja toinen, jonka avulla lopputulosta testataan)
ja kommentoi testipääohjelmasta pois kaikkien muiden metodien kutsut.
Tässä tarkoituksessa useamman rivin kommentti
/* tämä osa on kommentoitu pois */
on kätevä. - Muista jokaista operaatiota toteuttaessasi miettiä, mitä kaikkia tapauksia linkitetyn tietorakenteen käsittelemisessä pitää ottaa huomioon (edellisen materiaaliosion yhteenveto).
- Jos haluat harjoitella enemmän eli päätät toteuttaa metodin
print_from_bottom_to_top
, sinulla on valittavanasi useita erilaisia toteutustapoja:- Rekursio: Tämän saa toteutettua varsin pienellä vaivalla ja rekursion
kertaaminen on hyvä, mutta et opi mitään uutta osoittimista.
Aloita miettimällä, miten listan voi nähdä rekursiivisena
tietorakenteena, eli miten sen saa jaettua samanmuotoiseksi,
mutta pienemmäksi osaongelmaksi.
Huomaa, että luokan yksityisessä rajapinnassa on valmiiksi
määritelty apufunktio (
recursive_print
), jonka on tarkoitus rekursiivisesti kutsua itseään. - Kahteen suuntaan linkitetty lista: Tässä saat harjoitella
enemmän osoittimien käsittelyä, mutta tämä vaatii enemmän vaivaa
kuin rekursiivinen ratkaisu.
Idea on, että toteutat
Card_data
-tietueisiin osoittimet, jotka linkittävät kortit toisiinsa myös toiseen suuntaan. Nämä osoittimet pitää tietenkin päivittää kaikissa tietorakennetta muokkaavissa metodeissa. - Voit tietenkin ilman toiseen suuntaan osoittavia osoittimiakin tehdä tulostuksen myös iteratiivisesti. Tämä vain vaatii aika paljon enemmän listan läpikäymistä edestakaisin, mikä on kovin tehotonta.
- Rekursio: Tämän saa toteutettua varsin pienellä vaivalla ja rekursion
kertaaminen on hyvä, mutta et opi mitään uutta osoittimista.
Aloita miettimällä, miten listan voi nähdä rekursiivisena
tietorakenteena, eli miten sen saa jaettua samanmuotoiseksi,
mutta pienemmäksi osaongelmaksi.
Huomaa, että luokan yksityisessä rajapinnassa on valmiiksi
määritelty apufunktio (
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.