Ohjelmoinnin peruskurssi Y2, kurssimateriaali

Luku 4.3: Tehtävä: Reading a human-writeable file

Etusivulle

Luku 4.3: Tehtävä: Reading a human-writeable file

Pistearvo: 200p

Bonus: +5 % omista pisteistä aikaisesta palautuksesta.

Teema

Tehtävissä 4.2 ja 4.3 luetaan eri formaatein tallennettua dataa. Molemmissa luettava data kuvaa shakkipelin tilanteita. Shakkipeliä kuvaavat luokat ja tiedoston tulkintaa varten olevan luokan pohja annetaan valmiina.

Oppimis- ja kertaustavoitteet

  • Harjoitellaan lukemista tietovirrasta
  • Tutustutaan mahdolliseen tapaan säilyttää tietoa tiedostossa.
  • Kirjoitetaan isomman ohjelman keskeinen osa. Lähes jokaisessa projektiaiheessa ohjelman tulee pystyä lukemaan ja tallentamaan tiedostoja. Monessa työssä formaatti voi olla yksinkertaisempi.
  • Tutustutaan merkkijonotyökaluihin. Tehtävässä merkkijonoista täytyy etsiä alkioita, merkkijonoja täytyy pilkkoa osiin, ylimääräistä whitespacea (tyhjää tilaa: välilyönnit, tabulaattorit, rivinvaihdot jne.) täytyy pystyä poistamaan, jne

Intro : Tiedostoformaateista

Yksi keskeinen ominaisuus lähes joka ohjelmassa on mahdollisuus tallentaa ohjelman toimintaan liittyvää tietoa tiedostoihin sekä ladata ohjelman käyttöön. Tallennettavalla tiedolla on lähes aina jokin selkeä rakenne. Tiedon esitystapaa tiedostoissa kutsutaan tiedostoformaatiksi.

Formaattien suunnitteluun tai olemassa olevan formaatin valintaan johonkin tehtävään vaikuttaa joukko erilaisia tavoitteita kuten

  • Luettavuus

  • Editoitavuus (käsin tai apuohjelmilla)
    • Kirjoittaminen alusta myös käsin
    • Mahdollisuus lisätä väliin
  • Virheherkkyys
    • Yhtälailla formaatin kuin parserin (tiedoston tulkitsijan) tehtävä
  • Tilankäyttö

  • Formaatin laajennettavuus

  • Nopeus

  • Tunnetut formaatit (esim CSV) joita käyttämällä ohjelman tallentama data on muilla ohjelmilla käsiteltävissä.

Käsin kirjoitettava formaatti

Tässä tehtävässä kirjoitetaan ohjelma, joka lukee käsin editoitavaa tiedostoformaattia. Mm. monet asetustiedostot ovat tällaisia. Niitä on helppo lukea ja kirjoittaa käsin. Nämäkin formaatit ovat helposti laajennettavissa: Niihin voidaan lisätä tietoa, jota ohjelman ei välttämättä tarvitse ymmärtää (esim. ohjelman plugineille tarkoitettuja asetustietoja), mutta tällaisen tiedon tulee olla ohitettavissa.

Käsin kirjoitettava formaatti ei voi olla yhtä sitova kuin konelukemiseen tarkoitettu, ja sitä lukevan koodin tulisi sietää erityisesti ylimääräistä whitespacea, vaihtelua rivien järjestyksessä jne. Mikäli käyttäjä rikkoo formaatin sääntöjä, pitäisi tälle tulostaa mahdollisimman selkeä kuvaus ongelmasta, jotta hän pystyy korjaamaan virheen. (Tässä tehtävässä riittää heittää poikkeuksia, joskin ne voisivat kantaa tarvittavaa informaatiota)

Usein tällaiseen tiedostoon pitää voida kirjoittaa kommentteja (kuten vaikkapa Python-koodiin), jotka tiedostoa lukeva koodi ohittaa. Tässä tehtävässä kommentteja ei käytetä.

Esimerkkejä muista formaateista

Luvussa 4.2 kirjoitetaan konelukuun tarkoitettua formaattia.

Tehtävä : käytettävä formaatti

Tehtävän formaatti on kehitetty shakkipelin tilanteen tallennukseen. Tässä on pelkkä lopputilanne, ei siirtoja. Alla on esitetty esimerkkitallennus, ja sen jälkeen seuraa formaalimpi esitys siitä, millainen tehtävän käyttämä rakenne on.

Esitetyn formaatin suunnitteluperiaatteina on sen luettavuus helposti ihmisen toimesta, mahdollisuus lisätä uusia lohkoja säilyttäen silti mahdollisuus lukea tietoa vanhoilla ohjelmilla sekä vikasietoisuus (vain yksi asia per rivi). Tiedostossa on myös versionumero ja tunniste, joiden avulla voidaan estää tilanteet, joissa yritetään lukea väärän tyyppistä dataa.

