PR1ET8: Voo suunamine ja pseudo-juhuarvud

Praktikumi materjal

Esitamisele kuuluvad ülesanded

Selles praktikumis on kaks ülesannet, millest mõlemale on laiendusena pakutud välja lisaülesanne.

Ülesanne 1 [W08-1]: Kuupäeva kontroll

Ülesande eesmärgiks on tuvastada, kas sisestatud kuupäev on realistlik või mitte. Ülesande raames tutvume ka voo suunamise kasutamisega. Ülesande algus tehakse klassis koos läbi (andmete lugemise ja väljastamine).

Lae alla ülesande aluskood: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_1_date_base.c

Nõuded
  • Programm kuvab iga kuupäeva järel, kas tegu on reaalse või vigase kuupäevaga
  • Aastate vahemik on piiratud 1900 – 2099
  • Programmis on rakendatud liigaasta kontroll
  • Maksimaalselt töödeldakse 100 kuupäeva
  • Sisestatavad kuupäevad vastavad kõik formaadile DDMMYYYY .
  • Baasülesande raames tuleb lahendada funktsioonid sellisel kujul nagu nad antud on.  Kohustuslike funktsioonide loetelu ja kommentaarid leiad aluskoodist.
  • Programmi esitades pead seda tegema kasutades sisendvoo ümbersuunamist. Sisendiks on fail testkuupäevadega (testandmed antud allpool)
Algoritm

NB! Algoritm on sel korral piiritletud kuupäeva valideerimisega. Ülesande aluskoodis olev massiivide kasutamine ei ole algoritmis kajastatud, mistõttu erineb ka tegevuste järjekord.

Meeldetuletuseks: tegevusdiagrammid ei kajasta funktsioonide vahelist andmevahetust ega ka nende väljakutseid.

Samm-sammuline lahendamisjuhend

Alususeks tuleb luua andmefail, milleks on tavaline tekstifail. Sinna kirjutame samad andmed, mida muidu trükiksime klaviatuurilt, kusjuures ka samas järjekorras. Iga sisendi vahel on kas reavahetus või tühik (lähtuvalt scanf funktsiooni iseloomust). Nii saame oma testandmed ühekordselt kirja panna ning korduvalt testida programmi kiirelt samadel tingimustel. Mõnel ülesandel võib taolisi testfaile olla mitu, mõnel piisab ühest.

Sisendfaili kirjutades tuleks arvestada, et testitud saaks kõik võimalikud olukorrad programmi töös. Kindlasti tuleb testida nii realistlike kui ka ebareaalseid kuupäevi. Näiteks 11. detsember 1981; 51. detsember; kuu nr 22; kuu “abc” jne. Eriti olulised on piirjuhud – nt 29. veebruar. Oleme koostanud testsisendi sinu eest. Kui soovid testandmeid lisada, pane need kõige lõppu!

Salvesta järgnev testsisend tekstifailina samasse kausta kuhu oma programmi paned!

Järgmiseks oleks meil vaja programmi, mis neid kontrollima hakkaks.

Nüüd hakkame töötama ette antud aluskoodiga. Esimesed kaks funktsiooni teeme tunnis koos ära! Kui tunnis polnud, vaata loengusalvestust!

Selle tulemusena peaks meil olema 2 faili, mõlemad samas kaustas:

  1. Programmikood (nt date.c )
  2. Tekstifail sisendandmetega (nt input või input.txt )

Järgmisena on meil vaja lähtekoodist kompileerida programm. Üks valik programmi loomiseks on see kompileerida läbi Geany või mõne teise rakenduse, mida oled senimaani kasutanud. Võid seda julgelt teha, kui end sedasi mugavamalt tunned. Ära vaid pärast igat muudatust koodi kompileerida!

Ava mind, et näha kuidas seda teha käsurealt

Kompileerida võid ka käsurealt. Täpselt sama asi juhtub tegelikult kui nt Geany sees vajutad build nuppu. Selleks on üldine struktuur kompilaatori_nimi -o programmi_nimi koodifaili_nimi.c . Oluline on, et -o järel on alati soovitav programmi nimi (väljund). Kõige lõppu paneme me lähtekoodi faili nimetuse. Lisaks kasutame tavaliselt täiendavaid lippusid, et lihtsustada vigade leidmist. Näiteks -Wall -Wextra ja -Wconversion .

