8. Voo suunamine ja pseudojuhuarvud

Labori materjal

Esitamisele kuuluvad ülesanded

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

Ülesanne 1: kuupäeva kontroll

Ülesande eesmärgiks on tuvastada kas sisestatud kuupäev on tõene või vigane. Ülesande raames tutvume ka voo suunamisega.

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

Nõuded
  • Programm kuvab iga kuupäeva puhul kas tegu on reaalse või vigase kuupäeva.
  • Aastate vahemik on piiratud 1900 – 2099
  • Programmis on rakendatud liigaasta kontroll
  • Maksimaalselt töötleb 100 kuupäeva
  • 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, mis sisaldab endas sellel lehel antud testkuupäevasid.
Algoritm

NB! Algoritm näitab meile üldisemat ideed ülesande lahenduskäigust ning on eelkõige informatiivse väärtusega. Algoritmis ei kajastu kuidas võiks toimida andmevahetus funktsioonidega. Samuti on funktsioonide kasutamisest tulenevalt mõningad järjestusest teistmoodi.

Samm-sammuline lahendamisjuhend

Alususeks peame tegema andmefaili. Sinna kirjutame samad andmed, mida muidu trükiksime klaviatuurilt iga kord programmi testides. Teisisõnu kirjutame oma testandmed ühekordselt ära ja hiljem lihtsustame oma testimist sedasi. Mõnel ülesandel võib taolisi testfaile olla mitu, mõnel piisab ühest.

Lähtefaili kirjutades tuleks arvestada kõikvõimalike erinevate juhtudega,  mis programmis esineda võivad. Kindlasti tuleb testida nii sobilike kui ka mittesobivaid kuupäevi. Näiteks võib siin olla tavapäraseid kuupäevi – 11. detsember 1981, kuid samuti ka ebareaalseid kuupäevi – 51. detsember, kuu nr 22 jne. Eriti olulised on piirjuhud – nt 29. veebruar liigaastal ja tavapärasel aastal. Järgnevalt on välja pakutud üks võimalik loetelu kuupäevi (võid julgelt kuupäevi lisada loetelu lõppu, kuid need peavad kindlasti sisalduma testis).

Siin on sinu testsisend. Salvesta see 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!

Nüüd 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 programmi. Ü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 unusta iga kord uuesti kompileerimast pärast muudatusi!

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 aga oma programmi koodi sisaldava faili nime. Lisaks kasutame tavaliselt täiendavaid lippusid, et meile ka rohkem veateateid kuvatakse. Näiteks -Wall  ja -Wextra .

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 date.c

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

Veendume, et failid on kõik seal, kus peaks 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 loetakse andmed ette söödetud failist (kasutades voo ümbersuunamist). Selleks saame kasutada järgmist struktuuri, asendades failid õigete nimedega: ./programminimi < andmefailinimi

./programminimi – sedasi saad programmi käima Linuxis käsurealt
< – tähistab, et programmi klaviatuurilt tulevad sisestused juhitakse ümber
andmefailinimi – siit hakatakse lugema mida programmile ette sööta ehk siis kust sisestus tuleb

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äljund nägema välja samasugune nagu siin.

Ülesanne 2: loto

Lae alla ülesande aluskood:

Nõuded
  • Tunnitöö tuleb ehitada ette antud aluskoodile.  Aluskood on sulle antud ning sisaldab juba funktsioonide loetelu funktsioonidest koos kommentaaridega mis tuleb sul realiseerida ja kasutusele võtta.
  • 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 saab kattuda võidunumbriga vaid ühel korral.
  • Kui kõik numbrid kattusid, õnnitle peavõidu korral. Kui ükski ei kattunud, avalda kaastunnet.
Testimine

NB! Kuna loterii nagu nimigi ütleb on juhuslik, siis selle testimisel tuleks juhuarvu seeme (srand funktsiooni argument) määrata konstandiks. Genereeri ühe korral lototroni numbrid ära ja jäta need meelde, et saaksid testi tulemusi kergelt korrata!

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)

Antud testis teeme muudatuse oma lähtenõuetes, 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.

Antud testi juures saame jälgida kusjuures kahte erinevat asja

  1. Jälgi võitude arvu! St 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 vai lihtsalt 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 iga 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: mittekorrektse kuupäeva põhjendus

Algse lahenduse puudujäägiks oli ebaselgus miks üks või teine kuupäev ei valideerunud. Täiendame oma programmi sedasi, et ka põhjus oleks arusaadav.

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 olemasolevat programmi struktuuri.
  • Meeldetuletus! Väldi maagilisi arve!
Testimine

Lisaülesanne 2: lototronile unikaalsed numbrid

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 vahet 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