Esimerkki

Tiedosto on tarkoitettu ihmisen luettavaksi ja kirjoitettavaksi. Tutki itse alla olevaa esimerkkiä.

SHAKKI 1.2 Tallennustiedosto

#Pelin tiedot

Tallennettu : 5.7.2001
Musta     : Marko
Valkoinen : Lauri

#Kommentit

Laurin revanssipeli, joskin huonosti on menossa...

#Musta

Kuningas   : a4
Torni      : a6
Sotilas    : b3
Kuningatar : c8

#Valkoinen

Kuningas   : d3
Ratsu      : f1

chess2clean.sav

Vähemmän siisti (mutta ehjä) esimerkki

Ihmisen kirjoittamassa tiedostossa täytyy mielellään sallia hieman vaihtelua whitespacen käytön suhteen. Alla olevassa esimerkissä kyseessä on uudempi versio tiedostoformaatista, joka on kuitenkin ladattavissa vanhalla ohjelmamme versiolla. Ladattaessa menetämme tiedon siirroista ja turnauksesta, mutta kaikki version 1.2 ominaisuudet ovat ladattavissa normaalisti. Esimerkissä whitespace on värjätty keltaiseksi. Huomaa vaihteleva tyhjien rivien käyttö, välilyönnit rivien päissä ja keskellä.


SHAKKI 1.3 Tallennustiedosto

#pelin TIedot

Tallennettu  :5.7.2001
Musta     : Marko
Valkoinen:Lauri  
#Kommentit 
Laurin revanssipeli, joskin huonosti on menossa...

#Siirrot
Kb4
b3
Ka4

#Turnaus  

Ei turnausta

#musta

Kuningas   : a4   
Torni      : a6
Sotilas    :b3

Kuningatar: c8


#Valkoinen

 Kuningas : d3
 Ratsu    : f1
  

chess2.sav

Tiedoston rakenne

Tiedoston rakenne on seuraava:

Header-rivi sisältää yksittäisillä välilyönneillä erotettuina seuraavat osat:
teksti "SHAKKI" heti rivin alussa,
versionumeron muotoa 1.2 (numero.numero, Voit ohittaa numeron tarkistuksen tässä tehtävässä),
sekä tekstin "Tallennustiedosto"

Tätä seuraa (1 - N) lohkoa (jotka alkavat merkillä # ja tämän perään kirjoitetulla
lohkon tunnisteella)

Jokainen lohko päättyy joko tiedoston päättymiseen tai seuraavan lohkon tunnisteeseen.
Merkin # täytyy olla rivin ensimmäinen merkki, jotta rivi tulkitaan lohkon tunnisteeksi.

Ainakin lohkojen "pelin tiedot", "musta" ja "valkoinen" täytyy löytyä jotta peli voidaan ladata.

"Pelin tiedot"-lohko tulee aina ennen "musta"- ja "valkoinen"-lohkoja.

Lohkot

Lohkon rakenne

Tunniste = merkki '#' ja jokin merkkijono

Mahdollinen whitespace tunnisteen lopussa ei kuulu tunnisteeseen. Tunnisteen
tekstissä isoilla ja pienillä kirjaimilla ei ole väliä.

Lohko jatkuu seuraavaan '#'-merkkiin tai tiedoston/tietovirran loppuun asti.
Tyhjät tai pelkkää whitespacea sisältävät rivit ohitetaan, jollei lohkon kuvauksessa
muuten kerrota, muut rivit sisältävät lohkon dataa.

Näillä riveillä voi rivin päissä tai erotinmerkin ':' ympärillä olla vaihteleva määrä whitespacea.

VINKKI: str-luokan metodin strip() käyttö sopivassa vaiheessa voi olla kätevää.

Lohkojen kuvaukset

