Praktikumi materjal
- Slaidid: Standardvood
- Slaidid: Pseudojuhuarvud
- Täiendav: voo suunamise juhend
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 .
- NB! Kuupäevade formaadid on konkreetselt määratletud.
https://en.wikipedia.org/wiki/Date_format_by_country
- NB! Kuupäevade formaadid on konkreetselt määratletud.
- 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!
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
14041805 26052100 31012015 30092011 01012001 31062011 32011999 00012011 01002023 01132033 29022022 28022022 28022000 29022000 29022004 29021900 |
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:
- Programmikood (nt date.c )
- 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!
Veendume, et failid on olemas ja samas kaustas kasutades käsku ls -l :
|
1 2 3 4 5 |
INTRA\risto.heinsar@lx27:~/P/date> ls -l total 18 -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 12732 Oct 6 14:11 date -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 536 Oct 5 15:50 date.c -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 73 Oct 6 14:11 input.txt |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/date> ./date < input Dates read: 16 14.04.1805 26.05.2100 31.01.2015 30.09.2011 01.01.2001 31.06.2011 32.01.1999 00.01.2011 01.00.2023 01.13.2033 29.02.2022 28.02.2022 28.02.2000 29.02.2000 29.02.2004 29.02.1900 |
Testimine: valmislahendus
Pärast programmi valmimist peaks su väljundis olema järgnevad vastavused.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/kp> ./date < input Dates read: 16 14.04.1805 < Invalid date! 26.05.2100 < Invalid date! 31.01.2015 < OK 30.09.2011 < OK 01.01.2001 < OK 31.06.2011 < Invalid date! 32.01.1999 < Invalid date! 00.01.2011 < Invalid date! 01.00.2023 < Invalid date! 01.13.2033 < Invalid date! 29.02.2022 < Invalid date! 28.02.2022 < OK 28.02.2000 < OK 29.02.2000 < OK 29.02.2004 < OK 29.02.1900 < Invalid date! |
Ülesanne 2 [W8-02]: Loto
Lae alla ülesande aluskood:
- Eestikeelsete kommentaaridega: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_2_loto_base.c
- Ingliskeelsete kommentaaridega: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_2_loto_base_en.c
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Enter lottery number [1 ... 25] (1 / 6): 1 Enter lottery number [1 ... 25] (2 / 6): 3 Enter lottery number [1 ... 25] (3 / 6): 5 Enter lottery number [1 ... 25] (4 / 6): 13 Enter lottery number [1 ... 25] (5 / 6): 14 Enter lottery number [1 ... 25] (6 / 6): 15 User numbers are 1 3 5 13 14 15 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 1 Winning number: 13 Winning number: 15 Matched 3 out of 6! |
Test 2: Võidunumbrid puuduvad
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Enter lottery number [1 ... 25] (1 / 6): 11 Enter lottery number [1 ... 25] (2 / 6): 12 Enter lottery number [1 ... 25] (3 / 6): 14 Enter lottery number [1 ... 25] (4 / 6): 21 Enter lottery number [1 ... 25] (5 / 6): 22 Enter lottery number [1 ... 25] (6 / 6): 23 User numbers are 11 12 14 21 22 23 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Matched 0 out of 6! None of the numbers matched. Better luck next time! |
Test 3: Jackpot
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Enter lottery number [1 ... 25] (1 / 6): 17 Enter lottery number [1 ... 25] (2 / 6): 18 Enter lottery number [1 ... 25] (3 / 6): 10 Enter lottery number [1 ... 25] (4 / 6): 1 Enter lottery number [1 ... 25] (5 / 6): 20 Enter lottery number [1 ... 25] (6 / 6): 25 User numbers are 17 18 10 1 20 25 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 17 Winning number: 18 Winning number: 10 Winning number: 1 Winning number: 20 Winning number: 25 Matched 6 out of 6! Congratulations! You won the jackpot! |
Test 4: Vigane sisestus
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Enter lottery number [1 ... 25] (1 / 6): -5 Invalid number! Retry: 5 Enter lottery number [1 ... 25] (2 / 6): 26 Invalid number! Retry: 27 Invalid number! Retry: -4 Invalid number! Retry: 6 Enter lottery number [1 ... 25] (3 / 6): 7 Enter lottery number [1 ... 25] (4 / 6): 8 Enter lottery number [1 ... 25] (5 / 6): 9 Enter lottery number [1 ... 25] (6 / 6): 10 User numbers are 5 6 7 8 9 10 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 9 Winning number: 10 Matched 2 out of 6! |
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.
|
1 |
#define MAX_LOTTO 1 |
St kõik lototroni numbrid peaksid tulema ühed ning sisestame ka enda numbrid kõik ühtedena.
Testi raames jälgime kahte asja
- 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!)
- Jälgi lototroni genereeritud numbreid. Need tohivad olla vaid ühed! (0 või 2 esinemine tähendab, et sul on viga juharvude valemi koostamisel!)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Enter lottery number [1 ... 1] (1 / 6): 1 Enter lottery number [1 ... 1] (2 / 6): 1 Enter lottery number [1 ... 1] (3 / 6): 1 Enter lottery number [1 ... 1] (4 / 6): 1 Enter lottery number [1 ... 1] (5 / 6): 1 Enter lottery number [1 ... 1] (6 / 6): 1 User numbers are 1 1 1 1 1 1 Lottery numbers are 1 1 1 1 1 1 1 1 1 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Matched 6 out of 6! Congratulations! You won the jackpot! |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/kp> ./date_adv < input Dates read: 16 14.04.1805 < Year out of range! 26.05.2100 < Year out of range! 31.01.2015 < OK 30.09.2011 < OK 01.01.2001 < OK 31.06.2011 < Day exceeds maximum days for given month! 32.01.1999 < Day exceeds maximum days for given month! 00.01.2011 < Day before first of month! 01.00.2023 < No such month exists! 01.13.2033 < No such month exists! 29.02.2022 < 29th of February only exists on leap year! 28.02.2022 < OK 28.02.2000 < OK 29.02.2000 < OK 29.02.2004 < OK 29.02.1900 < 29th of February only exists on leap year! |
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
- Kasutaja lotonumbrite unikaalsuse kontrolliks
- Lototroni genereeritud võidunumbrite unikaalsuse kontrolliks
- Kasutaja ja lotoarvude kattuvuse leidmise funktsioonis FindMatchCount()
Testimine
Test 1: Kontrollime unikaalsuse nõuet kasutajale
NB! Kontrolli kindlasti kasutades sama jada!
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Enter lottery number [1 ... 25] (1 / 6): 1 Enter lottery number [1 ... 25] (2 / 6): 2 Enter lottery number [1 ... 25] (3 / 6): 3 Enter lottery number [1 ... 25] (4 / 6): 4 Enter lottery number [1 ... 25] (5 / 6): 3 You've already entered this number! Retry: 2 You've already entered this number! Retry: 1 You've already entered this number! Retry: 5 Enter lottery number [1 ... 25] (6 / 6): 6 User numbers are 1 2 3 4 5 6 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 1 Winning number: 4 Matched 2 out of 6! |
Test 2: Kontrollime unikaalsuse töötamist lototroni poolt
Selleks, et kontrollida lototroni tööd, peame me jällegi manipuleerima konstante.
|
1 |
#define MAX_LOTTO 10 |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Enter lottery number [1 ... 10] (1 / 6): 1 Enter lottery number [1 ... 10] (2 / 6): 2 Enter lottery number [1 ... 10] (3 / 6): 3 Enter lottery number [1 ... 10] (4 / 6): 4 Enter lottery number [1 ... 10] (5 / 6): 5 Enter lottery number [1 ... 10] (6 / 6): 6 User numbers are 1 3 4 5 6 Lottery numbers are 2 8 5 1 10 9 3 6 7 4 Winning number: 1 Winning number: 2 Winning number: 3 Winning number: 4 Winning number: 5 Winning number: 6 Matched 6 out of 6! Congratulations! You won the jackpot! |
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
- Boolean type support library
https://en.cppreference.com/w/c/types/boolean - What is a leap year
https://www.timeanddate.com/date/leapyear.html - Standard streams
https://en.wikipedia.org/wiki/Standard_streams - Redirection
https://en.wikipedia.org/wiki/Redirection_(computing) - Pseudorandomness
https://en.wikipedia.org/wiki/Pseudorandomness - Why does Cloudflare use lava lamps to help with encryption? (üks võimalik lahendus pseudojuhuslikkuse probleemile)
https://www.cloudflare.com/learning/ssl/lava-lamp-encryption/ - Unix time
https://en.wikipedia.org/wiki/Unix_time - Unixi praegune kellaaeg ja selle teisendi
https://www.unixtimestamp.com - rand() and srand() in C/C++
https://www.geeksforgeeks.org/rand-and-srand-in-ccpp/ - time.h library in C
https://www.cplusplus.com/reference/ctime/