Kodused ülesanded
Funktsioonide nimede ja tüüpide valideerimise kood on juhendi lõpus. Esitada tuleb kuus faili:
arvud.h
, arvud.cpp
, pilt.h
, pilt.cpp
, ilm.h
, ilm.cpp
.
1. Funktsioonid
NB! Loodud funktsioonid lisa vastavalt failidesse arvud.h
ja arvud.cpp
.
1a. Kirjuta funktsioon unique_ptr<int> genereeri_arv()
, mis tagastab juhusliku täisarvu lõigul [1, 1000]
.
1b. Kirjuta mallifunktsioon std::string proovi_arvu(std::weak_ptr<T> ptr)
, mis kontrollib, kas parameetrina antud nõrk viit on kehtiv. Kehtiva viida korral tagastab funktsioon on olemas, ma luban
ja mittekehtiva viida korral ei ole enam :/
.
Näiteks, testprogrammi
auto arv1{genereeri_arv()}; auto arv2{genereeri_arv()}; auto arv3{genereeri_arv()}; cout << format( "arv1: {}; arv2: {}; arv3: {}" , *arv1, *arv2, *arv3); auto ptr1{std::make_shared< int >(32)}; std::weak_ptr< int > weak1{ptr1}; cout << format( "\nptr1: {}" , proovi_arvu(weak1)); std::weak_ptr< float > weak2{make_shared< float >(25.5)}; weak2.reset(); cout << format( "\nptr2: {}" , proovi_arvu(weak2)); |
võimalik väljund on
arv1: 525; arv2: 162; arv3: 494 ptr1: on olemas, ma luban ptr2: ei ole enam :/ |
2. Pildid
NB! Loodud funktsioonid lisa vastavalt failidesse pilt.h
ja pilt.cpp
.
Üks lihtsamaid pildiformaate on PPM (Portable Pixel Map). PPM fail koosneb päisest, kus on neli välja:
- id - PPM faili puhul on see P6
- laius - pildi laiuse pikslite arv
- kõrgus - pildi kõrguse pikslite arv
- värv - maksimaalne värvi väärtus [0, 255] (tegelikult võib olla [0, 65535] )
Peale päist on RGB väärtused binaarkujul (iga piksli jaoks on kolm baiti värvide rgb jaoks).
2a. Koosta struktuur RGB
värvide väärtuste hoidmiseks.
- Struktuur sisaldab liikmeid r, g ja b jaoks (sobib tüüp
unsigned char
). - Struktuuri suurus peab olema kolm baiti.
- Struktuuri suurust saab kontrollida
sizeof(RGB)
abil. Juhul kui suurus on midagi muud (näiteks 4), siis saab struktuuri definitsioonis nime järele kirjutadaattributepacked
, mis võiks asja parandada.
- Struktuuri suurust saab kontrollida
Huvitavat: On ka failiformaat ID-ga "P3", mille RGB väärtused on ASCII koodis.
2b. Koosta struktuur PiltRGB
, milles on
- isendiväljad pildi päise parameetrite jaoks ja unikaalne viit nimega
m_andmed
RGB massiivi jaoks - konstruktor (parameetriks faili nimi), mis loeb PPM faili päise isendimuutujatessse ja faili ülejäänud sisu massiivi
m_andmed
.- faili avamiseks sobib
std::ifstream fail{faili_nimi, std::ios::binary}
, sest tegemist on binaarfailiga. Faili saab sisse lugeda käsugaread
, mille üheks parameetriks onreinterpret_cast<char *>(toorviit värvipikslite algusele)
. Võib eeldada, et fail on alati olemas.
- faili avamiseks sobib
- funktsioon
void salvesta(faili nimi)
, mis salvestab struktuuri etteantud nimega faili PPM formaadis. - funktsioon
RGB& piksel(int x, int y)
- tagastab viite RGB struktuurile, mis vastab etteantud koordinaatidega pikslile. - funktsioon
void inverteeri()
, mis pöörab pildi värvid ümber, nt kui maksimaalne värvi väärtus on 255, siis (0, 5, 255) -> (255, 250, 0). - funktsioon
void lisa_kolmandik()
, mis lisab kolmandikjooned nii horisontaalselt kui ka vertikaalselt. Näiteks, pilt
![]() |
muutub peale funktsiooni void lisa_kolmandik()
rakendamist järgmiseks:
![]() |
Ümardamise erinevuste vältimiseks arvutada kolmandik ujukomaarvudes ja lõpus muuta see täisarvuks. Kolmandikjoon lisada vastavast äärest, nt parempoolne vertikaaljoon lisada paremast äärest kolmandiku kaugusele ja vasakpoolne vertikaaljoon vasakust äärest kolmandiku kaugusele. Analoogiliselt toimida horisontaaljoontega.
3. Ilmajaam ja sensorid
NB! Loodud funktsioonid lisa vastavalt failidesse ilm.h
ja ilm.cpp
.
Loo klassid, mille abil saab simuleerida võrguta ilmajaamade ja nende sensorite tööd. Ilmajaamadel on sensorid ja ilmajaamad saavad sensoreid omavahel jagada. Sensoril on nõrgad seosed (viidad) nendega seotud ilmajaamadele ja neid on võimalik võrgust lahti ühendada.
Loo kaks klassi Ilmajaam
ja Sensor
, mille kõik isendimuutujad on avalikud.
Klass Ilmajaam
algab päisega class Ilmajaam : public std::enable_shared_from_this<Ilmajaam> {
See on vajalik, et jooksvast objektist (this
) saaks luua weak_ptr
(funktsiooniga weak_from_this()
).
Klassis Ilmajaam
on järgmised isendiväljad:
m_nimi
- sõne ilmajaama nime jaoksm_sensorid
- vektor, mille elementideks on jagatud viidadSensor
objektidest
Klassis on konstruktor, mille parameetriks on sõne (ilmajaama nimi). Konstruktor loob uue objekti ja väärtustab isendivälja m_nimi
etteantud nimega.
Klassis Sensor
on järgmised isendiväljad:
m_nimi
- sõne sensori nime jaoksm_ilmajaamad
- vektor, mille elementideks on nõrgad viidadIlmajaam
objektidest
Klassis on konstruktor, mille parameetriks on sõne (sensori nimi) ja nõrk viit ilmajaamale. Konstruktor loob uue objekti ja väärtustab isendivälja m_nimi
ning lisab parameetrina antud ilmajaama vektorisse. Sensorit ei saa luua ilma, et mõni Ilmajaam oleks sellega seotud.
Klassis Ilmajaam
on järgmised funktsioonid:
weak_ptr<Sensor> lisaSensor(string nimi)
, mille parameetriks on sõne (sensori nimi) ja mis tagastab nõrga viida äsjaloodud sensorile. Funktsioon loob jagatud viida uuest sensorist ja lisab selle ilmajaama vektorisse.
NB! Uue sensori loomiseks on vaja nõrka viita jooksvast ilmajaamast (this).
Siin on see koodiosa, millega saab ilmajaamas luua jagatud viita uuele sensorile
std::make_shared<Sensor>(nimi, std::enable_shared_from_this<Ilmajaam>::weak_from_this()) |
Funktsioon lisaSensor
on funktsioon, millega sensoreid luua!
lisaSensorid
, mille parameetriks on jagatud viitIlmajaam
objektile ja mis ei tagasta midagi. Funktsioon lisab parameetriks olevalt ilmajaamalt sensorid jooksva (aktiivse) ilmajaama sensorite vektorisse ja vastupidi. Kui lisatav sensor on juba olemas (kontrollida nime järgi), siis sensorit ei lisata. Sensori lisamisel lisatakse ilmajaama nõrk viit ka sensorile endale.int mõõda(string)
- funktsioon, mis tagastab etteantud nimega sensori mõõtmise väärtuse (rohkem allpool). Kui sensorit pole, siis tagastatakseint
tüübi minimaalne väärtus.void eemalda(Sensor* s)
, mis eemaldab sensori ilmajaama nimekirjast (kui sensor on seal).
Klassis Sensor
on järgmised funktsioonid:
void lisaJaam(weak_ptr<Ilmajaam> jaam)
- lisab ilmajaama sensori vektorisse.void lahti()
- lülitab sensori "välja", st eemaldab sensori tema ilmajaamadest ja tühjendab sensori ilmajaamade vektori (kustutab kõik viidad ilmajaamadele).int mõõda()
- tagastab temperatuuri näidu. Selle alamülesande raames piisab, kui tagastusväärtus on 0.
Automaatkontroll ei nõua <<
ülelaadimist, aga selle olemasolul kasutatakse seda, et printida muutujate infot, kui mõni test põrub.
4. Ilmajaamade ja sensorite simulatsioon
NB! Loodud funktsioonid lisa vastavalt failidesse ilm.h
ja ilm.cpp
.
Loo lisafunktsioonid, mille abil simuleerida eelmises ülesandes tehtud klasside tööd.
4a. Sensori mõõda
funktsiooni täiendamine
Kirjuta funktsioon int random_nr()
, mida saab kasutada ülesandes mõõtmistulemuste simuleerimiseks.
Funktsioon
- kasutab generaatoriks
mt19937
(static
) - seemneks on
2025
- genereerib täisarvu lõigult
[16, 26]
kasutades C++random
teegi vahendituniform_int_distribution
(samutistatic
).
Esimesed 5 numbrit võiks olla: 17, 21, 25, 19, 26.
Kui funktsioon on loodud, lisada selle kasutamine funktsioonile Sensor::mõõda
.
4b. Simulatsiooni loomine
Loo funktsioon ilm_main
, mille parameetriks on stringstream
objekt ja mis tagastab viimase näidu (täisarvu).
Funktsioonis on lokaalsed vektorid ilmajaamade (shared_ptr<Ilmajaam>
) ja sensorite (weak_ptr<Sensor>
) hoidmiseks ning int
tüüpi muutuja viimase näidu jaoks. Edaspidi nimetame neid vastavalt ilmajaamade ja sensorite vektoriteks.
Kasutaja sisend simuleeritakse stringstream
objektiga, kuhu salvestatakse järjest täisarvud käskudega ja erinevad argumendid, mida vajatakse käskude täitmisel.
Käskude jaoks defineeri enum Käsud
klass. Käsud on järgmised: UUS_JAAM, UUS_SENSOR, MÕÕDA_SENSOR, JAAMADE_ÜHENDAMINE, EEMALDA_SENSOR, EEMALDA_JAAM
Funktsioon täidab järjest stringstream
objektis olevaid käske (mugav on kasutada switch
lauset).
Käske töötle järgmiselt:
UUS_JAAM
Peale käsukoodi on ilmajaama nimi. Loo uus ilmajaama objekt ja lisa see ilmajaamade vektorisse.
UUS_SENSOR
Peale käsukoodi on argumentideks varemloodud ilmajaama indeks ilmajaamade vektoris ja sensori nimi. Loo uus sensori objekt ilmajaamale (kasuta lisaSensor
) ja lisa sensor sensorite vektorisse.
MÕÕDA_SENSOR
Peale käsukoodi on argumentideks varemloodud ilmajaama indeks ilmajaamade vektoris ja sensori nimi. Rakenda sensorile funktsiooni mõõda
.
JAAMADE_ÜHENDAMINE
Peale käsukoodi on argumentideks esimese ja teise ilmajaama indeksid ilmajaamade vektoris. Ühenda kahe ilmajaama sensorid omavahel kasutades funktsiooni lisaSensorid
.
EEMALDA_SENSOR
Peale käsukoodi on argumendiks sensori indeks sensorite vektoris. Kustuta sensor temaga ühendatud ilmajaamadest, tühjenda sensori ilmajaamade vektor ning kustuta sensor sensorite vektorist.
EEMALDA_JAAM
Peale käsukoodi on argumendiks kustutatava ilmajaama indeks ilmajaamade vektoris. Kustuta ilmajaam ilmajaamade vektorist.
Automaatkontrollis ja ise testimiseks saab kasutada järgmisi funktsioone:
void test_ilm_1() { std::stringstream ss; int code = static_cast < int >(Käsud::UUS_JAAM); ss << code << ' ' << "Puhkekodu" << ' ' ; ss << code << ' ' << "Kontor" << ' ' ; code = static_cast < int >(Käsud::UUS_SENSOR); ss << code << ' ' << 0 << ' ' << "Sahver" << ' ' ; ss << code << ' ' << 1 << ' ' << "Koosolekuruum" << ' ' ; code = static_cast < int >(Käsud::EEMALDA_SENSOR); ss << code << ' ' << 0 << ' ' ; code = static_cast < int >(Käsud::MÕÕDA_SENSOR); ss << code << ' ' << 0 << ' ' << "Sahver" << ' ' ; int tulemus = ilm_main(ss); //std::println("test_ilm_1: {}", tulemus); std::cout << "test_ilm_1: " << tulemus << '\n' ; } void test_ilm_2() { std::stringstream ss; int code = static_cast < int >(Käsud::UUS_JAAM); ss << code << ' ' << "Puhkekodu" << ' ' ; ss << code << ' ' << "Kontor" << ' ' ; code = static_cast < int >(Käsud::UUS_SENSOR); ss << code << ' ' << 0 << ' ' << "Sahver" << ' ' ; ss << code << ' ' << 1 << ' ' << "Koosolekuruum" << ' ' ; code = static_cast < int >(Käsud::JAAMADE_ÜHENDAMINE); ss << code << ' ' << 0 << ' ' << 1 << ' ' ; code = static_cast < int >(Käsud::MÕÕDA_SENSOR); ss << code << ' ' << 0 << ' ' << "Koosolekuruum" << ' ' ; int tulemus = ilm_main(ss); //std::println("test_ilm_2: {}", tulemus); std::cout << "test_ilm_2: " << tulemus << '\n' ; } void test_ilm_3() { std::stringstream ss; int code = static_cast < int >(Käsud::UUS_JAAM); ss << code << ' ' << "Kasvuhoone_1" << ' ' ; code = static_cast < int >(Käsud::UUS_SENSOR); ss << code << ' ' << 0 << ' ' << "Tomatid" << ' ' ; ss << code << ' ' << 0 << ' ' << "Kurgid" << ' ' ; code = static_cast < int >(Käsud::MÕÕDA_SENSOR); ss << code << ' ' << 0 << ' ' << "Porgandid" << ' ' ; int tulemus = ilm_main(ss); //std::println("test_ilm_3: {}", tulemus); std::cout << "test_ilm_3: " << tulemus << '\n' ; } void test_ilm_4() { std::stringstream ss; int code = static_cast < int >(Käsud::UUS_JAAM); ss << code << ' ' << "Kasvuhoone_1" << ' ' ; ss << code << ' ' << "Kasvuhoone_2" << ' ' ; code = static_cast < int >(Käsud::UUS_SENSOR); ss << code << ' ' << 0 << ' ' << "Tomatid" << ' ' ; ss << code << ' ' << 1 << ' ' << "Kurgid" << ' ' ; code = static_cast < int >(Käsud::JAAMADE_ÜHENDAMINE); ss << code << ' ' << 0 << ' ' << 1 << ' ' ; code = static_cast < int >(Käsud::EEMALDA_JAAM); ss << code << ' ' << 0 << ' ' ; code = static_cast < int >(Käsud::MÕÕDA_SENSOR); ss << code << ' ' << 0 << ' ' << "Tomatid" << ' ' ; ss << code << ' ' << 0 << ' ' << "Kurgid" << ' ' ; int tulemus = ilm_main(ss); //std::println("test_ilm_4: {}", tulemus); std::cout << "test_ilm_4: " << tulemus << '\n' ; } void test_ilm_5() { std::stringstream ss; int code = static_cast < int >(Käsud::UUS_JAAM); ss << code << ' ' << "Puhkekodu" << ' ' ; ss << code << ' ' << "Kontor" << ' ' ; code = static_cast < int >(Käsud::UUS_SENSOR); ss << code << ' ' << 0 << ' ' << "Sahver" << ' ' ; ss << code << ' ' << 1 << ' ' << "Koosolekuruum" << ' ' ; code = static_cast < int >(Käsud::MÕÕDA_SENSOR); ss << code << ' ' << 0 << ' ' << "Sahver" << ' ' ; int tulemus = ilm_main(ss); // std::println("test_ilm_5: {}", tulemus); std::cout << "test_ilm_5: " << tulemus << '\n' ; } |
Kui funktsioonid üksteise järel välja kutsuda, võiks programmi väljund olla järgnev:
test_ilm_1: -2147483648 test_ilm_2: 17 test_ilm_3: -2147483648 test_ilm_4: 25 test_ilm_5: 19 |
Funktsioonide nimede/tüüpide kontroll
template < typename IntT, typename FloatT> concept arvudKorrektne = requires(std::weak_ptr<IntT> i, std::weak_ptr<FloatT> f) { { genereeri_arv() } -> std::same_as<std::unique_ptr<IntT>>; { proovi_arvu(i) } -> std::same_as<std::string>; { proovi_arvu(f) } -> std::same_as<std::string>; }; static_assert (arvudKorrektne< int , float >, "Arvude funktsioonid katki" ); template < typename PiltT> concept piltKorrektne = requires(PiltT pilt) { { PiltT{ "fail" } }; { pilt.m_andmed } -> std::same_as<std::unique_ptr< struct RGB[]> &>; { pilt.piksel(1, 2) } -> std::same_as< struct RGB &>; { pilt.salvesta( "fail" ) }; }; static_assert (piltKorrektne<PiltRGB>, "Pildi struktuur katki" ); template < typename PiltT> concept piltModKorrektne = requires(PiltT pilt) { { PiltT{ "fail" } }; { pilt.piksel(1, 2) } -> std::same_as< struct RGB &>; { pilt.lisa_kolmandik() }; { pilt.inverteeri() }; }; static_assert (piltModKorrektne<PiltRGB>, "Pildi funktsioonid katki" ); template < typename IlmajaamT, typename SensorT> concept ilmKorrektne = requires(IlmajaamT ilmajaam, SensorT sensor, std::shared_ptr<IlmajaamT> ilmajaamSharedPtr, std::weak_ptr<IlmajaamT> ilmajaamWeakPtr, std::string nimi) { { SensorT{nimi, ilmajaamWeakPtr} }; { sensor.mõõda() }; { sensor.lahti() }; { sensor.lisaJaam(ilmajaamWeakPtr) }; { IlmajaamT{nimi} }; { ilmajaam.m_sensorid } -> std::same_as<std::vector<std::shared_ptr<SensorT>> &>; { ilmajaam.mõõda(nimi) } -> std::same_as< int >; { ilmajaam.lisaSensorid(ilmajaamSharedPtr) }; { ilmajaam.lisaSensor(nimi) } -> std::same_as<std::weak_ptr<SensorT>>; { ilmajaam.eemalda(&sensor) }; }; static_assert (ilmKorrektne<Ilmajaam, Sensor>, "Ilmajaam või sensor katki" ); template < typename IlmajaamT, typename SensorT> concept ilmMainKorrektne = requires(IlmajaamT ilmajaam, SensorT sensor, std::weak_ptr<IlmajaamT> ilmajaamPtr, std::string nimi, std::stringstream ss) { { Käsud::UUS_JAAM }; { Käsud::UUS_SENSOR }; { Käsud::EEMALDA_SENSOR }; { Käsud::EEMALDA_JAAM }; { Käsud::MÕÕDA_SENSOR }; { Käsud::JAAMADE_ÜHENDAMINE }; { ilm_main(ss) }; }; static_assert (ilmMainKorrektne<Ilmajaam, Sensor>, "enum või ilm_main katki" ); |