Kommenttilohko (tunniste #Kommentit)

Ohitetaan tässä tehtävässä

Kommenttilohko. Koko lohkon sisältö on merkkijono, joka kuvaa tallennettua tilannetta. Teksin alussa ja lopussa olevat tyhjät rivit eivät kuulu kommenttiin, mutta tekstin sisällä olevat kyllä.

Pelin tiedot (tunniste #Pelin tiedot)

Alla on kuvattu tämän osion mahdollisesti sisältämät rivit.

"Tallennettu" ":" DATA
   DATA on pelin tallennuspäivämäärä muodossa Päivä.Kuukausi. Vuosi
   Ohitetaan tässä tehtävässä
"Musta" ":" DATA
   DATA on mustan pelaajan nimi
"Valkoinen" ":" DATA
   DATA on valkoisen pelaajan nimi

Yllämainitut rivit voivat olla missä tahansa järjestyksessä.

Pelaajan nimessä saa olla välilyöntejä. esim. "Teemu Teekkari"
(nimen päissä oleva whitespace ei kuitenkaan kuulu nimeen)

Nappuloiden sijainnit (tunnisteet #Musta ja #Valkoinen)

Tunnisteella #Musta alkava lohko kertoo mustien nappuloiden sijainteja. #Valkoinen vastaavasti valkoisten sijainteja.

"Kuningas"/"Kuningatar"/"Torni"/"Lahetti"/"Ratsu"/"Sotilas" ":" DATA
   Rivin alku määrittää shakkinappulan tyypin.
   DATA on nappulan sijainti laudalla, esim. "a4"

Huomaa että lähetti on tiedostoformaatissa Lahetti. (ei ä-kirjainta)

Shakkinotaatio:

Shakkilaudan koko on 8x8. Laudalla on 8 riviä jotka on numeroitu 1-8, sekä 8 saraketta, jotka on merkitty pienin kirjaimin a-h.

Sijainti laudalla merkitään liittämällä peräkkäin sarakkeen kirjain ja rivin numero. Esim "h8" on yksi laudan nurkista.

Muut lohkot #???

Tuntemattomat lohkot ovat todennäköisesti formaattiin uudemmissa versioissa lisättyjä ominaisuuksia. Nämä lohkot tulee tehtävässä ohittaa. Ne eivät ole virhetilanteita.

Virhetilanteet

Virheelliset nappuloiden nimet, puuttuvat pelaajat, puuttuvat (toisen tai molempien) pelaajan nappuloiden paikat jne. ovat kaikki virheitä, joiden tulee johtaa poikkeuksen CorruptedChessFileException heittämiseen.

Tehtävänanto

Toteuta ja testaa luokkaan HumanWritableIO pyydetty metodi load_game

  • def load_game(self, input)

    Luo uuden peliolion (Game), jonka se metodin päätteeksi palauttaa. Metodi lukee pelin pelaajat ja nappuloiden sijainnin käyttäen apuna muita luokan metodeja. Tiedoston päättyessä palauttaa peliolion, jossa on tiedostossa annetut pelaajat ja lauta asetettuna. (Mikäli olennaisia tietoja puuttuu heitetään poikkeus) Kommenttilohko ja mahdolliset tuntemattomat lohkot metodin tulee ohittaa. Luo ja sulje tietovirta testiluokassasi, ei tässä metodissa.

    Jos luettavassa tiedostossa on jotain pielessä, metodi heittää poikkeuksen CorruptedChessFileException. Annettu tehtäväpohja heittää jo tällaisen poikkeuksen tilanteessa, jossa tietovirran luvussa on jokin ongelma. Sinun pitäisi heittää sellainen, jos luetun tiedon rakenteessa on jokin ongelma.

Valmiiksi annettu koodi

  • board.py. (Ei palauteta) Hyvin yksinkertainen luokka joka kuvaa pelilautaa. Mahdollistaa nappuloiden sijoittamisen laudalle ja laudan ruutujen tarkastelun. Sisältää apumetodin sarakekirjainten muuntamiseen ruudukon indekseiksi.

  • player.py. (Ei palauteta) Hyvin yksinkertainen luokka joka kuvaa pelaajaa. Mahdollistaa nimen ja pelaajan värin asettamisen ja näiden attribuuttien lukemisen.

  • game.py. (Ei palauteta) Hyvin yksinkertainen luokka joka koostaa pelissä tarvitut luokat yhteen. Mahdollistaa pelaajien ja pelilaudan asettamisen ja hakemisen.

  • piece.py. (Ei palauteta) Hyvin yksinkertainen luokka joka kuva shakkinappulaa. Shakkinappulalla on omistaja (pelaaja) sekä tyyppi (Kuningas, Ratsu, jne...)

  • corrupted_chess_file_error.py. (Ei palauteta) Poikkeusluokka tiedostonluvussa esiintyvien ongelmien esittämiseen.

  • broken_reader.py. (Ei palauteta) Apuluokka virhetilanteiden testaamiseen.

  • human_writeable_IO.py. Palautetaan

    Apuluokka, jonka avulla voidaan ladata ja tallentaa (tässä harjoituksessa tallennusta ei toteuteta) pelitilanne tiedostosta.

    Toteuta luokkaan vaadittujen metodien lisäksi halutessasi myös apumetodeja. Esimerkiksi eri tyyppisten lohkojen lukemiseen voi olla kätevää tehdä omat metodit.

  • test.py. Palautetaan Testitiedoston pohja. Testiluokan nimen tulee olla Test jotta A+ tunnistaa sen. Eli Test tiedostossa test.py.

Ohjeita

Lue molemmat PyUnit-ohjeet, mikäli et vielä ole lukenut niitä. Halutessasi tee Eclipseen projekti jossa PyUnit:ia on helppo suorittaa.

Tehtävänanto löytyy A+:sta.

Etusivulle