Nüüd paneme selle kõik kokku. Olles saanud käsuakna õigesse kausta, kus asuvad su teised failid, saad teha järgmist:

gcc -o date -Wall -Wextra -Wconversion date.c

Selle reaga kompileeritakse lähtekoodi fail date.c  programmiks nimega date .

Veendume, et failid on olemas ja samas kaustas kasutades käsku ls -l :

Kui varem oli meil 2 faili, siis nüüd peaks neid olema 3:

  • date  – nn binaarfail ehk programm, mis loodi lähtekoodi kompileerimise tulemusena. Käivitatav!
  • date.c  – lähtekoodi fail. Siia kirjutame me tekstiredaktoriga koodi, ei ole käivitatav programmina!
  • input.txt  – tekstifail, mis sisaldab kuupäevi ehk testandmed.

Nüüd käivitame programmi sedasi, et klaviatuurilt trükkimise asemel suuname sisendvoo ümber operatsioonisüsteemi tasandil (meie programm ei loe faili ega oskagi seda teha!). Selleks saame kasutada järgmist käsustruktuuri, asendades failid õigete nimedega: ./programminimi < andmefailinimi

./programminimi – sedasi saad programmi käima Linuxis ja Maci käsurealt
< – tähistab sisendvoo ümbersuunamist – operatsioonisüsteem asendab sisendvoo klaviatuurilt sellele järgneva failinimega
andmefailinimi –  fail, kus paikneb soovitud sisend

Siin lõppeb tunnis koos tehtav osa ning algab iseseisev töö. Selleks hetkeks peaks programmi väljund olema järgmine

Testimine: valmislahendus

Pärast programmi valmimist peaks su väljundis olema järgnevad vastavused.

Ülesanne 2 [W8-02]: Loto

Lae alla ülesande aluskood:

Nõuded
  • Tunnitöö tuleb ehitada ette antud aluskoodile, realiseerides ja kasutades selles ettemääratud funktsioone
  • Lotonumbrid genereeritakse vahemikus 1 … 25 (otspunktid kaasaarvatud)
  • Kasutajalt küsitakse 6 arvu (lotonumbrid)
  • Programm genereerib juhuarvudena 10 arvu (võidunumbrid)
  • Programm kuvab genereeritud võidunumbrid
  • Kontrolli ja näita mitu ja millised numbrid kattusid
    • Baasülesandes pole nõutud numbrite unikaalsus
    • Iga lotonumber tohib kattuda võidunumbriga vaid ühel korral
  • Kui kõik numbrid kattusid, õnnitle peavõidu puhul. Kui ükski ei kattunud, avalda kaastunnet.
Testimine

NB! Kuna loterii nagu nimigi ütleb on juhuslik, selle testimine teadmata sisendit ei ole mõistlik. Testimise jaoks määra juhuarvude alguspunkt konstandiks ning kirjuta genereeritavad arvud üles – nii saad testimiseks korratavad tulemused.

Test 1: Juhuslikud arvud, mõni võidunumber, sisestus OK.

Test 2: Võidunumbrid puuduvad

Test 3: Jackpot

Test 4: Vigane sisestus

Test 5: Iga number võidab vaid korra (absurdsed olukorrad – sanity check)

Selle testi vältel teeme ajutise muudatuse, mis läheb vastuollu ülesande üldiste nõuetega, et testida, mitu korda üks lotonumber võita saab. Kaine mõistus ütleb, et iga number saab võita vaid korra.

NB! See test töötab selliselt vaid siis, kui unikaalsuse nõue ei ole täidetud (st pole tehtud lisaülesanne). Korduvad numbrid on seega lubatud.

St kõik lototroni numbrid peaksid tulema ühed ning sisestame ka enda numbrid kõik ühtedena.

Testi raames jälgime kahte asja

  1. Jälgi võidunumbrite arvu – iga meie sisestatud number saab võita ühe korra! St väljundis peaksime nägema Matched 6 out of 6!)
  2. Jälgi lototroni genereeritud numbreid. Need tohivad olla vaid ühed! (0 või 2 esinemine tähendab, et sul on viga juharvude valemi koostamisel!)
