Website Summary Files Commits Branches @commit @diff @stats
path: root / Week09
diff options
context:
space:
mode:
Commitb38346eebca9a007971af02fb3bb9472c5e16d0c (patch)
Author
 Syndamia <kamen@syndamia.com>
2026-04-26 21:43:31 +0300
Committer
 Syndamia <kamen@syndamia.com>
2026-04-26 21:43:31 +0300
Files575a64089a17be271aec84683f426252d8f5d1f9 /Week09
oop-2025-solutions-b38346eebca9a007971af02fb3bb9472c5e16d0c.tar
oop-2025-solutions-b38346eebca9a007971af02fb3bb9472c5e16d0c.tar.gz
oop-2025-solutions-b38346eebca9a007971af02fb3bb9472c5e16d0c.zip
Parent7d98b664c9e459a08f2e6e6fa5b636686dfed554 (diff)
feat(Week09): Add solutions
diff --git a/Week09/Exercise01/Locomotive.cpp b/Week09/Exercise01/Locomotive.cpp
new file mode 100644
index 0000000..2475126
--- /dev/null
+++ b/Week09/Exercise01/Locomotive.cpp
@@ -0,0 +1,81 @@
+#include "Locomotive.h"
+#include <cstring>
+
+unsigned Locomotive::GetID() const {
+ return ID;
+}
+
+void Locomotive::SetID(unsigned ID) {
+ this->ID = ID;
+}
+
+const char* Locomotive::GetManufacturer() const {
+ return manufacturer;
+}
+
+void Locomotive::SetManufacturer(const char manufacturer[MAX_LEN]) {
+ strncpy(this->manufacturer, manufacturer, MAX_LEN);
+}
+
+const char* Locomotive::GetModel() const {
+ return model;
+}
+
+void Locomotive::SetModel(const char model[MAX_LEN]) {
+ strncpy(this->model, model, MAX_LEN);
+}
+
+int Locomotive::GetYearOfManufacture() const {
+ return yearOfManufacture;
+}
+
+void Locomotive::SetYearOfManufacture(int yearOfManufacture) {
+ this->yearOfManufacture = yearOfManufacture;
+}
+
+double Locomotive::GetLength() const {
+ return length;
+}
+
+void Locomotive::SetLength(double length) {
+ this->length = length;
+}
+
+unsigned short Locomotive::GetCyllinders() const {
+ return cyllinders;
+}
+
+void Locomotive::SetCyllinders(unsigned short cyllinders) {
+ this->cyllinders = cyllinders;
+}
+
+bool Locomotive::GetSupportsMultipleWorking() const {
+ return supportsMultipleWorking;
+}
+
+void Locomotive::SetSupportsMultipleWorking(bool supportsMultipleWorking) {
+ this->supportsMultipleWorking = supportsMultipleWorking;
+}
+
+// Тази функция не е нужно да бъде приятелска, можеше просто да използваме
+// константните селектори.
+std::ofstream& operator<<(std::ofstream& ostr, const Locomotive& loc) {
+ ostr << "Train #" << loc.ID << std::endl
+ << "+ Model: " << loc.model << std::endl
+ << "+ Manufacturer: " << loc.manufacturer << std::endl
+ << "+ Year of manufacture: " << loc.yearOfManufacture << std::endl
+ << "- Length: " << loc.length << std::endl
+ << "- Engine cyllinders: " << loc.cyllinders << std::endl
+ << "- Multiple working: " << (loc.supportsMultipleWorking ? "Yes" : "No") << std::endl;
+ return ostr;
+}
+
+// Тазу функция не е нужно да бъде приятелска, можеше просто да използваме
+// мутаторите.
+std::ifstream& operator>>(std::ifstream& istr, Locomotive& loc) {
+ istr >> loc.ID;
+ istr.getline(loc.model, MAX_LEN);
+ istr.getline(loc.manufacturer, MAX_LEN);
+ istr >> loc.yearOfManufacture >> loc.length >> loc.cyllinders >> loc.supportsMultipleWorking;
+ return istr;
+}
diff --git a/Week09/Exercise01/Locomotive.h b/Week09/Exercise01/Locomotive.h
new file mode 100644
index 0000000..45e9f7b
--- /dev/null
+++ b/Week09/Exercise01/Locomotive.h
@@ -0,0 +1,43 @@
+#ifndef _LOCOMOTIVE
+#define _LOCOMOTIVE
+
+#include <fstream>
+
+const unsigned MAX_LEN = 1024;
+
+class Locomotive {
+ unsigned ID;
+ char manufacturer[MAX_LEN];
+ char model[MAX_LEN];
+ int yearOfManufacture;
+ double length;
+ unsigned short cyllinders;
+ bool supportsMultipleWorking;
+
+public:
+ unsigned GetID() const;
+ void SetID(unsigned ID);
+
+ const char* GetManufacturer() const;
+ void SetManufacturer(const char manufacturer[MAX_LEN]);
+
+ const char* GetModel() const;
+ void SetModel(const char model[MAX_LEN]);
+
+ int GetYearOfManufacture() const;
+ void SetYearOfManufacture(int yearOfManufacture);
+
+ double GetLength() const;
+ void SetLength(double length);
+
+ unsigned short GetCyllinders() const;
+ void SetCyllinders(unsigned short cyllinders);
+
+ bool GetSupportsMultipleWorking() const;
+ void SetSupportsMultipleWorking(bool supportsMultipleWorking);
+
+ friend std::ofstream& operator<<(std::ofstream& ostr, const Locomotive& loc);
+ friend std::ifstream& operator>>(std::ifstream& istr, Locomotive& loc);
+};
+
+#endif /* _LOCOMOTIVE */
diff --git a/Week09/Exercise02/Vector.cpp b/Week09/Exercise02/Vector.cpp
new file mode 100644
index 0000000..8de9091
--- /dev/null
+++ b/Week09/Exercise02/Vector.cpp
@@ -0,0 +1,203 @@
+#include "Vector.h"
+#include <cmath>
+#include <cstring>
+
+void Vector::free() {
+ delete[] numbers;
+}
+
+void Vector::copyFrom(const Vector& other) {
+ numbersCount = other.numbersCount;
+ numbersAlloc = other.numbersAlloc;
+
+ numbers = new double[numbersAlloc];
+ for (unsigned i = 0; i < numbersCount; ++i)
+ numbers[i] = other.numbers[i];
+}
+
+Vector::Vector() {
+ numbers = nullptr;
+ numbersCount = numbersAlloc = 0;
+}
+
+Vector::~Vector() {
+ free();
+}
+
+Vector::Vector(const Vector& other) {
+ copyFrom(other);
+}
+
+Vector& Vector::operator=(const Vector& other) {
+ if (this != other.ptr()) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+Vector::Vector(Vector&& other) {
+ numbers = other.numbers;
+ numbersCount = other.numbersCount;
+ numbersAlloc = other.numbersAlloc;
+
+ other.numbers = nullptr;
+ other.numbersCount = other.numbersAlloc = 0;
+}
+
+Vector& Vector::operator=(Vector&& other) {
+ if (this != other.ptr()) {
+ free();
+
+ numbers = other.numbers;
+ numbersCount = other.numbersCount;
+ numbersAlloc = other.numbersAlloc;
+
+ other.numbers = nullptr;
+ other.numbersCount = other.numbersAlloc = 0;
+ }
+ return *this;
+}
+
+unsigned Vector::GetCount() const {
+ return numbersCount;
+}
+
+const double* Vector::GetNumbers() const {
+ return numbers;
+}
+
+Vector& Vector::operator+=(const Vector& other) {
+ unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount;
+ for (unsigned i = 0; i < minLen; ++i)
+ numbers[i] += other.numbers[i];
+
+ return *this;
+}
+
+Vector& Vector::operator-=(const Vector& other) {
+ unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount;
+ for (unsigned i = 0; i < minLen; ++i)
+ numbers[i] -= other.numbers[i];
+
+ return *this;
+}
+
+
+Vector& Vector::operator*=(double scalar) {
+ for (unsigned i = 0; i < numbersCount; ++i)
+ numbers[i] *= scalar;
+
+ return *this;
+}
+
+double Vector::operator*=(const Vector& other) {
+ double dotProduct = 0.0;
+ unsigned minLen = numbersCount < other.numbersCount ? numbersCount : other.numbersCount;
+
+ for (unsigned i = 0; i < minLen; ++i)
+ dotProduct += numbers[i] * other.numbers[i];
+
+ return dotProduct;
+}
+
+Vector& Vector::operator^=(const Vector& other) {
+ // Припомняме си, че векторното умножение работи само върху
+ // триизмерни вектори
+ if (numbersCount != 3 || other.numbersCount != 3)
+ return *this;
+
+ double s[3];
+ double *a = numbers, *b = other.numbers;
+
+ s[0] = a[1] * b[2] - a[2] * b[1];
+ s[1] = a[2] * b[0] - a[0] * b[2];
+ s[2] = a[0] * b[1] - a[1] * b[0];
+
+ memcpy(a, s, sizeof(double) * 3);
+
+ return *this;
+}
+
+double Vector::operator&() const {
+ double sum = 0.0;
+ for (unsigned i = 0; i < numbersCount; ++i)
+ sum += numbers[i] * numbers[i];
+ return sqrt(sum);
+}
+
+Vector* Vector::ptr() {
+ return this;
+}
+
+const Vector* Vector::ptr() const {
+ return this;
+}
+
+Vector operator+(const Vector& lhs, const Vector& rhs) {
+ Vector ret(lhs);
+ ret += rhs;
+ return ret;
+}
+
+Vector operator-(const Vector& lhs, const Vector& rhs) {
+ // Не трябва да е нужно да обясняваме защо това
+ // е напълно същото като логиката при operator+
+ return Vector(lhs) -= rhs;
+}
+
+Vector operator*(const Vector& lhs, double scalar) {
+ return Vector(lhs) *= scalar;
+}
+
+Vector operator*(double scalar, const Vector& rhs) {
+ return rhs * scalar;
+}
+
+double operator*(const Vector& lhs, const Vector& rhs) {
+ return Vector(lhs) *= rhs;
+}
+
+Vector operator^(const Vector& lhs, const Vector& rhs) {
+ return Vector(lhs) ^= rhs;
+}
+
+bool operator||(const Vector& lhs, const Vector& rhs) {
+ unsigned minLen = lhs.GetCount() < rhs.GetCount() ? lhs.GetCount() : rhs.GetCount();
+
+ // Под "паралелни" вектори говорим повече за "колинеарни" вектори.
+ // Или с други думи, считаме дали правите, образувани от центъра 0 и
+ // един вектор съвпада с правата, образувана от центъра 0 и другия вектор.
+ // Щом лежат на една права, можем да скалираме единия вектор,
+ // така че той да стане равен на другия.
+ // С други думи, за вектори x и y, и скалар s, имаме че
+ // x || y тогава и само тогава когато съществува s: x = s*y,
+ // тстк същ. s: за всяко i: x[i] = s * y[i]
+ // тстк същ. s: вс. i: x[i] / y[i] = s
+ // тстк x[0] / y[0] = x[1] / y[1] = x[2] / y[2] = ...
+ //
+ // Алтернативно можем да вземем точковото умножение на вектори x и y,
+ // и чрез него да намерим ъгъла между двата вектора.
+ // Те ще лежат на една права ако ъгъла е 0 или 180 градуса.
+ // С други думи, ако arccos((x * y) / (&x * &y)) е 0 или PI
+ for (unsigned i = 0; i < minLen - 1; ++i) {
+ // Това коректно ли е? Възможно ли е да имаме проблеми с такова директно сравнение?
+ if (lhs.GetNumbers()[i] / rhs.GetNumbers()[i] != lhs.GetNumbers()[i+1] / rhs.GetNumbers()[i+1])
+ return false;
+ }
+ return true;
+}
+
+bool operator==(const Vector& lhs, const Vector& rhs) {
+ if (lhs.GetCount() != rhs.GetCount())
+ return false;
+
+ for (unsigned i = 0; i < lhs.GetCount(); ++i)
+ if (lhs.GetNumbers()[i] != rhs.GetNumbers()[i])
+ return false;
+ return true;
+}
+
+bool operator!=(const Vector& lhs, const Vector& rhs) {
+ return !(lhs == rhs);
+}
diff --git a/Week09/Exercise02/Vector.h b/Week09/Exercise02/Vector.h
new file mode 100644
index 0000000..bf7b0c3
--- /dev/null
+++ b/Week09/Exercise02/Vector.h
@@ -0,0 +1,59 @@
+#ifndef _VECTOR
+#define _VECTOR
+
+class Vector {
+ double* numbers;
+ unsigned numbersCount;
+ unsigned numbersAlloc;
+
+ void free();
+ void copyFrom(const Vector& other);
+
+public:
+ Vector();
+ ~Vector();
+ Vector(const Vector& other);
+ Vector& operator=(const Vector& other);
+
+ Vector(Vector&& other);
+ Vector& operator=(Vector&& other);
+
+ unsigned GetCount() const;
+ const double* GetNumbers() const;
+
+ // Добра конвенция при бинарни (двуаргументни) оператори е да
+ // дефинираме като член-функции съответните _= оператори (+=, -=, ...)
+ // и след това да дефинираме _ опеарторите (+, -, ...) като нормални
+ // функции, които вътрешно използват _=
+
+ Vector& operator+=(const Vector& other);
+ Vector& operator-=(const Vector& other);
+ Vector& operator*=(double scalar);
+ double operator*=(const Vector& other);
+ Vector& operator^=(const Vector& other);
+
+ double operator&() const;
+
+ // Понеже предефинираме &, не можем да направим &vector, за да
+ // вземем указател от референция към обект. За нашите цели е нужно,
+ // затова си правим помощни методи които "реимплементират" същата логика.
+ Vector* ptr();
+ const Vector* ptr() const;
+};
+
+Vector operator+(const Vector& lhs, const Vector& rhs);
+Vector operator-(const Vector& lhs, const Vector& rhs);
+
+// Понеже лявия и десния аргумент се различават по тип,
+// така поддържаме комутативност
+Vector operator*(const Vector& lhs, double scalar);
+Vector operator*(double scalar, const Vector& rhs);
+
+double operator*(const Vector& lhs, const Vector& rhs);
+Vector operator^(const Vector& lhs, const Vector& rhs);
+
+bool operator||(const Vector& lhs, const Vector& rhs);
+bool operator==(const Vector& lhs, const Vector& rhs);
+bool operator!=(const Vector& lhs, const Vector& rhs);
+
+#endif /* _VECTOR */
diff --git a/Week09/Exercise03/String.cpp b/Week09/Exercise03/String.cpp
new file mode 100644
index 0000000..a0b2565
--- /dev/null
+++ b/Week09/Exercise03/String.cpp
@@ -0,0 +1,153 @@
+#include "String.h"
+#include <cstring>
+
+void String::free() {
+ delete[] str;
+}
+
+void String::copyFrom(const String& other) {
+ length = other.length;
+ // Не забравяме за терминиращата нула
+ str = new char[length + 1];
+ strcpy(str, other.str);
+}
+
+String::String() {
+ str = nullptr;
+ length = 0;
+}
+
+String::~String() {
+ free();
+}
+
+String::String(const String& other) {
+ copyFrom(other);
+}
+
+String& String::operator=(const String& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+String::String(String&& other) {
+ str = other.str;
+ length = other.length;
+
+ other.str = nullptr;
+ other.length = 0;
+}
+
+String& String::operator=(String&& other) {
+ if (this != &other) {
+ free();
+
+ str = other.str;
+ length = other.length;
+
+ str = nullptr;
+ length = 0;
+ }
+ return *this;
+}
+
+String::String(const char* str) {
+ this->length = strlen(str);
+ this->str = new char[this->length + 1];
+ strcpy(this->str, str);
+}
+
+std::ostream& operator<<(std::ostream& ostr, const String& string) {
+ if (string.str == nullptr)
+ return ostr << "";
+ return ostr << string.str;
+}
+
+String& String::operator+=(const String& other) {
+ char* largerStr = new char[length + other.length + 1];
+ strcpy(largerStr, str);
+ strcat(largerStr, other.str);
+
+ delete[] str;
+ str = largerStr;
+ length += other.length;
+
+ return *this;
+}
+
+char String::operator[](unsigned index) const {
+ return str[index];
+}
+
+String::IndexRange::IndexRange(unsigned index) {
+ start = end = index;
+}
+
+String::IndexRange& String::IndexRange::operator,(const IndexRange& rhs) {
+ if (rhs.start < this->start)
+ this->start = rhs.start;
+ if (this->end < rhs.end)
+ this->end = rhs.end;
+ return *this;
+}
+
+String String::operator[](IndexRange range) const {
+ if (range.end >= length)
+ range.end = length - 1;
+ if (range.start > range.end)
+ return String();
+ if (range.start == 0 && range.end == length - 1)
+ return *this;
+
+ String substr;
+ substr.length = range.end - range.start + 1;
+ substr.str = new char[substr.length + 1];
+
+ strncpy(substr.str, str + range.start, substr.length);
+ substr.str[substr.length] = '\0';
+
+ return substr;
+}
+
+bool operator==(const String& lhs, const String& rhs) {
+ return strcmp(lhs.str, rhs.str) == 0;
+}
+
+bool operator!=(const String& lhs, const String& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator<(const String& lhs, const String& rhs) {
+ return strcmp(lhs.str, rhs.str) < 0;
+}
+
+bool operator<=(const String& lhs, const String& rhs) {
+ return strcmp(lhs.str, rhs.str) <= 0;
+}
+
+bool operator>(const String& lhs, const String& rhs) {
+ return strcmp(lhs.str, rhs.str) > 0;
+}
+
+bool operator>=(const String& lhs, const String& rhs) {
+ return strcmp(lhs.str, rhs.str) >= 0;
+}
+
+bool operator<<(const String& lhs, const String& rhs) {
+ if (rhs.length > lhs.length)
+ return false;
+ return strcmp(lhs.str + (lhs.length - rhs.length), rhs.str) == 0;
+}
+
+bool operator>>(const String& lhs, const String& rhs) {
+ if (lhs.length > rhs.length)
+ return false;
+ return strncmp(lhs.str, rhs.str, lhs.length) == 0;
+}
+
+String operator+(const String& lhs, const String& rhs) {
+ return String(lhs) += rhs;
+}
diff --git a/Week09/Exercise03/String.h b/Week09/Exercise03/String.h
new file mode 100644
index 0000000..674813c
--- /dev/null
+++ b/Week09/Exercise03/String.h
@@ -0,0 +1,61 @@
+#ifndef _STRING
+#define _STRING
+
+#include <ostream>
+
+class String {
+ char* str;
+ unsigned length;
+
+ void free();
+ void copyFrom(const String& other);
+
+public:
+ String();
+ ~String();
+ String(const String& other);
+ String& operator=(const String& other);
+
+ String(String&& other);
+ String& operator=(String&& other);
+
+ // Помощни член-функции, за да тестваме String
+ String(const char* str);
+ friend std::ostream& operator<<(std::ostream& ostr, const String& string);
+
+ // Каза ни са кои оператори трябва да бъдат имплементирани,
+ // но както помощни функции, можем да си имплементираме и други
+ // оператори
+ String& operator+=(const String& other);
+
+ char operator[](unsigned index) const;
+
+ const char* te() const {
+ return str;
+ }
+
+ struct IndexRange {
+ unsigned start;
+ unsigned end;
+
+ IndexRange(unsigned index);
+ IndexRange& operator,(const IndexRange& rhs);
+ };
+ String operator[](IndexRange range) const;
+
+ // Алтернативно, може да създадем селектори
+ // GetStr който връща str указателя и GetLength,
+ // и тези функции няма да е нужно да са приятелски
+ friend bool operator==(const String& lhs, const String& rhs);
+ friend bool operator!=(const String& lhs, const String& rhs);
+ friend bool operator<(const String& lhs, const String& rhs);
+ friend bool operator<=(const String& lhs, const String& rhs);
+ friend bool operator>(const String& lhs, const String& rhs);
+ friend bool operator>=(const String& lhs, const String& rhs);
+ friend bool operator<<(const String& lhs, const String& rhs);
+ friend bool operator>>(const String& lhs, const String& rhs);
+};
+
+String operator+(const String& lhs, const String& rhs);
+
+#endif /* _STRING */
diff --git a/Week09/Exercise03/main.cpp b/Week09/Exercise03/main.cpp
new file mode 100644
index 0000000..087b05f
--- /dev/null
+++ b/Week09/Exercise03/main.cpp
@@ -0,0 +1,15 @@
+#include "String.h"
+#include <iostream>
+
+int main() {
+ String a = "Hello";
+ String b = "World";
+
+ String c = a + " " + b;
+
+ std::cout << c << std::endl;
+ std::cout << (c << b) << ' ' << (a >> c) << std::endl;
+ std::cout << c[String::IndexRange(2), 7] << std::endl;
+
+ return 0;
+}
diff --git a/Week09/Exercise04/Rover.cpp b/Week09/Exercise04/Rover.cpp
new file mode 100644
index 0000000..dc311c7
--- /dev/null
+++ b/Week09/Exercise04/Rover.cpp
@@ -0,0 +1,64 @@
+#include "Rover.h"
+#include <cmath>
+
+// Използваме полярни координати, за да опишем посоките.
+// С други думи, използваме ъгъл, такъв че (1,0) е на 0 градуса (радиана),
+// (0,1) е на 90 градуса, (-1,0) е на 180 градуса и (0,-1) е на 270 градуса.
+// Така ако знаем посоката напред, посоката на ляво е на 90 градуса обратно
+// на часовниковата стрелка от ъгъла, който описва посоката "напред".
+// Аналогично, посоката на ляво е на 90 градуса по часовниковата стрелка от
+// ъгъла, който описва посоката "напред".
+
+void Rover::moveDistByAngle(double dist, double angle) {
+ // https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates
+ this->x += dist * cos(angle);
+ this->y += dist * sin(angle);
+}
+
+Rover::Rover() {
+ x = y = 0;
+ forward = M_PI_2;
+}
+
+Rover& operator<(double dist, Rover& rover) {
+ rover.moveDistByAngle(dist, rover.forward + M_PI_2);
+ return rover;
+}
+
+Rover& Rover::operator>(double dist) {
+ this->moveDistByAngle(dist, this->forward - M_PI_2);
+ return *this;
+}
+
+Rover& Rover::operator^(double dist) {
+ this->moveDistByAngle(dist, this->forward);
+ return *this;
+}
+
+Rover& operator<<(double degrees, Rover& rover) {
+ rover.forward += degrees / 180.0 * M_PI;
+ return rover;
+}
+
+Rover& Rover::operator>>(double degrees) {
+ this->forward -= degrees / 180.0 * M_PI;
+ return *this;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const Rover& rover) {
+ double forwardUnitX = cos(rover.forward), forwardUnitY = sin(rover.forward);
+ ostr << "Rover at (" << rover.x << ',' << rover.y
+ << "), looking direction (" << forwardUnitX << ',' << forwardUnitY << ')'
+ << std::endl;
+ return ostr;
+}
+
+std::istream& operator>>(std::istream& istr, Rover& rover) {
+ // Очакваме координат, който описва посоката "напред"
+ // Например (0,1)
+ double forwardUnitX, forwardUnitY;
+ istr >> rover.x >> rover.y >> forwardUnitX >> forwardUnitY;
+ // https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates
+ rover.forward = atan2(forwardUnitY, forwardUnitX);
+ return istr;
+}
diff --git a/Week09/Exercise04/Rover.h b/Week09/Exercise04/Rover.h
new file mode 100644
index 0000000..4286f06
--- /dev/null
+++ b/Week09/Exercise04/Rover.h
@@ -0,0 +1,27 @@
+#ifndef _ROVER
+#define _ROVER
+
+#include <ostream>
+#include <istream>
+
+class Rover {
+ double x;
+ double y;
+ double forward;
+
+ void moveDistByAngle(double dist, double angle);
+
+public:
+ Rover();
+
+ friend Rover& operator<(double dist, Rover& rover);
+ Rover& operator>(double dist);
+ Rover& operator^(double dist);
+ friend Rover& operator<<(double degrees, Rover& rover);
+ Rover& operator>>(double degrees);
+
+ friend std::ostream& operator<<(std::ostream& ostr, const Rover& rover);
+ friend std::istream& operator>>(std::istream& istr, Rover& rover);
+};
+
+#endif /* _ROVER */
diff --git a/Week09/Exercise05/String.cpp b/Week09/Exercise05/String.cpp
new file mode 100644
index 0000000..903aa60
--- /dev/null
+++ b/Week09/Exercise05/String.cpp
@@ -0,0 +1,75 @@
+#include "String.h"
+#include <cstring>
+#include <iostream>
+
+void String::free() {
+ delete[] str;
+}
+
+void String::copyFrom(const String& other) {
+ length = other.length;
+ // Не забравяме за терминиращата нула
+ str = new char[length + 1];
+ strcpy(str, other.str);
+}
+
+String::String() {
+ str = nullptr;
+ length = 0;
+}
+
+String::~String() {
+ free();
+}
+
+String::String(const String& other) {
+ copyFrom(other);
+}
+
+String& String::operator=(const String& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+String::String(String&& other) {
+ str = other.str;
+ length = other.length;
+
+ other.str = nullptr;
+ other.length = 0;
+}
+
+String& String::operator=(String&& other) {
+ if (this != &other) {
+ free();
+
+ str = other.str;
+ length = other.length;
+
+ other.str = nullptr;
+ other.length = 0;
+ }
+ return *this;
+}
+
+String::String(unsigned length) {
+ this->length = length;
+ this->str = new char[length + 1];
+ this->str[length] = '\0';
+}
+
+void String::Copy(const char* str) {
+ if (this->str == nullptr) {
+ length = strlen(str);
+ this->str = new char[length + 1];
+ }
+ strncpy(this->str, str, length);
+ this->str[length] = '\0';
+}
+
+const char* String::GetStr() const {
+ return str;
+}
diff --git a/Week09/Exercise05/String.h b/Week09/Exercise05/String.h
new file mode 100644
index 0000000..08c7a79
--- /dev/null
+++ b/Week09/Exercise05/String.h
@@ -0,0 +1,28 @@
+#ifndef _STRING
+#define _STRING
+
+#include <ostream>
+
+class String {
+ char* str;
+ unsigned length;
+
+ void free();
+ void copyFrom(const String& other);
+
+public:
+ String();
+ ~String();
+ String(const String& other);
+ String& operator=(const String& other);
+
+ String(String&& other);
+ String& operator=(String&& other);
+
+ String(unsigned length);
+ void Copy(const char* other);
+
+ const char* GetStr() const;
+};
+
+#endif /* _STRING */
diff --git a/Week09/Exercise05/StringArray.cpp b/Week09/Exercise05/StringArray.cpp
new file mode 100644
index 0000000..c3eca35
--- /dev/null
+++ b/Week09/Exercise05/StringArray.cpp
@@ -0,0 +1,219 @@
+#include "StringArray.h"
+#include <iostream>
+
+void StringArray::free() {
+ delete[] strings;
+}
+
+void StringArray::copyFrom(const StringArray& other) {
+ stringsCount = other.stringsCount;
+ stringsAlloc = other.stringsAlloc;
+ stringsAssigned = other.stringsAssigned;
+
+ strings = new String[stringsAlloc];
+ for (unsigned i = 0; i < stringsCount; ++i)
+ strings[i] = other.strings[i];
+}
+
+void StringArray::resize() {
+ stringsAlloc = stringsAlloc == 0 ? 8 : stringsAlloc * 2;
+ String* stringsLarger = new String[stringsAlloc];
+
+ for (unsigned i = 0; i < stringsCount; ++i)
+ stringsLarger[i] = strings[i];
+
+ delete[] strings;
+ strings = stringsLarger;
+}
+
+StringArray::StringArray() {
+ strings = nullptr;
+ stringsCount = stringsAlloc = stringsAssigned = 0;
+}
+
+StringArray::~StringArray() {
+ free();
+}
+
+StringArray::StringArray(const StringArray& other) {
+ copyFrom(other);
+}
+
+StringArray& StringArray::operator=(const StringArray& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+StringArray::StringArray(StringArray&& other) {
+ strings = other.strings;
+ stringsCount = other.stringsCount;
+ stringsAlloc = other.stringsAlloc;
+ stringsAssigned = other.stringsAssigned;
+
+ other.strings = nullptr;
+ other.stringsCount = other.stringsAlloc = other.stringsAssigned = 0;
+}
+
+StringArray& StringArray::operator=(StringArray&& other) {
+ if (this != &other) {
+ free();
+
+ strings = other.strings;
+ stringsCount = other.stringsCount;
+ stringsAlloc = other.stringsAlloc;
+ stringsAssigned = other.stringsAssigned;
+
+ other.strings = nullptr;
+ other.stringsCount = other.stringsAlloc = other.stringsAssigned = 0;
+ }
+ return *this;
+}
+
+void StringArray::PushLength(unsigned length) {
+ if (stringsCount >= stringsAlloc)
+ resize();
+ strings[stringsCount++] = String(length);
+}
+
+void StringArray::PushString(const char* str) {
+ if (stringsAssigned >= stringsAlloc)
+ resize();
+ strings[stringsAssigned++].Copy(str);
+
+ if (stringsAssigned > stringsCount)
+ stringsCount = stringsAssigned;
+}
+
+StringArray& StringArray::operator[](const Z& expectedNumbers) {
+ for (unsigned i = 0; i < expectedNumbers.numbersCount; ++i) {
+ PushLength(expectedNumbers.numbers[i]);
+ }
+ return *this;
+}
+
+StringArray& StringArray::operator()(const StringArray& strings) {
+ for (unsigned i = 0; i < strings.stringsAssigned; ++i) {
+ PushString(strings.strings[i].GetStr());
+ }
+ return *this;
+}
+
+StringArray& StringArray::operator()(const char* str) {
+ PushString(str);
+ return *this;
+}
+
+StringArray::StringArray(const char* str) : StringArray() {
+ PushString(str);
+}
+
+StringArray& StringArray::operator|(const char* str) {
+ PushString(str);
+ return *this;
+}
+
+// Това не е нужно по условие, но ще ни е
+// полезно за тестване.
+std::ostream& operator<<(std::ostream& ostr, const StringArray& sa) {
+ for (unsigned i = 0; i < sa.stringsAssigned; ++i)
+ ostr << sa.strings[i].GetStr() << std::endl;
+ return ostr;
+}
+
+/* Помощен клас Z */
+
+void Z::free() {
+ delete[] numbers;
+}
+
+void Z::copyFrom(const Z& other) {
+ numbersCount = other.numbersCount;
+ numbersAlloc = other.numbersAlloc;
+
+ numbers = new unsigned[numbersAlloc];
+ for (unsigned i = 0; i < numbersCount; ++i)
+ numbers[i] = other.numbers[i];
+}
+
+void Z::resize() {
+ numbersAlloc = numbersAlloc == 0 ? 8 : numbersAlloc * 2;
+ unsigned* numbersLarger = new unsigned[numbersAlloc];
+
+ for (unsigned i = 0; i < numbersCount; ++i)
+ numbersLarger[i] = numbers[i];
+
+ delete[] numbers;
+ numbers = numbersLarger;
+}
+
+Z::Z() {
+ numbers = nullptr;
+ numbersCount = numbersAlloc = 0;
+}
+
+Z::~Z() {
+ free();
+}
+
+Z::Z(const Z& other) {
+ copyFrom(other);
+}
+
+Z& Z::operator=(const Z& other) {
+ if (this != &other) {
+ free();
+ copyFrom(other);
+ }
+ return *this;
+}
+
+Z::Z(Z&& other) {
+ numbers = other.numbers;
+ numbersAlloc = other.numbersAlloc;
+ numbersCount = other.numbersCount;
+
+ other.numbers = nullptr;
+ other.numbersCount = other.numbersAlloc = 0;
+}
+
+Z& Z::operator=(Z&& other) {
+ if (this != &other) {
+ free();
+
+ numbers = other.numbers;
+ numbersAlloc = other.numbersAlloc;
+ numbersCount = other.numbersCount;
+
+ other.numbers = nullptr;
+ other.numbersCount = other.numbersAlloc = 0;
+ }
+ return *this;
+}
+
+Z::Z(unsigned number) {
+ numbersAlloc = 8;
+ numbersCount = 1;
+ numbers = new unsigned[numbersAlloc];
+ numbers[0] = number;
+}
+
+// Това е един метод да имплементираме operator++ и operator+,
+// където с ++ все едно подсказваме че ще добавяме елемент и с
+// + се добавя елемента.
+// Валидно е и ++ да не върши нищо и цялата логика да е в +.
+// Но така задължаваме употребата на "+++".
+
+Z& Z::operator++(int) {
+ if (numbersCount + 1 >= numbersAlloc)
+ resize();
+ return *this;
+}
+
+Z& Z::operator+(const Z& rhs) {
+ for (unsigned i = 0; i < rhs.numbersCount && numbersCount < numbersAlloc; ++i)
+ numbers[numbersCount++] = rhs.numbers[i];
+ return *this;
+}
diff --git a/Week09/Exercise05/StringArray.h b/Week09/Exercise05/StringArray.h
new file mode 100644
index 0000000..4b15ba0
--- /dev/null
+++ b/Week09/Exercise05/StringArray.h
@@ -0,0 +1,80 @@
+#ifndef _STRINGARRAY
+#define _STRINGARRAY
+
+#include "String.h"
+#include <ostream>
+
+// Декларация на класа, за да може в StringArray
+// да си го използваме преди пълната дефиниция
+class Z;
+
+class StringArray {
+ String* strings;
+ unsigned stringsCount;
+ unsigned stringsAlloc;
+
+ unsigned stringsAssigned;
+
+ void free();
+ void copyFrom(const StringArray& other);
+ void resize();
+
+public:
+ StringArray();
+ ~StringArray();
+ StringArray(const StringArray& other);
+ StringArray& operator=(const StringArray& other);
+
+ StringArray(StringArray&& other);
+ StringArray& operator=(StringArray&& other);
+
+ void PushLength(unsigned length);
+ void PushString(const char* str);
+
+ StringArray& operator[](const Z& expectedNumbers);
+
+ // Можем да създадем помощен клас "PassedStrings".
+ // Обаче нямаме ограничение което задължава StringArray и
+ // PassedStrings да са различни класове.
+ // Можем и просто да се възползваме от StringArray,
+ // и да си спестим писане на код.
+ StringArray& operator()(const StringArray& strings);
+ StringArray& operator()(const char* str);
+ StringArray(const char* str);
+
+ // Оператор "|" е ляво асоциативен
+ StringArray& operator|(const char* str);
+
+ // Това не е нужно по условие, но ще ни е
+ // полезно за тестване.
+ friend std::ostream& operator<<(std::ostream& ostr, const StringArray& sa);
+};
+
+class Z {
+ unsigned* numbers;
+ unsigned numbersCount;
+ unsigned numbersAlloc;
+
+ void free();
+ void copyFrom(const Z& other);
+ void resize();
+
+public:
+ Z();
+ ~Z();
+ Z(const Z& other);
+ Z& operator=(const Z& other);
+
+ Z(Z&& other);
+ Z& operator=(Z&& other);
+
+ Z(unsigned num);
+
+ Z& operator++(int);
+ Z& operator+(const Z& rhs);
+
+ friend StringArray;
+};
+
+
+#endif /* _STRINGARRAY */
diff --git a/Week09/Exercise05/main.cpp b/Week09/Exercise05/main.cpp
new file mode 100644
index 0000000..8bf6a6c
--- /dev/null
+++ b/Week09/Exercise05/main.cpp
@@ -0,0 +1,12 @@
+#include "StringArray.h"
+#include <iostream>
+
+int main() {
+ StringArray s;
+
+ // Защо за числата трябва да конвертираме всички, а при | конвертираме само първия?
+ s[ Z(7) +++ Z(4) +++ Z(3) ] ("") (StringArray("Hello")|"World") [ Z(4) +++ Z(5) +++ Z(1) ] ("!") [ Z(2) ] (StringArray("Code")|"A"|"B");
+
+ std::cout << s;
+ return 0;
+}