Szorgalmi feladatok
A feladatok megoldásai az admin portálon adhatók be. A szorgalmi feladatokkal egy pontversenyben is részt lehet venni. Alapbeállítás szerint anonim módon jelensz meg a táblázatban. Ha szeretnél névvel megjelenni vagy teljesen eltűnni, az admin portálon beállíthatod.
A verseny állásának megtekintéséhez is be kell jelentkezni.
Teljes tört osztály
Dolgozd ki az előadáson bemutatott kódot folytatva a teljes tört osztályt C++ nyelven!
Valósítsd meg a + (egyoperandusú), +=, - (egy- és kétoperandusú), -=, *, *=, /, /=, >>, (double) cast operátorokat! Figyelj a referenciák helyes használatra!
Mennyi a legkevesebb új tagfüggvény (szintaktikai értelemben), amennyivel ez megoldható? Oldd meg úgy a feladatot, hogy a lehető legkevesebb legyen!
Figyelj arra, mit jelentenek az „egyoperandusú” és „kétoperandusú” szavak! Ezek nem az operátorokat megvalósító függvények paraméterszámát adják meg. Például egyoperandusú mínusz az ellentett: -x, és kétoperandusú mínusz a kivonás: a-b. Egyoperandusú csillag a dereferálás: *p, kétoperandusú csillag a szorzás: a*b.
Elfogadott megoldások: 14 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-09-14 23:59:00.
Oldd meg a "Morzekódot dekódoló tömb" feladatot a példatárból! https://cpp11.eet.bme.hu/f00/#1 A megoldásod tartalmazza
- a tömbbe rendezett fa kódját kiíró kódrészletet,
- magát a fát, amit a kódod legenerált,
- és a fa felhasználásával morze dekódolást végző főprogramot!
Ha tudod, a fát constexpr is létrehozhatod, az helyettesítheti az 1-2. pontot.
Elfogadott megoldások: 12 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-09-22 04:00:00.
Függvény osztály
Az előadás kifejezésfáival kapcsolatos feladat.
Tervezz és implementálj egy általános függvény osztályt! Hova illik ez be az osztályhierarchiába? Implementálj egy szinusz és egy koszinusz osztályt! Ha ügyesen tervezted meg a függvény osztályt, akkor ezek az összeghez és a szorzathoz hasonlóan pár sorból fognak állni.
Ha kész vannak a függvény, szinusz és koszinusz osztályok, akkor most írd meg azok deriválását is! Figyelj arra, hogy az összetett függvény deriválási szabályát kell alkalmaznod: f(g(x))'=f'(g(x))·g'(x), mert a szinusz vagy a koszinusz objektum is egy kifejezést tartalmaz.
Használd a függvénysablon tervezési mintát! Próbáld meg a függvény osztályban megvalósítani, amit csak lehet, hogy a leszármazottak minél egyszerűbbek legyenek. Onnan tudod, hogy jó a megoldásod, hogy a függvény ősosztály deriváló metódusa a láncszabályt tartalmazva final minősítőt kaphat (és csak ilyen megoldásra jár majd pont). Ugyanez a helyzet a print metódussal.
Elfogadott megoldások: 13 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-09-29 04:00:00.
Számrendszerek
Nézd meg az extrákban az I/O manipulátorokkal kapcsolatos írást! Ez az előadás mértékegységes példájának folytatása. Utána...
a) Írj bináris szám kiíró I/O manipulátort! A használata legyen az alábbi:
std::cout << bin << 0 << std::endl; /* 0 */
std::cout << bin << 240 << std::endl; /* 11110000 */
Vajon mi lehet itt a bin típusa?
b) Írj akárhányas számrendszerben kiíró I/O manipulátort!
std::cout << base(2) << 240 << std::endl; /* 11110000 */
std::cout << base(7) << 240 << std::endl; /* 462 */
std::cout << base(16) << 240 << std::endl; /* F0 */
Melyik az első részkifejezés, amit ki kell értékelnie a fordítónak? Indulj ki ebből!
Ügyelj arra, hogy a megvalósításban ne legyen pow() (egész számokkal kell dolgozni, a pow() pedig lebegőpontos számokkal dolgozik, pontatlanság lehet). Ezen kívül, ne legyen std::to_string() se! Legalábbis egyetlen számjegy sztringgé alakítására semmiképp, mivel akkor minden számjegyhez külön std::string objektum jönne létre. Általában véve, mindenféle dinamikus memóriakezelést elkerülhető.
Elfogadott megoldások: 15 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-10-13 04:00:00.
Hanoi tornyai
Adott az alábbi forráskód, amely a Hanoi tornyai feladványt oldja meg:
#include <iostream>
void hanoi(int n, char honnan, char seged, char hova) {
if (n == 0)
return;
hanoi(n-1, honnan, hova, seged);
std::cout << "rakj 1-et: " << honnan << "->" << hova << std::endl;
hanoi(n-1, seged, honnan, hova);
}
int main() {
hanoi(4, 'A', 'B', 'C');
return 0;
}
Hogy lehet megoldani azt, hogy minden lépés mellé ki legyen írva annak sorszáma? Pl. 3 korongra így:
1. lepes: rakj 1-et: A->C
2. lepes: rakj 1-et: A->B
3. lepes: rakj 1-et: C->B
4. lepes: rakj 1-et: A->C
5. lepes: rakj 1-et: B->A
6. lepes: rakj 1-et: B->C
7. lepes: rakj 1-et: A->C
Mutass minél többféle, egymástól eltérő elvű (nem csak szintaktikailag különböző) megoldást! A rekurzió maradjon meg. Mi a megoldásokban a közös?
Figyelj arra, hogy az elkészített függvények használatának módja – lényegében a fejléce – ugyanaz legyen, mint az eredeti függvényé (korongok száma, oszlop1, oszlop2, oszlop3)! Ez persze nem jelenti azt, hogy nem írhatsz segédfüggvényeket ettől eltérő paraméterezéssel. Ne csinálj tárolót, nincs rá szükség: a függvény olyan sorrendben állítja elő a lépéseket, ahogy a kimenetre is azoknak kerülniük kell.
Van két olyan „triviális” módszer, ami nélkül a beküldött kód nem lesz elfogadott. Sajnos ezek nem specifikálhatóak, mert ha a feladatkiírásban szerepelnének, akkor az a megoldást is elárulná egyből. Egyszerűségük miatt sejteni fogod, amikor megtaláltad őket, hogy ezekről van szó. Ha nem, számíts „találj ki még más elvű megoldást” értékelésre. Lásd az előadást is!
Elfogadott megoldások: 11 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-10-20 04:00:00.
std::optional
Néha szükségünk van egy olyan objektumra, amelyik egy jól meghatározott típusú értéket tárol – vagy éppenséggel üres. Például egy függvénynél, amelyik visszaad egy értéket, vagy nem ad vissza semmit. Ha sikerül beolvasnia egy számot, akkor visszaadja azt, ha nem, akkor pedig csak egy üres objektumot.
Ezt meg tudjuk oldani dinamikus memóriakezeléssel is. De ebben az esetben az kényelmetlen és lassú: egyetlen egy int-et kellene dinamikusan foglalni, indirekten visszaadni stb. Ehelyett inkább egy olyan objektumra lenne szükségünk, amelyik ezt érték szerint tartalmazza, és tudja azt is, hogy üres-e vagy nem. A használatát így képzelhetjük el:
Optional<std::string> get_string_from_stdin();
int main() {
Optional<std::string> opt = get_string_from_stdin();
if (opt) {
std::cout << "Ezt a sztringet kaptam: " << *opt << std::endl;
} else {
std::cout << "Nem kaptam sztringet" << std::endl;
}
}
A tárolt érték típusa std::string, de a sablonparaméter miatt lehetne bármi más.
Készíts egy ilyen osztályt! Ügyelj az alábbiakra:
- Nem használhatsz dinamikus memóriakezelést, mert akkor elveszik a feladat értelme.
- Helyette egy
sizeof(T)méretű tömböt kell azOptionalobjektumba tenni, és neked kell tudnod, hogy ott épp létre van hozva objektum vagy nincs. - Ügyelni kell arra is, hogy a tömb megfelelő módon helyezkedjen el a memóriában. Előfordulhat, hogy a
Ttípusra vonatkoznak ilyen megkötések (pl.inttípus 4-gyel osztható memóriacímen). A memóriabeli igazítás azalignaskulcsszóval oldható meg. - Az
Optionalobjektum megszűntekor a tartalmazottTdestruktorát is meg kell hívni, már amennyiben volt tartalmazottT.
Tesztesetek nincsenek megadva, azokat neked kell kitalálnod. Vajon mi várható el egy ilyen osztálytól? Gondolj arra, hogy egy Optional 0 vagy 1 darab objektumot tartalmaz érték szerint, és azt az objektumot helyettesíti. Érdemes a kódodat GCC/Clang -fno-elide-constructors fordítási paraméter mellett tesztelni, hogy kikapcsold a hibákat elfedő optimalizációkat!
A C++17 óta egyébként van ilyen osztály, std::optional néven. Ez a Boost optional osztály mintájára készült.
Elfogadott megoldások: 12 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-10-27 04:00:00.
Összefésülő rendezés
Az összefésülő rendezés (merge sort, lásd Prog1/Algel, https://preview.redd.it/ke79d99ynaz11.png?auto=webp&s=6563c537f3098e81c614c6284cd39628e4151d9e) lényege a következő:
- Rekurzívan rendezzük a tömb első és második felét.
- Ezek után pedig a két különálló, rendezett tartományt összefésüljük egyetlen rendezett tartománnyá.
Alább egy megvalósítás int-ek tömbjére.
void merge(int *in, int begin, int mid, int end, int *out) {
int i = begin, j = mid;
for (int c = begin; c < end; ++c) {
if (i < mid && (j >= end || in[i] <= in[j])) {
out[c] = in[i];
i++;
} else {
out[c] = in[j];
j++;
}
}
}
void copy(int *in, int begin, int end, int *out) {
for (int c = begin; c < end; ++c) {
out[c] = in[c];
}
}
void merge_sort(int *tomb, int begin, int end, int *temp) {
if (end - begin < 2)
return;
int mid = (begin + end) / 2;
merge_sort(tomb, begin, mid, temp);
merge_sort(tomb, mid, end, temp);
merge(tomb, begin, mid, end, temp);
copy(temp, begin, end, tomb);
}
Az összefésüléshez szükséges egy segédtömb: a két fél tartomány az összefésülés (merge) során a segédtömbbe kerül, ahonnan aztán vissza kell másolni (copy). A fenti rendező függvény ezért elvárja a hívójától, hogy kapjon egy munkaterületet, amelyik az eredeti tömb méretével megegyező méretű.
Végezd el az alábbi módosításokat a kódon!
- Template-esítsd: ne inteken dolgozzon, hanem tetszőleges típusú elemeken. Természetesen a <, >= stb. operátorokat attól a típustól elvárhatod.
- Csinálj egy csomagoló függvényt, amely lefoglalja magától a megfelelő méretű segédtömböt, hogy ezzel ne a hívónak kelljen bajlódnia!
- Figyeld meg, hogy az összefésülésnél a segédtömbbe MÁSOLÓDNAK az objektumok, aztán onnan az eredeti helyükre visszaMÁSOLÓDNAK megint. Ezeknek a lépéseknek nem másolásnak, hanem mozgatásoknak kellene lenniük. Alakítsd át úgy a kódot, hogy (1) a segédtömb inicializálatlan memóriaterület legyen, amelyre (2) az összefésülés átmozgatja az objektumokat, és ahonnan végül a lecserélt copy függvény (3) az eredeti tömbbe, a végleges helyükre visszamozgatja azokat!
Figyelj arra, hol használsz konstruktort, destruktort és értékadást! A megoldásod az extrák menüpont alatt elérhető SuperNoisy osztállyal is tesztelheted. Figyelj arra, hogy a rendezendő tömb elemeinek lehet, hogy nincs default konstruktora!
Elfogadott megoldások: 11 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-11-03 04:00:00.
Noexcept függvények
A főprogramban két kódrészlet van. Külön kell őket vizsgálnod. Melyiknél mi történik? Miért?
#include <iostream>
struct X {
X() = default;
X(X const &) { throw 0; }
};
void f_val(X param) noexcept {
}
void f_ref(X const & param) noexcept {
X copy(param);
}
int main() {
X x1;
try {
std::cout << "f_val hivasa" << std::endl;
f_val(x1);
} catch (...) {}
try {
std::cout << "f_ref hivasa" << std::endl;
f_ref(x1);
} catch (...) {}
}
Elfogadott megoldások: 15 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-11-10 04:00:00.
Noexcept mozgató konstruktor
Mi a hiba az alábbi programrészben? Kettőt is tudsz mutatni!
class String {
/* ... */
};
String::String(String && moved) noexcept {
data_ = moved.data_;
len_ = moved.len_;
moved.data_ = new char[1];
moved.data_[0] = '\0';
moved.len_ = 0;
}
Elfogadott megoldások: 14 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-11-10 04:00:00.
Függvény építése RPN kifejezésből
Az RPN jelölésben (Reverse Polish Notation) az operátorokat az operandusokat után írjuk: "2 3 +" jelentése 2+3, és "2 3 + x *" jelentése (2+3)*x. Egy ilyen kifejezés egy veremmel könnyen kiértékelhetjük. Pl. konstans feldolgozásához bedobjuk a verembe a számot, műveletnél pedig a verem tetején lévő két számot kell kivenni, elvégezni a műveletet, és az eredményt visszatenni a verembe. A műveletsor végére egyetlen egy szám kell legyen a veremben, ami az eredmény.
Ha függvényt kell előállítani, pl. "2 3 + x *" → (2+3)*x, akkor ugyanígy lehet gondolkodni, csak a veremben függvényeknek kell lenniük. Ebben a feladatban ezt kell megoldanod. Kell egy olyan függvényt írnod, amelyik megkapja a sztringet, és visszatér egy egyváltozós matematikai függvénnyel. Ez utóbbi bárhányszor meghívható, különböző x értékekkel:
auto f = create_func_from_rpn("21.7 34.2 x * +"); // f = 21.7+34.2*x
std::cout << f(3) << std::endl; // 21.7+34.2*3 értéke
std::cout << f(4) << std::endl; // 21.7+34.2*4 értéke
std::cout << f(5) << std::endl; // 21.7+34.2*5 értéke
Oldd meg ezt úgy, hogy 1) a sztringet csak egyszer dolgozod fel, a create_func_from_rpn() függvényhíváskor, 2) nem definiálsz saját osztályt, tisztán csak beépített eszközöket használsz! Írj std::move-ot, ahova csak lehet!
Ne bonyolítsd, és ne implementáld újra a szabványos könyvtárat: egy képernyőre elfér a kód.
Elfogadott megoldások: 14 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-11-17 04:00:00.
print()
A feladat egy olyat print() függvénycsaládot írni, amelyik meg tudja különböztetni, más formátumban írja ki a számokat, a karaktereket és a sztringeket.
- A számokat (
int,double, egyebek) önmagukban, pl. 5 vagy 5.1. - A karaktereket (pl.
charvagychar16_t) aposztrófok között: 'a'. - A sztringeket (pl.
char*vagystd::string) pedig idézőjelek között: "hello". - Egyéb típusokat ne lehessen kiírni vele.
A feladatot sablon metaprogramozással oldd meg!
Útmutatás. Elvileg csak három print() függvényre lesz szükséged, amelyek közül mindig valamelyiket az std::enable_if engedélyezi, a többit tiltja. Nézz szét a type_traits dokumentációjában, milyen sablonokat tudsz felhasználni és miket kell magadnak megírnod. Figyelned kell arra is, hogy T és T const eltérő típusok, ugyanakkor vissza lehet vezetni egyiket a másikra. És arra, hogy ne zsúfolj mindent a print()-ek fejlécébe; ha kell, írj segédfüggvényeket (metafüggvényeket)!
Elfogadott megoldások: 13 darab.
Szerezhető: 1 pont. Leadási határidő: 2025-11-24 04:00:00.
Type traits – nyelvismereti verseny
Alább egy type trait sablonosztály: ez megmondja a példányosító típusról, hogy osztály-e. Lényegében az előadás kódja becsomagolva.
#include <iostream>
template <typename T>
class IsClass {
private:
template <typename U>
static constexpr bool helper(int U::*) { return true; }
template <typename U>
static constexpr bool helper(...) { return false; }
public:
static constexpr bool value = helper<T>(0);
};
int main() {
std::cout << IsClass<int>::value;
std::cout << IsClass<std::ostream>::value;
}
Implementálj az alábbi trait osztályok közül amennyit csak tudsz!
IsDerived<Base, Derived>::value: leszármazottja-e (ez laborfeladat is).IsSame<A, B>::value: ugyanaz a típus-e.IsFunction<T>::value: függvény-e, pl. int(bool) függvény, mert int f(bool);IsArray<T>::value: igaz, ha T tömb.RemoveExtent<T>::type: levesz a tömbből egy dimenziót. T[x]→T, T[x][y]→T[x].RemoveAllExtents<T>::type: az összes dimenziót leveszi: T[x][y]...→T, amúgy általában T→T.ArrayDimensions<T>::value: a tömb dimenzióinak száma, pl. T[x][y][z] esetén 3.IsIterable<T>::value: megeszi-e az std::begin() függvény.HasRandomAccessIterator<T>::value: mint az előző, de az is feltétel, hogy random access iterálható legyen.IsCopiable<T>::value: van-e másoló konstruktora (a konstruktora átvesz-e balértéket, pl. az std::cout nem másolható).IsMovable<T>::value: van-e mozgató konstruktora (átvesz-e jobbértéket). (Lehet, hogy ilyenkor is másolás történik, de nem azt kell ellenőrizni.)IsPolymorphic<T>::value: van-e virtuális függvénye.IsEmptyClass<T>::value: igaz, ha üres a T osztály, nincs adattagja, pl. struct X {}.IsEnum<T>::value: igaz, ha egy enum, amúgy hamis.IsAbstract<T>::value: igaz, ha T absztrakt osztály, amúgy hamis.Decay<T>::type: a benne lévő típus a T típus függvényparaméter átadáskori transzformáltja, pl. int const → int, int[10] → int*, int& → int.IsSigned<T>::value: igaz, ha a T típus előjeles egész (bármekkora), hamis, ha nem előjeles. (Csak egész típusokra kell működjön.)
A megoldások nyers nyelvi eszközökre épüljenek, ne beépített makrókra, és ne STL-re! Nem baj, ha patologikus körülmények között nem működnek. Szabad nem előírt, de „elvárható” fordítói képességekre támaszkodni.
Ha néhányat megcsináltál, szorgalmi pontért beadhatod a megoldást. Szabványos fejlécfájlokból, boost-ból ne puskázz! Ha neten utánanézel dolgoknak, az se direktben a megoldás legyen, úgy nincs értelme. A beadott forráskódban a feladatban szereplő sorrendben legyenek a megoldások! Ha segédosztályokat, segédfüggvényeket használsz, azokat mind rejtsd az osztályok belsejébe!
Értékelés: legalább a fele megvan (és jó) → 1 pont. Majdnem az összes megvan (1-2 hiányzó vagy hibás) → 2 pont.
Elfogadott megoldások: 7 darab.
Szerezhető: 2 pont. Leadási határidő: 2025-12-08 04:00:00.
Saját std::function
Írd meg az std::function-t! Ha mindent jól csinálsz, akkor az alábbi kódban az std::function helyére my_function-t írhatsz majd:
#include <functional>
#include <iostream>
#include <cmath>
int main() {
std::function<double(double)> f;
if (!f)
std::cout << "Egyelőre nullptr" << std::endl;
f = sin;
std::cout << sin(2.3) << "==" << f(2.3) << std::endl;
f = [] (double x) { return x*x; };
std::cout << 2.3*2.3 << "==" << f(2.3) << std::endl;
f = std::bind(pow, std::placeholders::_1, 4);
std::cout << pow(2.3, 4) << "==" << f(2.3) << std::endl;
auto f2 = f; /* másolható */
std::cout << pow(2.3, 4) << "==" << f2(2.3) << std::endl;
f = nullptr;
try {
f(2.3);
} catch (std::bad_function_call &e) {
std::cout << "Megint nullptr" << std::endl;
}
}
Ehhez az osztályodnak egy olyan operator= kell, amelyik tetszőleges objektumot (függvénypointert, lambdát, ...) át tud venni, és le tud másolni. Ezért a lemásolt objektumot be kell majd csomagolnod egy osztályba, aminek típusa a lemásolt objektumtól függ – klasszikus type erasure.
Figyelj arra, hogyan adod át a becsomagolt függvénynek a paramétereket! Meg arra is, hogy egy std::function lemásolásakor lemásolódik a bele csomagolt funktort is. Ez azért fontos, mert a funktornak belső állapota lehet. Az std::function ilyen jellegű viselkedését is tudnia kell az osztálynak.
Értékelés:
- Működő megoldás 1 pontot ér.
- Hatékony, egyszerű, >=C++11 elemeit jól használó megoldás 2 pontot.
Elfogadott megoldások: 7 darab.
Szerezhető: 2 pont. Leadási határidő: 2025-12-01 04:00:00.
Polimorf típus
Tudjuk, hogy heterogén kollekcióhoz szükségünk van egy indirekcióra az objektumok eltérő típusa és mérete miatt. Ez kényelmetlen, mert a plusz indirekció és az ismeretlen típus is nehézkessé teszi az objektumok érték szerinti kezelését. A másolás megoldható egy clone() segédfüggvénnyel, amit virtuális konstruktorként emlegetünk, még ha valójában nem is konstruktor. Az érték szerint kezeléshez pedig az előadáson készítettünk egy segédosztályt, amely másoláskor az objektum clone() függvényét hívja:
template <typename BASE>
class PolymorphicValue {
private:
BASE *ptr_;
public:
explicit PolymorphicValue(BASE *ptr = nullptr): ptr_{ptr} {}
~PolymorphicValue() {
delete ptr_;
}
PolymorphicValue(PolymorphicValue const & masik) {
if (masik.ptr_ != nullptr)
ptr_ = masik.ptr->clone(); /* itt a lényeg */
else
ptr_ = nullptr;
}
/* ... */
};
Ezzel persze egy új elvárásunk van a tartalmazni kívánt típus felé: legyen clone() függvénye:
class Shape {
public:
virtual Shape * clone() const = 0;
/* ... */
};
class Triangle: public Shape { /* ... */ };
class Rectangle: public Shape { /* ... */ };
PolymorphicValue<Shape> s1(new Rectangle);
PolymorphicValue<Shape> s2 = s1; /* p1.ptr_->clone() */
Erre azért van szükség, mert a PolymorphicValue osztály konstruktora Shape * paramétert kap, és nem ismeri a lemásolandó objektum típusát. Az intruzív megvalósítás azonban nem előnyös: A PolymorphicValue feladata, a memóriakezelés egy része bekerült a Shape osztályba és annak leszármazottaiba.
Viszont ha más megközelítéssel indulnánk neki a feladat megoldásának, ismerhetné a típust. Ha sablon lenne a PolymorphicValue konstruktora, akkor átvehetné érték szerint is az objektumot, amelyet tartalmazni kell, és ismert lenne a típusa is:
PolymorphicValueV2<Shape> s1( Rectangle{} ); /* template-es ctor */
PolymorphicValueV2<Shape> s2( Triangle{} );
PolymorphicValueV2<Shape> s3 = s1; /* Rectangle copy ctor, Triangle copy ctor */
PolymorphicValueV2<Shape> s4 = s1;
s3->get_area(); /* Shape* és Shape& */
(*s3).get_area();
Oldd meg, hogy ez így működjön! Ehhez szükséged lesz egy type erasure-re is, amiről előadáson esett szó. Ha mindent jól csinálsz, a clone() függvény törölhető lesz; a PolymorphicValueV2 osztályod közvetlenül a tartalmazott objektum másoló konstruktorát fogja használni, és semmilyen egyéb függvényt nem vár annak interfészén.
Vigyázat: ez egy nehéz feladat, nem véletlenül két pontos. Az értékelés:
- 0 pont, ha nem teljes, vagy nem működik a program
- 1 pont, ha működik, de nem hatékony, vagy nagyon nem letisztult a kód
- 2 pont, ha működik és hatékony
Elfogadott megoldások: 5 darab.
Szerezhető: 2 pont. Leadási határidő: 2025-12-08 04:00:00.