diff options
| author | Syndamia <kamen@syndamia.com> | 2024-04-22 13:52:55 +0300 |
|---|---|---|
| committer | Syndamia <kamen@syndamia.com> | 2024-04-22 13:52:55 +0300 |
| commit | f7ed9a8a6c31b17d54d2f37cc0f12b64f8e4b6d2 (patch) | |
| tree | 866abf46779f63a2fd1c8cfc70f7ff5f3bc11752 /week09 | |
| parent | a2e284b0056075e2365deaa2455be567c3b3c945 (diff) | |
| download | oop-2023-solutions-f7ed9a8a6c31b17d54d2f37cc0f12b64f8e4b6d2.tar oop-2023-solutions-f7ed9a8a6c31b17d54d2f37cc0f12b64f8e4b6d2.tar.gz oop-2023-solutions-f7ed9a8a6c31b17d54d2f37cc0f12b64f8e4b6d2.zip | |
[w9] Added exercise descriptions and solution to exam 1
Diffstat (limited to 'week09')
| -rw-r--r-- | week09/Exam1/Drone.cpp | 140 | ||||
| -rw-r--r-- | week09/Exam1/Drone.h | 34 | ||||
| -rw-r--r-- | week09/Exam1/DroneShow.cpp | 100 | ||||
| -rw-r--r-- | week09/Exam1/DroneShow.h | 28 | ||||
| -rw-r--r-- | week09/Exam1/main.cpp | 79 | ||||
| -rw-r--r-- | week09/README.md | 104 |
6 files changed, 485 insertions, 0 deletions
diff --git a/week09/Exam1/Drone.cpp b/week09/Exam1/Drone.cpp new file mode 100644 index 0000000..6895a74 --- /dev/null +++ b/week09/Exam1/Drone.cpp @@ -0,0 +1,140 @@ +#include "Drone.h" +#include <cstring> +#include <fstream> +#include <iostream> + +/* Голяма четворка */ + +void Drone::free() { + delete[] id; +} +void Drone::copyFrom(const Drone& other) { + id = new char[strlen(other.id) + 1]; + strcpy(id, other.id); + strcpy(generatedPath, other.generatedPath); + position = other.position; +} + +Drone::Drone() { + id = nullptr; + generatedPath[0] = '\0'; + position = 0; +} +Drone::~Drone() { + free(); +} +Drone::Drone(const Drone& other) { + copyFrom(other); +} +Drone& Drone::operator=(const Drone& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +/* Move семантики */ + +Drone::Drone(Drone&& other) { + id = other.id; + other.id = nullptr; + + strcpy(generatedPath, other.generatedPath); + position = other.position; +} + +Drone& Drone::operator=(Drone&& other) { + if (this != &other) { + free(); + + id = other.id; + other.id = nullptr; + + strcpy(generatedPath, other.generatedPath); + position = other.position; + } + return *this; +} + +/* Метод от 1.2 */ +void Drone::printGeneratedPath() { + std::ifstream inFile(generatedPath, std::ios::binary); + if (!inFile.is_open()) { + throw "Could not open generatedPath!"; // ок е и вместо това да се направи "return;" + } + + while(!inFile.eof()) { + double x, y; + // Не е казано формата на този файл какъв е, затова допускаме най-простия възможен: + // една голяма последователност от double-и, първия е х1, втория е y1, третия е x2, четвъртия е y2 и так. нат. + inFile.read((char*)&x, sizeof(x)); + inFile.read((char*)&y, sizeof(y)); + + std::cout << x << ", " << y << std::endl; + } + + inFile.close(); +} + +/* Метод от 1.2 */ +Coordinate Drone::moveWithOneStep() { + std::ifstream inFile(generatedPath, std::ios::binary); + if (!inFile.is_open()) { + throw "Could not open generatedPath!"; // ок е вместо това да бъде "return;" + } + + double x, y; + for (int i = 0; i <= position + 1 && !inFile.eof(); i++) { + inFile.read((char*)&x, sizeof(x)); + inFile.read((char*)&y, sizeof(y)); + } + // Ако във файла не съществува координат на position+1 + if (inFile.eof()) { + inFile.close(); + throw "No next position"; + } + + std::cout << x << ", " << y << std::endl; + + position++; + inFile.close(); + return { x, y }; // Еквивалентно на "return Coordinate({ x, y });" +} + +/* Помощна за 2.2, метод play */ +// Кодът е почти еднакъв с moveWithOneStep, обаче при moveWithOneStep първо местим и връщаме новата позиция, +// докато тук връщаме сегашната и след това местим +// Хубаво е логиката да се изкара в някаква обща член-функция, но като за контролно така е коректно +Coordinate Drone::positionAndMove() { + std::ifstream inFile(generatedPath, std::ios::binary); + if (!inFile.is_open()) { + throw "Could not open generatedPath!"; // ок е вместо това да бъде "return;" + } + + double x, y; + // vvvvvvvvvvv ето тук е единствената разлика с moveWithOneStep + for (int i = 0; i <= position && !inFile.eof(); i++) { + inFile.read((char*)&x, sizeof(x)); + inFile.read((char*)&y, sizeof(y)); + } + // Ако във файла не съществува координат на position+1 + if (inFile.eof()) { + inFile.close(); + throw "No next position"; + } + + std::cout << x << ", " << y << std::endl; + + position++; + inFile.close(); + return { x, y }; // Еквивалентно на "return Coordinate({ x, y });" +} + +/* Помощна за 3.1 */ +Drone::Drone(const char* id, char generatedPath[64], int position) { + this->id = new char[strlen(id)+1]; + strcpy(this->id, id); + strcpy(this->generatedPath, generatedPath); + this->position = position; +} diff --git a/week09/Exam1/Drone.h b/week09/Exam1/Drone.h new file mode 100644 index 0000000..a45cceb --- /dev/null +++ b/week09/Exam1/Drone.h @@ -0,0 +1,34 @@ +// Помощна структура за метода moveWithOneStep +struct Coordinate { + double x; + double y; +}; + +class Drone { + // +0.25 За член данни + char* id; + char generatedPath[64]; + // Валидна интерпретация е position да бъде индекс, нищо не му противоречи + int position; + + // +1.25 За голяма петица + void free(); + void copyFrom(const Drone& other); +public: + Drone(); + ~Drone(); + Drone(const Drone& other); + Drone& operator=(const Drone& other); + Drone(Drone&& other); + Drone& operator=(Drone&& other); + + // +0.50 За метод + void printGeneratedPath(); + // +0.50 За метод + Coordinate moveWithOneStep(); + + // Помощна за 2.2, метод play + Coordinate positionAndMove(); + // Помощна за 3.1 + Drone(const char* id, char generatedPath[64], int position); +}; diff --git a/week09/Exam1/DroneShow.cpp b/week09/Exam1/DroneShow.cpp new file mode 100644 index 0000000..aaffc8f --- /dev/null +++ b/week09/Exam1/DroneShow.cpp @@ -0,0 +1,100 @@ +#include "DroneShow.h" +#include <iostream> +#include <cstring> + +/* Голяма петица */ +void DroneShow::free() { + delete[] name; +for (int i = 0; i < 1024; i++) { + delete drones[i]; + } +} +void DroneShow::copyFrom(const DroneShow& other) { + name = new char[strlen(other.name) + 1]; + strcpy(name, other.name); + for (int i = 0; i < 1024; i++) { + drones[i] = new Drone(*other.drones[i]); + } +} + +DroneShow::DroneShow() { + name = nullptr; + for (int i = 0; i < 1024; i++) { + drones[i] = nullptr; + } +} + +DroneShow::~DroneShow() { + free(); +} + +DroneShow::DroneShow(const DroneShow& other) { + copyFrom(other); +} + +DroneShow& DroneShow::operator=(const DroneShow& other) { + if (this != &other) { + free(); + copyFrom(other); + } + return *this; +} + +DroneShow::DroneShow(DroneShow&& other) { + this->name = other.name; + other.name = nullptr; + + for (int i = 0; i < 1024; i++) { + this->drones[i] = other.drones[i]; + other.drones[i] = nullptr; + } +} + +DroneShow& DroneShow::operator=(DroneShow&& other) { + if (this != &other) { + free(); + + this->name = other.name; + other.name = nullptr; + + for (int i = 0; i < 1024; i++) { + this->drones[i] = other.drones[i]; + other.drones[i] = nullptr; + } + } + return *this; +} + +/* Метод от 2.2 */ +bool DroneShow::isEmpty(int index) { + return drones[index] == nullptr; +} + +/* Конструктор от 2.2 */ +DroneShow::DroneShow(const char* name, Drone* drones[1024]) { + this->name = new char[strlen(name) + 1]; + strcpy(this->name, name); + for (int i = 0; i < 1024; i++) { + this->drones[i] = new Drone(*drones[i]); // Директно извикваме копиращия конструктор + } +} + +/* Метод от 2.2 */ +void DroneShow::play() { + try { + while(true) { // за всяка стъпка от шоуто + for (int i = 0; i < 1024; i++) { // за всеки дрон + if (isEmpty(i)) continue; // правим го за да не пишем код в още къдрави скоби + + // Всички дронове имат еднакъв брой въведени позиции, тоест първият дрон, + // който се опита да отиде на следваща несъществуваща позиция ще хвърли грешка и това описва + // края на шоуто + Coordinate c = drones[i]->positionAndMove(); + std::cout << c.x << ", " << c.y << std::endl; + } + } + } + catch(const char* error) { + // Няма какво да правим по условие + } +} diff --git a/week09/Exam1/DroneShow.h b/week09/Exam1/DroneShow.h new file mode 100644 index 0000000..fd7e880 --- /dev/null +++ b/week09/Exam1/DroneShow.h @@ -0,0 +1,28 @@ +#include "Drone.h" + +class DroneShow { + char* name; // ок ако има голяма петица и нужните проверки, иначе трябва да е "char name[128]" + // масив от указатели, ако е nullptr значи няма дрон, иначе има + // това е по-добра интерпретация от това във всеки дрон да пазим "isEmpty" булева стойност или подобно, понеже + // пише че на позиция може да *няма* дрон, тоест аргумент е ако има дефолтен дрон пак да кажем, че има + Drone* drones[1024]; + + // Голямата петица не дава директно точки, но отнема + // Щом имаме динамична памет, тогава ЗАДЪЛЖИТЕЛНО трябва да имаме голяма петица + void free(); + void copyFrom(const DroneShow& other); +public: + DroneShow(); + ~DroneShow(); + DroneShow(const DroneShow& other); + DroneShow& operator=(const DroneShow& other); + DroneShow(DroneShow&& other); + DroneShow& operator=(DroneShow&& other); + + // +0.15 за метод + bool isEmpty(int index); + // +0.50 за конструктор; не са ни дадени ограничения, затова правим възможно най-простия такъв + DroneShow(const char* name, Drone* drones[1024]); + // +0.35 за метод + void play(); +}; diff --git a/week09/Exam1/main.cpp b/week09/Exam1/main.cpp new file mode 100644 index 0000000..1d62051 --- /dev/null +++ b/week09/Exam1/main.cpp @@ -0,0 +1,79 @@ +#include "DroneShow.h" +#include <iostream> +#include <fstream> + +/* Относно условието с dronesPath.txt, напълно валидна интерпретация е, че просто + * пренасяме информация от файл на име dronesPath.txt в друг с име, въведено от потребителя. + * Друга интерпретация е, че пътищата трябва да се изкарат в различни файлове за всеки дрон, или пък + * да разширим Drone класа, така че да работи с такъв файл или с директен обект който пази пътя. + * + * Всички тези са валидни, ако се зачетете в условието, нищо което е директно казано не противоречи, + * на вас остава да решите кое искате да имплементирайте. + * На мен ми се струва, че първото изисква възможно най-малко труд, така че това съм направил. + */ +void dronesPathLogic() { + std::ifstream inFile("dronesPath.txt"); + if (!inFile.is_open()) return; + + char outName[1024]; + std::cin.getline(outName, 1024); + + std::ofstream outFile(outName, std::ios::binary); + if (!outFile.is_open()) return; + + while(!inFile.eof()) { // за всеки път в dronesPath.txt + int currentSize = 0; + + // Намираме дължината на сегашния път + // Възможно е да го напрваим с оразмеряващ се масив в който пълним всички координати, но това ми се струва повече писане + int startPos = inFile.peek(); + while (inFile.peek() != '\n' && !inFile.eof()) { // докато не сме стигнали края на пътя + currentSize++; + double x, y; + inFile >> x >> y; // "пропускаме" сегашния координат + } + inFile.clear(); // Ако сме стигнали края на файла, fail флагът ще бъде вдигнат, така го сваляме + inFile.seekg(startPos, std::ios::beg); // Намерили сме дължината, но сега ще трябва да изкараме всички координати + + // Не е казано как трябва да изглежда файла в който пишем, затова правим най-простото нещо: + // първо пишем дължината на пътя (брой координати) и след това толкова на брой координати + // Имайки предвид, че е двоичен, не можем да имаме разделител ей-така, за да определим кога + // един път почва и друг свършва. + outFile.write((char*)¤tSize, sizeof(currentSize)); + + while (inFile.peek() != '\n' && !inFile.eof()) { + double x, y; + inFile >> x >> y; + outFile.write((char*)&x, sizeof(x)); + outFile.write((char*)&y, sizeof(y)); + } + } + + inFile.close(); + outFile.close(); +} + +int main() { + char bufferName[1024], bufferGeneratedPath[1024]; + Drone* drones[1024]; + + for (int i = 0; i < 1024; i++) { + std::cin.getline(bufferName, 1024); + std::cin.getline(bufferGeneratedPath, 1024); + int position; + std::cin >> position; + std::cin.ignore(); + + drones[i] = new Drone(bufferName, bufferGeneratedPath, position); + } + + dronesPathLogic(); + + std::cin.getline(bufferName, 1024); + DroneShow ds(bufferName, drones); + ds.play(); + + for(int i = 0; i < 1024; i++) { + delete drones[i]; + } +} diff --git a/week09/README.md b/week09/README.md new file mode 100644 index 0000000..bbb5121 --- /dev/null +++ b/week09/README.md @@ -0,0 +1,104 @@ +# Задачи - ООП, Седмица 9, 18.04.2024 + +*Този файл е копие на задачите от: [syndamia.com/teaching/oop-2023/week9](https://syndamia.com/teaching/oop-2023/week9)* + +На днешното упражнение ще решаваме [задачата от Контролно 1](https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=311448), затова задачите ще са в същия дух (макар и да не включват най-новия материал). + +## Преговорни + +### Задача 1 - Голяма петица + +Реализирайте клас Printer, който съдържа модел като низ с произволна дължина и брой принтирани страници като неотрицателно цяло число. +Имплементирайте голяма петица. + +### Задача 2 - Файлове и класове + +Реализирайте клас Date, който съдържа номера на деня, месеца и годината в три отделни целочислени член-данни. +Имплементирайте член-методи `storeText`, `storeBinary`, които съответно запазват данните в текстов файл (във формата "YEAR MONTH DAY") и в двоичен файл с подадени имена. +Аналогично имплементирайте `loadText` и `loadBinary`, които презаписват член-данните с тези от подадените (имена на) файлове. + +В главната функция създайте 5 дати, запазете всяка в **един и същ текстов файл**, след това прочетете датите в **нови** 5 променливи и изкарайте датите в обратен ред. + +## Лесни + +### Задача 3 + +Реализирайте клас Train, който съдържа: + +- модел като низ с максимална дължина от 127 знака +- идентификационен номер на релсовата линия върху която се намира, като целочислена неотрицателна стойност +- име на текстов файл, съдържащ всички райони от сегашната релсова линия, всеки на нов ред. + Самото име представяйте като низ с произволна дължина. +- сегашна локация (район) от релсовата линия като низ с произволна дължина. + Тази локация не се подава, и при създаване на обекта винаги е първата във файла. + +Имплементирайте методите: + +- от голямата петица +- `TransferNextRegion`, който променя сегашната локация на следващата по ред в текстовия файл (чието име е подадено в конструктор). + Ако няма следващо по ред, тогава локацията да си остане същата и да се хвърли грешка. + Ако се срещнат проблеми с файла, хвърлете грешка. +- `SwitchRailLine`, който приема идентификационен номер на релсовата линия и име на текстов файл, и променя вътрешните стойности. + Съответно локацията трябва да бъде първата в подадения файл. + Ако се срещнат проблеми с файла, хвърлете грешка. + +Реализирайте клас TrainNetwork, който съдържа: + +- идентификационен код, като низ с максимална дължина от 7 знака +- масив, запазващ максимум 511 влака (типа се оставя по ваша преценка) + +За този клас имплементирайте методите: + +- `HaveCollided`, който приема индекс на два влака и връща дали са се блъснали. + Това се случва ако в една и съща релсова линия и един и същи регион, когато регионът не е последния възможен. +- `RunTrains`, който придвижва напред всички влакове, докато не стигнат финалната си възможна дестинация. + Влакове които са се ударили не се придвижват напред. + Връщате броя ударили се влакове. + +Да се имплементира главна функция, в която приемате име на двоичен файл от потребителя. +В този файл имате някакъв брой редици с идентификационен номер на релсова линия, брой локации върху съответната линия и всички локации като нормални низове, разделени с нови редове. + +Допълнително в главната функция приемайте от потребителя влаковете, като имената на текстовите файлове се избират от програмата (**НЕ** от потребителя) според идентификационния номер на релсовата линия и информацията във файла с редиците. +**Не може да променяте Train класа!** + +Последно в главната функция създайте обект от тип TrainNetwork и изкарайте резултата от `RunTrains` на екрана. + +## Трудни + +### Задача 4 + +Реализирайте клас Car, в който се запазват: + +- марка като низ с максимум 31 знака +- модел като низ с произволна дължина +- брой седалки като положително цяло число +- гладност на човека на всяка седлка като целочислен масив с размер броя седалки + +Имплементирайте методи: + +- от голямата петица +- `AddPassenger`, който добавя нов човек на дадения индекс на седалка +- `RemovePassenger`, който премахва човека от дадения индекс +- `TotalHunger`, който връща общото количество гладност в колата +- `StoreData`, който запазва всички данни от колата в **двоичен** файл с подадено име +- `LoadData`, който презаписва всички данни с тези от подадения по име **двоичен** файл + +Реализирайте клас DriveThrough, в който се запазват: + +- име на ресторант, към който е свързано съответния проход, като низ с произволна дължина +- коли на опашка, като масив с коли с произволна дължина + +Имплементирайте методи: + +- от голяма петица +- `QueueUp`, който приема кола и я вкарва в края на опашката. + Разбира се, масивът се уголемява ако е нужно. +- `Serve`, който изпълнява поръчката на най-предната кола в опашката. + За единица глад, ресторанта може да сготви достатъчно храна (за да нахрани клиента с "единица" храна) за единици време между половината от дължината на името на ресторанта и три пъти дължината на името на ресторанта време. + Максималното възможно количество време за изпълнение на поръчката варира и според броя коли в опашка: ако са под 6 на брой, тогава тогава се увеличава с 10%, а ако са над 10 тогава се намалява с по 5% за всяка кола след десетата. +- `EfficiencyService`, който изпълнява поръчките на всички коли в опашката и връща средно колко време е отнело на поръчка. +- `StoreData`, който запазва всички данни в **текстов** файл с подадено име +- `LoadData`, който презаписва всички данни с тези от подадения по име **текстов** файл + +Имплементирайте главна функция, в която от потребителския вход приемате име на текстов файл. +Създайте обект от тип DriveThrough, който да запълни своите стойности с тези от подадения файл и изкарайте на екрана стойността от `EfficiencyService`. |