Märkus: Tunnitöö baasülesandes vaatleme vaid lihtsat juhtu, kus kasutaja arv saab võita ühekordselt. Näiteks kui kasutaja sisestab numbrid “1, 1, 1, 1, 1, 1” ja lototron genereerib “1, 2, 3, 4, 5, 6, 7, 8, 9, 10”, siis baasülesande raames piisab, kui loeme, et kokku tuli 6 tabamust. Kui aga kasutaja numbrid oleksid “1, 2, 3, 4, 5, 6” ja lototron genereeriks “1, 1, 1, 1, 1, 1, 1, 1, 1, 1”, siis oleks olnud vaid 1 tabamus.

Lisaülesanne 1 [W8-3]: Mittekorrektse kuupäeva põhjendus

Algse lahenduse puudujäägiks oli, et me ei põhjendanud miks kuupäev oli ebarealistlik. Täiendame oma programmi sedasi, et ka põhjus oleks kasutajale nähtav.

Nõuded
  • Laienda oma programmi nii, et programm põhjendaks, miks kuupäev reaalseks ei osutu
  • Minimaalselt pead eristama
    • Ebasobivat aasta väärtust
    • Ebasobivat kuu väärtust
    • Ebasobivat päevade arvu, eristades sealjuures väiksemat ja suuremat kui lubatud väärtust
    • Mitte-liigaastal olevat 29ndat veebruari
  • Lahenduses võid lisada täiendavaid funktsioone ja muuta mõistuse piires ka senist programmi struktuuri.
  • Meeldetuletus! Väldi maagilisi arve! Soovituslik on kodeerida oma veakoodid
Testimine

Lisaülesanne 2 [W8-4]: Lototronis vaid unikaalsed arvud

Selle ülesande eesmärk on muuta ülesanne täisväärtuslikuks. Selleks on meil vaja lahendada vaid üks funktsioon FindMatchCount()  ning seda õigetes kohtades kasutusele võtta.

Nõuded
  • Kasutaja poolt sisestatavatele numbritele tuleb rakendada unikaalsuse nõue. Kui kasutaja sisestab korduva numbri, tuleb see sama number uuesti küsida.
  • Lototronile tuleb rakendada unikaalsuse nõue. Lototroni poolt genereeritavad võidunumbrid ei tohi korduda.
  • Lahenduse käigus ei tohiks muuta GetUserNumbInRange()  ja GenerateRandomNum()  funktsioone, otsi selleks sobilikum koht.
  • Kommenteeri sisse ja lahenda ära funktsioon CheckIfNumInArray() . Võta see funktsioon kasutusele kolmes kohas
    1. Kasutaja lotonumbrite unikaalsuse kontrolliks
    2. Lototroni genereeritud võidunumbrite unikaalsuse kontrolliks
    3. Kasutaja ja lotoarvude kattuvuse leidmise funktsioonis FindMatchCount()
Testimine

Test 1: Kontrollime unikaalsuse nõuet kasutajale

NB! Kontrolli kindlasti kasutades sama jada!

Test 2: Kontrollime unikaalsuse töötamist lototroni poolt

Selleks, et kontrollida lototroni tööd, peame me jällegi manipuleerima konstante.

Selle testiga on meil arvuti poolt genereeritud numbrite arv täpselt sama suur kui maksimaalne unikaalsete numbrite arv. St kõik numbrid 1 – 10 peavad saama genereeritud ning ükski neist korduda ei tohi.

Mõtle ja vasta ka küsimusele, mis juhtuks, kui oleksime konstandi pannud 9 peale?

Pärast tundi peaksid

  • Teadma, millised standardvood eksisteerivad
  • Oskama kasutada voo suunamist erinevatel platvormidel
  • Oskama käivitada enda kompileeritud programme Linuxi käsurealt
  • Oskama kasutada tõeväärtusi (boolean andmetüüp)
  • Oskama tükeldada sisestust vajadusel tähemärkhaaval
  • Oskama kasutada scanf poolt taastatavat väärtust
  • Oskama kasutada üherealisi tingimuslauseid ja tsükleid
  • Oskama genereerida pseudojuhuarve
    • .. pannes need alati algama samast arvust
    • .. pannes need kellaajast sõltuvaks
  • Teadma, mis vahe on pseudojuhuarvul ja juhuarvul
  • Oskama piirata juhuarvude genereerimise vahemikku
  • Teadma, mis on ning kuidas töötab UNIXi kellaaeg, sh mis tähtsus on 1. jaanuaril 1970.

Täiendav materjal