aboutsummaryrefslogtreecommitdiff
path: root/week09
diff options
context:
space:
mode:
Diffstat (limited to 'week09')
-rw-r--r--week09/Exam1/Drone.cpp140
-rw-r--r--week09/Exam1/Drone.h34
-rw-r--r--week09/Exam1/DroneShow.cpp100
-rw-r--r--week09/Exam1/DroneShow.h28
-rw-r--r--week09/Exam1/main.cpp79
-rw-r--r--week09/README.md104
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*)&currentSize, 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`.