diff --git a/configuration/nogui/meson.build b/configuration/nogui/meson.build index f03f127bcbea5cea39e81553fa82438374c484e1..5f00880c76a7aed2368ac6882af50a34cc85f2e9 100644 --- a/configuration/nogui/meson.build +++ b/configuration/nogui/meson.build @@ -15,4 +15,4 @@ endif src = ['main.cpp'] -exe = executable('program', src, dependencies : [animationwindow_dep, sdl2_dep], cpp_args : compiler_flags) +exe = executable('program', src, dependencies : [std_lib_facilities_dep], cpp_args : compiler_flags) diff --git a/dependencies/subprojects/animationwindow/include/Widget.h b/dependencies/subprojects/animationwindow/include/Widget.h index 1d796fadb6a8868f207df79c9764fcab65b88515..a18db1df1cc00a5382931b8029e2e71bc5bf29ee 100644 --- a/dependencies/subprojects/animationwindow/include/Widget.h +++ b/dependencies/subprojects/animationwindow/include/Widget.h @@ -32,5 +32,8 @@ namespace TDT4102 { void setCallback(std::function<void(void)> callback); virtual ~Widget() {} void setVisible(bool isVisible); + unsigned int getWidth() const; + unsigned int getHeight() const; + void setSize(unsigned int newWidth, unsigned int newHeight); }; } \ No newline at end of file diff --git a/dependencies/subprojects/animationwindow/src/Color.cpp b/dependencies/subprojects/animationwindow/src/Color.cpp index 78d61533e97a89950a0e3f3425ead681e020edf4..222c01e3b87b1b20e5b41de1010fc8fbaaba89a4 100644 --- a/dependencies/subprojects/animationwindow/src/Color.cpp +++ b/dependencies/subprojects/animationwindow/src/Color.cpp @@ -21,7 +21,8 @@ const TDT4102::Color TDT4102::Color::navy = TDT4102::Color{0x000080}; const TDT4102::Color TDT4102::Color::blue = TDT4102::Color{0x0000ff}; const TDT4102::Color TDT4102::Color::teal = TDT4102::Color{0x008080}; const TDT4102::Color TDT4102::Color::aqua = TDT4102::Color{0x00ffff}; -const TDT4102::Color TDT4102::Color::orange = TDT4102::Color{0xffa500}; +const TDT4102::Color TDT4102::Color::orange = TDT4102::Color{0xffa500}; +const TDT4102::Color TDT4102::Color::mid_gray = TDT4102::Color{0x6a6c6e}; const TDT4102::Color TDT4102::Color::alice_blue = TDT4102::Color{0xf0f8ff}; const TDT4102::Color TDT4102::Color::antique_white = TDT4102::Color{0xfaebd7}; const TDT4102::Color TDT4102::Color::aquamarine = TDT4102::Color{0x7fffd4}; diff --git a/dependencies/subprojects/animationwindow/src/Widget.cpp b/dependencies/subprojects/animationwindow/src/Widget.cpp index 12d23ee627931ed57864b4f3e4d505a5e55de769..97f6ff27264e0d39bbff2a6fbce50400e6fd875b 100644 --- a/dependencies/subprojects/animationwindow/src/Widget.cpp +++ b/dependencies/subprojects/animationwindow/src/Widget.cpp @@ -18,4 +18,17 @@ TDT4102::Widget::Widget(TDT4102::Point location, unsigned int widgetWidth, unsig void TDT4102::Widget::setVisible(bool visible) { isVisible = visible; +} + +unsigned int TDT4102::Widget::getWidth() const { + return width; +} + +unsigned int TDT4102::Widget::getHeight() const { + return height; +} + +void TDT4102::Widget::setSize(unsigned int newWidth, unsigned int newHeight) { + width = newWidth; + height = newHeight; } \ No newline at end of file diff --git "a/infobank/Articles/\303\230ving 10.pdf" "b/infobank/Articles/\303\230ving 10.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..2addc700e2a87664fc53ec44249a2ab8df894e80 Binary files /dev/null and "b/infobank/Articles/\303\230ving 10.pdf" differ diff --git "a/infobank/Articles/\303\230ving 11.pdf" "b/infobank/Articles/\303\230ving 11.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..e076d0cd73958f4daac3adbea751e2984eaa22a1 Binary files /dev/null and "b/infobank/Articles/\303\230ving 11.pdf" differ diff --git "a/infobank/Articles/\303\230ving 9.pdf" "b/infobank/Articles/\303\230ving 9.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..d9831c8a5b13fbe895f80b5c117be7e160646ade Binary files /dev/null and "b/infobank/Articles/\303\230ving 9.pdf" differ diff --git "a/infobank/Articles/\303\230ving_9_bokm\303\245l.pdf" "b/infobank/Articles/\303\230ving_9_bokm\303\245l.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..7c7f1f5081467028e497ce85e622c396abfe604c Binary files /dev/null and "b/infobank/Articles/\303\230ving_9_bokm\303\245l.pdf" differ diff --git a/templates/_folder_Exercises/O10/MinesweeperWindow.cpp b/templates/_folder_Exercises/O10/MinesweeperWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..630f2d4c4a5c979c288be58610fca70ae5a37d86 --- /dev/null +++ b/templates/_folder_Exercises/O10/MinesweeperWindow.cpp @@ -0,0 +1,58 @@ +#include "MinesweeperWindow.h" +#include <iostream> + +MinesweeperWindow::MinesweeperWindow(int x, int y, int width, int height, int mines, const string &title) : + // Initialiser medlemsvariabler, bruker konstruktoren til AnimationWindow-klassen + AnimationWindow{x, y, width * cellSize, (height + 1) * cellSize, title}, + width{width}, height{height}, mines{mines} +{ + // Legg til alle tiles i vinduet + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + tiles.emplace_back(new Tile{ Point{j * cellSize, i * cellSize}, cellSize}); + tiles.back()->setCallback(std::bind(&MinesweeperWindow::cb_click, this)); + auto temp = tiles.back().get(); + add(*temp); + } + } + // Legg til miner paa tilfeldige posisjoner +} + +vector<Point> MinesweeperWindow::adjacentPoints(Point xy) const { + vector<Point> points; + for (int di = -1; di <= 1; ++di) { + for (int dj = -1; dj <= 1; ++dj) { + if (di == 0 && dj == 0) { + continue; + } + + Point neighbour{ xy.x + di * cellSize,xy.y + dj * cellSize }; + if (inRange(neighbour)) { + points.push_back(neighbour); + } + } + } + return points; +} + +void MinesweeperWindow::openTile(Point xy) { +} + +void MinesweeperWindow::flagTile(Point xy) { +} + +//Kaller openTile ved venstreklikk og flagTile ved hoyreklikk +void MinesweeperWindow::cb_click() { + + Point xy{this->get_mouse_coordinates()}; + + if (!inRange(xy)) { + return; + } + if (this->is_left_mouse_button_down()) { + openTile(xy); + } + else if(this->is_right_mouse_button_down()){ + flagTile(xy); + } +} diff --git a/templates/_folder_Exercises/O10/MinesweeperWindow.h b/templates/_folder_Exercises/O10/MinesweeperWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..8afc6d343a6bcbc4e385b5c1a7862f4d714eb4c6 --- /dev/null +++ b/templates/_folder_Exercises/O10/MinesweeperWindow.h @@ -0,0 +1,45 @@ +#pragma once +#include "AnimationWindow.h" +#include "Tile.h" + +using namespace std; +using namespace TDT4102; + +// Minesweeper GUI +class MinesweeperWindow : public AnimationWindow +{ +public: + // storrelsen til hver tile + static constexpr int cellSize = 30; + MinesweeperWindow(int x, int y, int width, int height, int mines, const string& title); +private: + const int width; // Bredde i antall tiles + const int height; // Hoyde i antall tiles + const int mines; // Antall miner + vector<shared_ptr<Tile>> tiles; // Vektor som inneholder alle tiles + + // hoyde og bredde i piksler + int Height() const { return height * cellSize; } + int Width() const { return width * cellSize; } + + // Returnerer en vektor med nabotilene rundt en tile, der hver tile representeres som et punkt + vector<Point> adjacentPoints(Point xy) const; + + // tell miner basert paa en liste tiles + int countMines(vector<Point> coords) const; + + // Sjekker at et punkt er paa brettet + bool inRange(Point xy) const { return xy.x >= 0 && xy.x< Width() && xy.y >= 0 && xy.y < Height(); } + + // Returnerer en tile gitt et punkt + shared_ptr<Tile>& at(Point xy) { return tiles[xy.x / cellSize + (xy.y / cellSize) * width]; } + const shared_ptr<Tile>& at(Point xy) const { return tiles[xy.x / cellSize + (xy.y / cellSize) * width]; } + + //aapne og flagge rute + void openTile(Point xy); + void flagTile(Point xy); + + // callback funksjoner til Tile knappene + void cb_click(); + +}; diff --git a/templates/_folder_Exercises/O10/Tile.cpp b/templates/_folder_Exercises/O10/Tile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..729eaed76ed29f91fc781564ebcfaf52ac6d23d2 --- /dev/null +++ b/templates/_folder_Exercises/O10/Tile.cpp @@ -0,0 +1,21 @@ +#include "Tile.h" + + + +// For aa sette Tilelabel i henhold til state +const std::map<Cell, std::string> cellToSymbol{{Cell::closed, ""}, + {Cell::open, ""}, + {Cell::flagged, "|>"}}; + +Tile::Tile(TDT4102::Point pos, int size) : + Button({pos.x, pos.y}, 1.5*size, size, "") { + setButtonColor(TDT4102::Color::silver); + } + +void Tile::open() +{ +} + +void Tile::flag() +{ +} diff --git a/templates/_folder_Exercises/O10/Tile.h b/templates/_folder_Exercises/O10/Tile.h new file mode 100644 index 0000000000000000000000000000000000000000..fa5754b846944f69339c55f49967754e0a34e767 --- /dev/null +++ b/templates/_folder_Exercises/O10/Tile.h @@ -0,0 +1,32 @@ +#pragma once +#include "AnimationWindow.h" +#include "widgets/Button.h" +#include <map> + +// De forskjellige tilstandene en Tile kan vaere i +enum class Cell { closed, open, flagged }; + +class Tile : public TDT4102::Button +{ + Cell state = Cell::closed; + void set_label(std::string s) { this->setLabel(s);} + void set_label_color(TDT4102::Color c) {this->setLabelColor(c);} + + // For aa sette labelfarge i henhold til hvor mange miner som er rundt + const std::map<int, TDT4102::Color> minesToColor{{1, TDT4102::Color::blue}, + {2, TDT4102::Color::red}, + {3, TDT4102::Color::dark_green}, + {4, TDT4102::Color::dark_magenta}, + {5, TDT4102::Color::dark_blue}, + {6, TDT4102::Color::dark_cyan}, + {7, TDT4102::Color::dark_red}, + {8, TDT4102::Color::gold}}; + +public: + Tile(TDT4102::Point pos, int size); + + void open(); + void flag(); + + Cell getState() const { return state; }; +}; diff --git a/templates/_folder_Exercises/O10/main.cpp b/templates/_folder_Exercises/O10/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a713bbcc6b71e23ca36208e61997b7a179ad5f8 --- /dev/null +++ b/templates/_folder_Exercises/O10/main.cpp @@ -0,0 +1,15 @@ +#include "MinesweeperWindow.h" + +int main() +{ + constexpr int width = 10; + constexpr int height = 10; + constexpr int mines = 3; + + Point startPoint{ 200, 300 }; + MinesweeperWindow mw{startPoint.x, startPoint.y, width, height, mines, "Minesweeper" }; + mw.wait_for_close(); + + return 0; +} + \ No newline at end of file diff --git a/templates/_folder_Exercises/O11/Stopwatch.cpp b/templates/_folder_Exercises/O11/Stopwatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4be1c713aee747fd38ae5ad501e6a18470ac223 --- /dev/null +++ b/templates/_folder_Exercises/O11/Stopwatch.cpp @@ -0,0 +1,12 @@ +#include "Stopwatch.h" + +void Stopwatch::start() { + startTime = std::chrono::steady_clock::now(); +} + +double Stopwatch::stop() { + std::chrono::time_point endTime = std::chrono::steady_clock::now(); + long durationInMicroseconds = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count(); + double durationInSeconds = double(durationInMicroseconds)/1000000.0; + return durationInSeconds; +} \ No newline at end of file diff --git a/templates/_folder_Exercises/O11/Stopwatch.h b/templates/_folder_Exercises/O11/Stopwatch.h new file mode 100644 index 0000000000000000000000000000000000000000..307f3835665aae16d34019c05d3012e877da6200 --- /dev/null +++ b/templates/_folder_Exercises/O11/Stopwatch.h @@ -0,0 +1,20 @@ +#pragma once +#include <iostream> +#include <chrono> + +// This class abstracts some (somewhat) nasty code that is +// definitely outside the scope of this course. +// Its main purpose is to return the amount of time +// taken by the program in main.cpp + +// Calling start() starts the stopwatch +// Calling stop() stops it and returns the amount of time +// that has elapsed since start() was called in seconds + +class Stopwatch { + std::chrono::time_point<std::chrono::steady_clock> startTime; + +public: + void start(); + double stop(); +}; \ No newline at end of file diff --git a/templates/_folder_Exercises/O11/optimizationTask.cpp b/templates/_folder_Exercises/O11/optimizationTask.cpp new file mode 100644 index 0000000000000000000000000000000000000000..243e9beacdbe8955cc37737898507a16c4d42baf --- /dev/null +++ b/templates/_folder_Exercises/O11/optimizationTask.cpp @@ -0,0 +1,52 @@ +#include "Stopwatch.h" +#include <vector> +#include <iostream> + +// Utdelt kode til oppgave 3 + +void setDiagonalValue(std::vector<std::vector<double>>& matrix, double newValue){ + for (int row = 0; row < matrix.size(); row++){ + for (int col = 0; col < matrix.size(); col++){ + bool isDiagonal = (row == col); + if (isDiagonal){ + matrix.at(row).at(col) = newValue; + } + } + } +} + +double sumMatrix(std::vector<std::vector<double>> matrix){ + double sum; + for (int col = 0; col < matrix.size(); col++){ + for (int row = 0; row < matrix.size(); row++){ + double value = matrix.at(row).at(col); + sum += value; + } + } + return sum; +} + +void optimizationTask() { + + const int matrixSize = 10000; + + // Create a matrix with zeros + std::vector<std::vector<double>> matrix; + + for (int i = 0; i < matrixSize; i++){ + std::vector<double> column; + for (int j = 0; j < matrixSize; j++){ + column.push_back(0.0); + } + matrix.push_back(column); + } + + // Set all elements on the diagonal to 0.41 + setDiagonalValue(matrix, 0.41); + + // Sum all elements in the matrix + double total = sumMatrix(matrix); + + double coolerNumber = total + 2; + std::cout << "TDT" << coolerNumber << std::endl; +} \ No newline at end of file diff --git a/templates/_folder_Exercises/O11/optimizationTask.h b/templates/_folder_Exercises/O11/optimizationTask.h new file mode 100644 index 0000000000000000000000000000000000000000..cf78e2f295e4dbccd2a5dcf9a2440a12811cf83e --- /dev/null +++ b/templates/_folder_Exercises/O11/optimizationTask.h @@ -0,0 +1,3 @@ +#pragma once + +void optimizationTask(); \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 11/parallel1_main.cpp b/templates/_folder_Lectures/Lecture 11/parallel1_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8be28dbe93c7942d5253fffa7072d626df4cfb9 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel1_main.cpp @@ -0,0 +1,167 @@ +#include <std_lib_facilities.h> +#include <AnimationWindow.h> +#include <widgets/Button.h> +#include <widgets/TextInput.h> +#include <widgets/DropdownList.h> + +void modifyA(int& a) { + +} + +struct Printer { + void say(std::string message) { + std::cout << message << std::endl; + } + + Printer() { + std::cout << "Printer was created" << std::endl; + } + + virtual ~Printer() { + std::cout << "Printer was UTTERLY DESTROYED" << std::endl; + } +}; + +// RAII: Resource Acquisition Is Initialisation + +struct ChildPrinter : public Printer { + std::unique_ptr<std::string> someMessage {new std::string{"Some message"}}; + + ChildPrinter() { + std::cout << "ChildPrinter was constructed" << std::endl; + } + + virtual void doPrinting() { + + } + + virtual ~ChildPrinter() { + std::cout << "ChildPrinter was destroyed" << std::endl; + } +}; + +void usePrinter(std::unique_ptr<Printer> printerPointer) { + +} + +std::unique_ptr<Printer> createPrinter() { + std::unique_ptr<Printer> pointer = make_unique<Printer>(); + return pointer; +} + +TDT4102::TextInput input({300, 400}, 300, 30, "Change me"); +void callbackFunction() { + std::cout << "Text in box: " << input.getText() << std::endl; +} + +int main() { + TDT4102::AnimationWindow window; + TDT4102::Button button({300, 300}, 100, 30, "Click me!"); + button.setCallback(&callbackFunction); + window.add(button); + + + input.setCallback(&callbackFunction); + window.add(input); + std::vector<std::string> vec{"Choice A", "Choice B", "Choice C"}; + TDT4102::DropdownList list({300, 500}, 100, 30, vec); + window.add(list); + + + window.wait_for_close(); + + std::shared_ptr<Printer> sharedPrinter = make_shared<Printer>(); + std::cout << "Instance count: " << sharedPrinter.use_count() << std::endl; + + std::shared_ptr<Printer> anotherSharedPrinter = sharedPrinter; + anotherSharedPrinter->say("Hello"); + std::cout << "Instance count: " << sharedPrinter.use_count() << std::endl; + + { + std::shared_ptr<Printer> yetAnother = sharedPrinter; + yetAnother->say("Hello"); + std::cout << "Instance count: " << sharedPrinter.use_count() << std::endl; + + } + + std::cout << "Instance count: " << sharedPrinter.use_count() << std::endl; + + + std::unique_ptr<Printer> printer = createPrinter(); + + // A constructor is called when the instance of the object is created + // Its destructor is called at the end of the containing scope + // (the } in the containing {}. Here it's the end of main()) + + //Printer printer; + + + std::unique_ptr<Printer> uniquePrinter; + if(true) { + // This is the manual way to allocate and deallocate memory + // We want to avoid this as much as possible because it leads to memory leaks + // Also, it's annoying having to remember to use delete + // When we use new, the constructor of the object is called + + //Printer* anotherPrinter = new Printer(); + + // When we use delete, the destructor is called + + //delete anotherPrinter; + + // When we allocate an array of objects, the constructors of each instance is + // called when the array is created + + //Printer* manyPrinters = new Printer[10]; + //manyPrinters[4].say("Hello"); + + // When we then use delete[] (which MUST be used for arrays), + // the destructor is called for each instance + + //delete[] manyPrinters; + + // A unique_ptr is a structure which contains one pointer, + // and guarantees there can only ever be one copy of that pointer + // its destructor deletes the contained memory automatically + //std::unique_ptr<Printer> print {new Printer()}; + + //std::cout << print.get() << std::endl; + // uniquePrinter.swap(print); + // uniquePrinter->say("Hello there!"); + // usePrinter(std::move(uniquePrinter)); // Borrow + + // ChildPrinter print; + } + + std::vector<std::unique_ptr<Printer>> vectorOfPrinters; + vectorOfPrinters.emplace_back(new Printer()); + + //std::unique_ptr<Printer> print {new Printer()}; + //std::unique_ptr<Printer> print = std::make_unique<Printer>(); + + + + int a = 5; + int& refToA = a; + modifyA(a); + + int* pointerToA = &a; + (*pointerToA)++; + std::cout << *pointerToA << std::endl; + + + for(int i = 0; i < 10; i++) { + std::string* test = new std::string("Hello from the heap!"); + + if(i == 3) { + continue; + } + //delete test; // double free + delete test; + + test->at(5); // dangling reference + } + + + return 0; +} \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 11/parallel2_destructors_houston.h b/templates/_folder_Lectures/Lecture 11/parallel2_destructors_houston.h new file mode 100644 index 0000000000000000000000000000000000000000..847b5c656ddff925959b638c6f8f2317f5c88c14 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel2_destructors_houston.h @@ -0,0 +1,124 @@ +// Lecture 11, Destructors example, Dragana Laketic + +#pragma once + +#include "std_lib_facilities.h" + + // class Sattelite used as a helper to define a dynamically + // alllocated data member of the class Houston. +class Sattelite { + string name; +public: + Sattelite() : name{"Apollo"} {} // Default constructor which sets + // the data member name to "Apollo". + Sattelite(string strName) : name{strName} {} // Overloaded constructor + // which takes one parameter of type + // string and assigns it to the data member name. + // Simple member function which allows a user to read the value + // of the data member name. Note that we can use const specifier + // to underline that the data member will not be changed. + string getName() const { + return name; + } + // Simple member function which allows a user to set the value + // of the data member name. + void setName(string strName) { + name = strName; + } +}; + +class Houston { + // class Houston has one data member and that is a pointer + // to an object of type Sattelite. + Sattelite *sattelite; +public: + // Default constructor + Houston() : sattelite{new Sattelite()} {} // Default constructor which + // dynamically allocates an object + // of type Sattelite and initialises + // the pointer data member sattelite + // with the address of the newly allocated + // object. + + // Constructor which takes in one parameter of type string + Houston(string strName) : sattelite{new Sattelite(strName)} {} // This constrctor + // dynamically allocates an object of type + // Sattelite and initialises it with the string + // value which is passed as a parameter to this + // constructor. The address of the newly allocated + // and initialised object is assigned to the + // class' data member sattelite. + + // Copy constructor + //Houston(const Houston& initHouston) : sattelite{new Sattelite()} {} // creates new allocation but does not copy the value + Houston(const Houston& initHouston) : sattelite{new Sattelite()} { // This copy constructor + // takes in one parameter: a reference to the object + // of the same type - class with which the object it + // constructs will be initialised. Mark that we also + // use const specifier to explicitly say that the object + // used for initialisation will not be changed during + // the construction of another object of this type. + // In the initialisation list of this copy constructor + // a new object of type Sattelite is dynamically allocated and + // the data member sattelite of the object which is being + // constructed is initialised with the address of this newly + // allocated object. + string initHoustonName = initHouston.readMySatteliteName(); // In the body of this constructor + // we read the name of the object pointed to by data member + // sattelite of the Houston object init Houston with which + // we initialise the object constructed by this constructor. + sattelite->setName(initHoustonName); // And then we assign this name to the newly allocated + // object pointed to by data member sattelite. + // This way of copying is called copy-by-value or DEEP COPY + // as we not only copy the values (addresses) in pointer variable + // but rather copy the value to newly allocated object. If we + // just copied the values in sattelite data members, it would be + // a SHALLOW COPY - the value of initHouston sattelite member would + // be copied to sattelite data member of the new constructed object + // so both objects would point to the same address in the memory. + } + // The copy constructor can be written as in the line below. + // The definition above is more explanatory as of what happens during + // construction by copying. + // Houston(const Houston& initHouston) : sattelite{new Sattelite(initHouston.readMySatteliteName())} {} + + // Destructor + // A special function called when the object goes out of scope and + // and is being destroyed in memory. This is the place where we can + // release resources allocated in the object's constructor (or during + // object's lifetime): dynamically allocated memory, filestream objects and similar. + ~Houston() { + cout << "Destructor freeing memory!" << endl; + // Here we let operating system to release the memory allocated + // by new operator in the constructor to which the address has been + // kept in sattelite data member. + delete sattelite; + } + // We haven't tatlked about it in the class but just as a note and + // recommendation: every time you write a copy constructor, write + // an overloaded operator=(). This is useful in case you assign + // an object which has some dynamically allocated resource(s) as + // data member(s) to another object of the same type. For the same + // reasons which hold for copy constructor, without overloaded + // operator=() only shallow copy would be performed and two + // objects would point to the same memory location. + Houston& operator=(const Houston& assignHouston) { + cout << "Assignment operator!" << endl; + printMySatteliteName(); + sattelite->setName(assignHouston.readMySatteliteName()); + printMySatteliteName(); + + return *this; + } + // Below are a few member function definitions which we used + // to demonstrate properties of copy constructors and destructors. + void printMySatteliteName() const { + std::cout << "My sattelite's name: " << sattelite->getName() << endl; + } + void renameMySattelite(string strNewName) { + sattelite->setName(strNewName); + } + string readMySatteliteName() const { + return sattelite->getName(); + } +}; diff --git a/templates/_folder_Lectures/Lecture 11/parallel2_destructors_main.cpp b/templates/_folder_Lectures/Lecture 11/parallel2_destructors_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7010d43c34b726d3235f58c96cf1c1a8a639986 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel2_destructors_main.cpp @@ -0,0 +1,79 @@ +// Lecture 11, Destructors example, Dragana Laketic + +#include "std_lib_facilities.h" +#include "houston.h" + +// Classes Sattelite and Houston which were used in the lecture +// are moved to a header file "houston.h" - renamed in this folder +// to "parallel2_destructors_houston.h". + +int main() { + // Pointers (dangers!) + Destructors & Copy Constructors + Houston houston1; // Default constructor used to instantiate houston1. + Houston houston2{"Sputnik"}; // Constructor which takes one string argument + // used to instantiate houston2. + Houston houston5{houston1}; // copy-constructor used here + Houston houstonX = houston1; // copy-constructor used here as well: + // note well that assignment here means initialisation! + Houston* ptrHouston{nullptr}; // A pointer to an object of type class Houston. + // It is a good practice to initialise it to nullptr + // which means it contains an invalid address! + + houston1.printMySatteliteName(); // An object calls its method. + // Name of the sattelite is determined in the + // default constructor. + ptrHouston = &houston2; // Pointer ptrHouston is assigned the address of houston2 + // (operator & used on variable name which represents object + // of type class Houston. + ptrHouston->printMySatteliteName(); // Example of accessing a member function + // via pointer. Object of houston2 is instantiated + // by calling a constructor with strin parameter + // of value "Sputnik". It is this name that will be + // written in the terminal after the method is called + // via pointer. + { + // At this place we enter a block-scope denoted by braces. + // All variables declared outside this block are valid within it as well. + // However, variables declared / defined within the block will not be + // valid outside the block - after we leave the closing brace "}". + Houston houston3{"Rosetta"}; // here new Sattelite() is called - default constructor + ptrHouston = &houston3; // Now pointer ptrHouston contains the address + // of houston3 object. + ptrHouston->printMySatteliteName(); // Access of class method via pointer + } // Here houston3 goes out of scope but delete sattelite was not being called! + + // We had an example of memory leakage - until we explicitly called delete + // in the destructor ~Houston().and let operating system know that it can free + // the memory. + + // Here ptrHouston is a dangling pointer! + // It contains an address which is no longer a valid address - + // object at that address is out of scope here. + // But! Since it is declared as a pointer to an object of type Houston, + // we can still call methods of that class: + //ptrHouston->printMySatteliteName(); // Remember? This line caused a runtime error! + + houston1.printMySatteliteName(); + houston5.printMySatteliteName(); + cout << "Houston 5 changing name:" << endl; + houston5.renameMySattelite("AlphaGO"); + // Before we wrote copy-constructor, the following two lines + // were printing the same name, i.e., both houston1 and houston5 + // had their sattelite's names changed. This is because the member + // sattelite is of type 'pointer to Sattelite' and it contains + // the address of the object of type Sattelite. Without copy-constructor, + // initialisation of object houston5 with houston2: + // Houston houston5{houston1}; + // will be deduced so that the value of data member 'sattelite' + // is copied and that value is an address to Sattelite object. + // That is, both houston5 and houston1 will point to the same + // Sattelite object in the memory. + // After we wrote a copy constructor, where we defined the way how this + // initialisation will be done, each object of type Houston keeps + // a different pointer, different addresses to their respective Sattelite + // (see how we defined the copy-constructor). + houston1.printMySatteliteName(); + houston5.printMySatteliteName(); + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 11/parallel2_repetition_main.cpp b/templates/_folder_Lectures/Lecture 11/parallel2_repetition_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..762119e58ee436bfb8352548540590cbc4d5ed60 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel2_repetition_main.cpp @@ -0,0 +1,50 @@ +// Lecture 11, Repetition example, Dragana Laketic + +#include "std_lib_facilities.h" +#include "points.h" + +// Classes Point, CartesianPoint and PolarPoint which we used +// in the lecture for the repetition of class inheritance, +// overloading and virtualisation, are defined in the "points.h" +// file which is here renamed to "parallel2_repetition_points.h". + +int main() { + // Repetition + // Repetition: Inheritance, virtualisation and abstract classes + + // Point point1; // NOTE: this instantiation is not possible after + // class Point became an abstract class when we made a pure + // virtual function printMyCoordinates() by adding '=0' + // at its declaration. + // No object - an instance of an abstract class - can be + // created in the program. + CartesianPoint decartes(5.4, 6.7); + PolarPoint euler(1.2, 4.5); + Point& refPoint1 = decartes; // A reference to a parent abstract class + Point& refPoint2 = euler; // Another reference to a parent abstract class + + // Overriding example + cout << "Overriding base abstract class methods:" << endl; + // point1.printMyCoordinates(); // NOTE: we cannot call any method of an abstract class! + // We could run this line before we made class Point to be + // an abstract class by adding a pure virtual function + // as its member function! + decartes.printMyCoordinates(); // Member function printMyCoordinates() of the + // child class CartesianPoint is called. It overrides its + // parent definition of the same function - same name, + // same return type, same parameter list. + euler.printMyCoordinates(); // Member function printMyCoordinates() of the child + // class PolarPoint is called - it overrdies its parent + // of the same function. + + // Example of virtualisation mechanism: + // Both refPoint1 and refPoint2 are of the same type: references to Point, + // but each calls the method of the child class to which the reference is assigned: + // refPoint1 calls printMyCoordinates() of the class CartesianPoint and + // refPoint2 calls printMyCoordinates() of the class PolarPoint + cout << "Virtualisation: calling exact methods via reference to parent class:" << endl; + refPoint1.printMyCoordinates(); + refPoint2.printMyCoordinates(); + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 11/parallel2_repetition_points.h b/templates/_folder_Lectures/Lecture 11/parallel2_repetition_points.h new file mode 100644 index 0000000000000000000000000000000000000000..f33178f2eae823a2e9f23fe87e74be27df88b8a8 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel2_repetition_points.h @@ -0,0 +1,71 @@ +// Lecture 11, Repetition example, Dragana Laketic + +#pragma once + +#include "std_lib_facilities.h" + +// Abstract class: +// pure virtual function +// protected constructor + +class Point { +protected: // What happens when you remove access protected + // and make coord1 and coord2 private data members as by default? + double coord1; + double coord2; +public: + virtual void printMyCoordinates() = 0; // An example of a pure virtual function. + // If a class has at least one pure virtual + // function, it is not possible to instantiate + // an object of the type of that class. We say + // that such class is abstract. We cannot have + // objects - instances of an abstract class in + // our program. + // Another way to make a class abstract is to + // make its constructor protected. In that way, + // only its children - the classes which inherit it, + // will be able to use its members. + // Abstract classes are usually used for organising + // hierachy of other classes, like in this simple + // example of 2D points. + virtual ~Point() {}; // virtualisation demands virtual destructor! + // Remember to add virtual destructor to the + // parent abstract class +}; + +class CartesianPoint : public Point { +public: + // Default constructor: + // Notice how CartesianPoint has no data members + // of its own, but it inherits data members of its + // parent class Point. Since they are declared + // protected: in class Point, the classes which inherit + // from Point can have direct access to them as in the + // following examples of constructors: + CartesianPoint() { + coord1 = 0.0; + coord2 = 0.0; + } + CartesianPoint(double x, double y) { + coord1 = x; + coord2 = y; + } + virtual void printMyCoordinates() { + cout << "CartesianPoint coordinate: (x=" << coord1 << ", y= " << coord2 << ")" << endl; + } +}; + +class PolarPoint : public Point { +public: + PolarPoint() { + coord1 = 0.0; + coord2 = 0.0; + } + PolarPoint(double r, double phi) { + coord1 = r; + coord2 = phi; + } + virtual void printMyCoordinates() { + cout << "PolarPoint coordinates: (radius=" << coord1 << ", angle=" << coord2 << ")" << endl; + } +}; diff --git a/templates/_folder_Lectures/Lecture 11/parallel2_smart_pointers_main.cpp b/templates/_folder_Lectures/Lecture 11/parallel2_smart_pointers_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa28fd328463913d8e899a735679ce2e68b72e85 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 11/parallel2_smart_pointers_main.cpp @@ -0,0 +1,94 @@ +// Lecture 11, Smart pointers example, Dragana Laketic + +#include "std_lib_facilities.h" +#include "houston.h" + +// We can return unique_ptr variable from a function. +unique_ptr<Sattelite> createUniqueSattelite(string satName) { + std::unique_ptr<Sattelite> ptr = std::make_unique<Sattelite>(); + ptr->setName(satName); + + return ptr; +} + +// Call by reference! +// When we pass unique pointer as a parameter to a function, +// it is best practice to do it by reference. In that way we +// avoid calling std::move() function on the unique pointer +// where the function is called in the program. +void printSatteliteUnique(std::unique_ptr<Sattelite>& peker) { + cout << "Funksjon: " << peker->getName() << endl; +} + +int main() { + // An example of a declaration of unique pointer: + // ptrSat is a unique pointer to a variable of type Sattelite + // which is created by a Sattelite default constructor. + // We use make_unique<Sattelite>() function to create a unique pointer + // to an object of type Sattelite which is created by Sattelite's + // default constructor since there is an empty parameter list. + // For: + // std::unique_ptr<Sattelite> ptrSat = make_unique<Sattelite>("Starlink"); + // a constructor which takes one string parameter would be called and + // a unique pointer to that object would be created. + // We can also initialise a unique pointer without calling make_unique<>(): + // std::unique_ptr<Sattelite> yetPtr{new Sattelite{"Rosetta"}}; + std::unique_ptr<Sattelite> ptrSat = make_unique<Sattelite>(); + // Unique pointers cannot be copied - they are unique! + // We can use function move to transfer the ownership of + // an object to another unique pointer like in the example below: + std::unique_ptr<Sattelite> ptrSat1 = std::move(ptrSat); // When this line is run, + // ptrSat will become invalid + // and generate an error if we + // attempt to perform any operation + // on it. + + // shared pointers are declared in the same way as unique pointers: + std::shared_ptr<Sattelite> sharedPtr = + std::make_shared<Sattelite>(); + std::shared_ptr<Sattelite> anotherSharedPtr = + std::make_shared<Sattelite>("Apollo"); + std::shared_ptr<Sattelite> yetAnotherSharedPtr{new Sattelite{"Rosetta"}}; + std::shared_ptr<Sattelite> copyShared; + std::shared_ptr<Sattelite> retShared; + Sattelite sat2{"AlphaFold"}; // used in the examples below + + + // We can use unique pointers just like raw pointers we have worked + // with until now. + cout << "My sattelite name: " << ptrSat1->getName() << endl; + ptrSat1->setName("Betha"); + cout << "My sattelite name: " << ptrSat1->getName() << endl; + + // When passing a unique pointer as parameter to a function, + // the best practice is to pass it by reference and in that + // way avoid calling move() function - as for the example of + // printSatteliteUnique() - see the definition of this function + // at the top of the file: + printSatteliteUnique(ptrSat1); + + // shared_ptr - some examples (although we have not had time to go + // through all examples in the class) + // Shared pointers are another type of smart pointers. They can be used + // to get access to the object pointed to in hte same way as all pointers: + cout << "Smart pointer points to " << sharedPtr->getName() << endl; + cout << "Another smart pointer points to " << anotherSharedPtr->getName() << endl; + cout << "Yet another smart pointer points to " << yetAnotherSharedPtr->getName() << endl; + + // Unlike unique pointers, shared pointers can be copied: + copyShared = sharedPtr; + cout << "Copied shared pointer points to " << copyShared->getName() << endl; + retShared = sharedPtr; + cout << "Second sopy points to " << retShared->getName() << endl; + // Method use_count() can tell us how mamy references there are to the same object: + cout << "Total num of shared pointer references " << copyShared.use_count() << endl; + copyShared = nullptr; // This operation will decrease a reference count: + cout << "Total num of shared pointer references a: " << sharedPtr.use_count() << endl; + retShared = nullptr; // ... and once more + cout << "Total num of shared pointer references b: " << sharedPtr.use_count() << endl; + + // Neither unique nor shared pointer require us to explicitly release allocated memory!!! + // That is why we call them smart. + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 12 - handout/main.cpp b/templates/_folder_Lectures/Lecture 12 - handout/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ecb077ef7feccd473ea12c6418209b85ec7aee19 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 12 - handout/main.cpp @@ -0,0 +1,69 @@ +#include <iostream> +#include <filesystem> +#include <fstream> +#include <vector> + +struct Pizza { + std::vector<std::string> toppings; +}; + +std::ifstream openFile(const std::filesystem::path& path) { + std::ifstream fileStream {path}; + if(!fileStream) { + std::cerr << "Could not open file: " + path.string() << std::endl; + } + return fileStream; +} + +int readNumberOfPizzas(std::ifstream& fileStream) { + int pizzaCount = 0; + fileStream >> pizzaCount; + return pizzaCount; +} + +Pizza readNextPizza(std::ifstream& fileStream) { + std::string line; + std::getline(fileStream, line); + + Pizza pizza; + std::stringstream lineStream {line}; + while(lineStream) { + std::string topping; + lineStream >> topping; + pizza.toppings.push_back(topping); + } + return pizza; +} + +std::vector<Pizza> parsePizzaFile(const std::filesystem::path& fileToRead) { + std::ifstream pizzaFile = openFile(fileToRead); + int numPizzas = readNumberOfPizzas(pizzaFile); + + std::vector<Pizza> pizzas; + for(int pizzaIndex = 0; pizzaIndex < numPizzas; pizzaIndex++) { + Pizza pizza = readNextPizza(pizzaFile); + pizzas.push_back(pizza); + } + + return pizzas; +} + +void printPizzas(const std::vector<Pizza>& pizzas) { + for(int pizzaIndex = 0; pizzaIndex < pizzas.size(); pizzaIndex++) { + std::cout << "Pizza " << (pizzaIndex + 1) << ": "; + const Pizza& pizza = pizzas.at(pizzaIndex); + for(int toppingIndex = 0; toppingIndex < pizza.toppings.size(); toppingIndex++) { + std::cout << pizza.toppings.at(toppingIndex) << ", "; + } + std::cout << std::endl; + } +} + +int main() { + const std::filesystem::path fileToRead = "pizzas.txt"; + + std::vector<Pizza> pizzas = parsePizzaFile(fileToRead); + + printPizzas(pizzas); + return 0; +} \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 12 - handout/pizzas.txt b/templates/_folder_Lectures/Lecture 12 - handout/pizzas.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fb06fcfe07e6eee8b99cb42412e70be1a2cfb8d --- /dev/null +++ b/templates/_folder_Lectures/Lecture 12 - handout/pizzas.txt @@ -0,0 +1,4 @@ +3 +Cheese +Cheese Salami +Cheese Beef \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 12/parallel2_GUI_main.cpp b/templates/_folder_Lectures/Lecture 12/parallel2_GUI_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..395908baba5160a747ec2e514a4e516a354c888f --- /dev/null +++ b/templates/_folder_Lectures/Lecture 12/parallel2_GUI_main.cpp @@ -0,0 +1,141 @@ +// Lecture 12, Example 1: GUI, Dragana Laketic + +#include "std_lib_facilities.h" +#include "AnimationWindow.h" +#include "widgets/Button.h" +#include "widgets/TextInput.h" +#include "widgets/DropdownList.h" + +// Examples of basic use of graphical user interface (GUI) +// implemented with graphicla elemets - widgets from the +// AnimationWindow library. + +// NOTE: Example 1a) refers to the case when we open an instance +// of a default AnimationWindow. + +/* 1a) + // Example of a callback function. This function handles the event + // "button-clicked", i.e., the code written within the function is + // run when a button is clicked. Note that this function is assigned + // to a particular variable of type TDT4102::Button within main(). +void callbacButton() { + static int gang{0}; // Here we can also see how static variables + // are used: when declared 'static', a variable + // does not lose its value when we go out of the + // scope of the function. It preserves its place + // in memory and the content of that memory location. + gang++; + cout << "Button clicked " << gang << " times" << endl; +} +*/ + + // An example of a user-defined class of a window which + // is derived from the basic classAnimationWindow. We usually + // use windows derived from some basic window class in our GUI + // programs since that gives us freedom to define how the window + // will look and how each of its graphical elements will behave. +class MyWindow : public TDT4102::AnimationWindow { + // We define widgets - graphical elements of the window as + // data members of the window class. In this example we have + // all three widgets: Button, TextInput and DropdownList as + // elements of the window. Note how all three widgets follow + // a similar pattern of parameters: first the coordinates of + // the top left corner of the widget within the window, then + // the width of the widget followed by its height. Following + // parameters depend on the type of the widget: a button + // will display the provided string as its name, a text box + // will contain the text provided by the string, and the drop-down + // meny will contain a list of items provided as a vector of strings + // as its parameter. + // Take a look at AnimationWindow documentation for a more + // thorough description of these graphical elements. + TDT4102::Button knapp{{100, 100}, 200, 100, "ClickMe!"}; + TDT4102::TextInput tekst{{400, 100}, 300, 100, "Write something here"}; + vector<string> frukt{"Eple", "Drue", "Plomme"}; + TDT4102::DropdownList lista{{100, 300}, 400, 100, frukt}; + // Callback functions (event handlers) which are assigned to + // the graphical elements - data members of this class - are + // provided as function members or methods of the class. + void callbackKnapp() { + cout << "Knappen clicked!" << endl; + } + void callbackTekst() { + cout << "Teksten: " << tekst.getText() << endl; + } + void callbackLista() { + cout << "Frukt: " << lista.getValue() << endl; + } +public: + MyWindow() { + // We add widgets to the window within the constructor of our + // user-defined window class. For that purpose add()-method + // inherited from the base class AnimationWindow is used. + add(knapp); + add(tekst); + add(lista); + // We assign callback functions to particular widgets of + // the window within window constructor as well. We use + // widgets' setCallback() method. However, when this method + // is called for the derived window class we cannot just + // use the address of the function - we need to use the bind() + // method which takes two parameters: the first one is the address + // of the function we want to set as a callback (remember that in + // this case we also have to provide the namespace where it is defined + // and that is the name of our class!) and the second parameter + // is always the pointer 'this', a pointer to the instance of the class at hand. + knapp.setCallback(std::bind(&MyWindow::callbackKnapp, this)); + tekst.setCallback(std::bind(&MyWindow::callbackTekst, this)); + lista.setCallback(std::bind(&MyWindow::callbackLista, this)); + } +}; + +int main() { + // An example of an event-driven programming: + // a widow of the type we have defined is opened and + // all the functionality in the program is implemented through + // callback functions assigned to different graphical elements + // of the window. + MyWindow win; + + win.wait_for_close(); + +/*1a) + // A simple example of how graphical user interface is implemented + // with the possibilities provided by AnimationWindow library. + TDT4102::AnimationWindow win; // Declaration of a default AnimationWindow. + TDT4102::Button knapp{{100, 100}, 200, 100, "ClickMe!"}; // Definition of + // a graphical element in the window - a widget. + // AnimationWindow library provides three types of + // widgets: button (Button), text input field + // (TextInput) and drop-down meny (DropdownList). + // Pay attention to the header files which must be + // included when you want to use these in your + // program (see the top of this file, include section). + // Note how the definition of a widget is done: first + // we provide a pair of coordinates whihc correspond to + // the top left corner of the widget within the window, + // ({100, 100})then the width of the widget (200) and + // the widget's height (100). The last parameter, string + // "ClickMe!" refers to the text which will be shown on + // the button when it is created in the window. + // Check AnimationWindow documentation for wider description! + + win.add(knapp); // Calling method add() of the AnimationWindow class with the widget + // sent as its parameter results in the widget being added to the window + // and shown as defined. + knapp.setCallback(&callbackButton); // The behaviour of the program is defined + // by the events produced when a user interacts with + // the graphical elements in the window. When an event + // happens with a certain graphical element in the window, + // the code defined within the so-called callback function + // is run. Callback functions are also called even-handlers + // for that reason. + // Widgets from the AnimationWindow library use their method + // setCallback() for that purpose. As a prameter, this method + // uses the address of the function which will be run when + // an event with the corresponding widget happens. + + win.wait_for_close(); // Usual way of keeping the window open until we explicitly close it. +*/ + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 12/parallel2_test_example_main.cpp b/templates/_folder_Lectures/Lecture 12/parallel2_test_example_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a86008f1c1f11d7f9d38abf4d22e56e92d11b785 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 12/parallel2_test_example_main.cpp @@ -0,0 +1,38 @@ +// Lecture 12, Example 3: testing + +#include "std_lib_facilities.h" +#include <cassert> + +int factorial(int number) { + // We can use assert command from <cassert> to ensure + // the input parameter is not a negative value. + // When you call factorial function with a negative value + // passed as a parameter, check the message in the terminal: + // assert statement will point you to the line in the code + // which failed. + assert(number >= 0); + if (number == 0) { + return 1; + } else { + return number*factorial(number-1); + } +} + +int main() { + cout << "Testing factorial() function" << endl; + // Test valid input + cout << "Input: " << 4 << " Output: " << factorial(4) << " (test: 24)" << endl; + // Test corner case + cout << "Input: " << 0 << " Output: " << factorial(0) << " (test: 1)" << endl; + // Test invalid input + cout << "Input: " << -11 << " Output: " << factorial(-11) + << " (test: assert statement!)" << endl; + cout << "Input: " << 'A' << " Output: " << factorial('A') + << " (test: non-sensical value!)" << endl; + // Test random input: use random number generator to generate inputs + // Call function under test for these values and compare the return result + // with hte result obtained from, for example, another factorial function + // from some other library. We can use the same seed value for the random + // number generator if we want a repeatable set of results. + return 0; +} \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 12/parallel2_try_catch_throw_main.cpp b/templates/_folder_Lectures/Lecture 12/parallel2_try_catch_throw_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b1733f96d252175602d7318c58dcea737089b2d --- /dev/null +++ b/templates/_folder_Lectures/Lecture 12/parallel2_try_catch_throw_main.cpp @@ -0,0 +1,170 @@ +// Lecture 12, Example 2: Exception-handling with try-catch-throw, Dragana Laketic + +#include "std_lib_facilities.h" +#include <cassert> + + // An example class which is used to handle exceptions. + // User-defined classes for exception handling can be + // designed according to the needs of our program. For more + // complex programs they can be implemented as class hierarchies. + // In our case, it is sufficient to provide an opportunity for + // a user to pass the message on hte exception that happened. + // What is thrown as an exception in the program is an instance + // of this class. +class MyException { + string message; +public: + MyException() : message("MyException happened!") { + cout << message << endl; + } + MyException(string strMessage) : name(strMessage) { + cout << message << endl; + } +}; + + // An example of a class which is just used for instantiating + // a dynamically allocated object in the example of exception safety. + // The class is known from previous lectures. What is important to + // note here is that we have output to a terminal each time a constructor + // or a destructor is called. it will help us follow how memory is handled - + // allocated and freed during hte program run. +class Sattelite { + string name; +public: + Sattelite() : name{"Starlink"} { + cout << "Constructing sattelite!" << endl; + } + Sattelite(string strName) : name{strName} {} + ~Sattelite() { + cout << "Destructing sattelite, freeing memory!" << endl; + } +}; + + // Definition of a function which is used in the example + // of exception safety. +void badPractice() { + Sattelite* ptrSat = new Sattelite(); + throw runtime_error("Bad practice at runtime!"); + // Mark that this line of code we shall never reach. + // Memory leakage happens because of the dynamically + // allocated memory for the object Sattelite is never + // called to be released by the operating system. + delete ptrSat; +} + + // Definition of a function which is used in the example + // of exception safety. +void goodPractice() { + shared_ptr<Sattelite> ptrSat = make_shared<Sattelite>(); + throw runtime_error("Good practice at runtime!"); + // Mark that befoore we leave the scope of this function upon + // the exception being thrown, the memory allocated for a Sattelite + // object pointed to by shared pointer ptrSat is released and freed + // by shared pointer (there is a destructor output in the terminal + // when you run the example!). This illustrates one of the recommendations + // for writing exception safe code. +} + +int main() { + // Declaration of three variables which are used in + // the example for exception handling. The first one is + // considered a given value as initialised at the declaration time. + // The second one is read from the terminal and provided by the user. + // The third one is calculated based on the first two. + int numberOfTents{20}; + int numberOfScouts; + int numOfScoutsPerTent; + + cout << "Input number of scouts:" << endl; + cin >> numberOfScouts; + + // Example of a try-catch block. + // (Run this bit of code with various input values) + // Within the try-block we write the code for which we want + // to make sure that exceptional situations are handled safely. + // For our case we inspect the values which are provided by + // the user and dependent on these values we throw various types + // of exceptions. Note how exceptions can be user-defined - as for + // the example used for the instance of class MyException - and exceptions + // from the C++ STL standard library. + // Note also that we throw exceptions by value! + try { + if (numberOfScouts < 0) { + // Here we throw a user-defined exception. In this case. + // it is an instance of the class MyException. + // NOTE: throw by value" + throw MyException("There cannot be negative number of scouts!"); + } + if (numberOfScouts % 5 != 0) { + // In this case we throw a user-defined exception as well. + throw MyCustomException("Scouts must be in groups of 5!"); + } + if (numberOfScouts == 0) { + // Here we throw a runtime_error exception from the C++ STL + // standard library. See headers <exception> and <stdexcept> + // for more details on these exceptions. + throw std::runtime_error("There must be some scouts present at the gathering!"); + } + if (numberOfScouts < 20) { + // Yet another example of throwing a runtime_error exception + // from standard library + throw std::runtime_error("Too few scouts to attend the gathering!"); + } + // The code below will be run if none of the exceptions above have been thrown. + numOfScoutsPerTent = numberOfScouts / numOfTents; + } catch (std::exception& e) { // NOTE: catch by reference! + // This is the first catch-block for the try-block above. + // Mark how we can have more than one catch-block per one + // try-block. That is because more than one type of an exception + // may occur during the code run and we can provide a catch-block + // per type of an exception. In this catch-block we handle exceptions + // from C++ standard library (see <exception> and <stdexcept>). Note + // how we use what() method of the exception class to obtain more + // information about the exception that occurred. + cout << e.what() << endl; + } catch (MyException& e) { + // In this catch-block we handle exceptions of the user-defined type + // class MyException + cout << "Catching user-defined exception!" << endl; + } catch(...) { + // catch-block (...) handles any other exception type, + // i.e., if an exception was thrown of a type not listed + // in previous catch-statements, then this block is run. + cout << "Unknown exception happened!" << endl; + } + + // Here is an example of the code which does not (in the first case) + // and which does (in the second case) follow the recommendations + // for exception safety. + // In both cases the exception is handled but in the first case + // the destructor of the dynamically allocated object Sattelite + // is not called because the code never ran the delete statement + // at the end of the badPractice() function. + cout << "Bad Practice Call:" << endl; + try { + badPractice(); + } catch (std::exception& e) { + cout << e.what() << endl; + } catch (...) { + cout << "Unknown bad practice" << endl; + } + cout << "-----------------------------" << endl; + cout << "Good Practice Call:" << endl; + // In this case, since we used smart pointer (shared pointer) + // to a dynamically allocated object, the destructor of that + // object was called when an exception in the function goodPractice() + // was thrown and the shared pointer went out of the scope where + // it was defined, i.e., the scpe of that function. Unlike the case above + // the memory held by operating system for Sattelite object is released. + // Look at the messages in the terminal when you run the program. + // Can you see where the memory leakage happened? + try { + goodPractice(); + } catch (std::exception& e) { + cout << e.what() << endl; + } catch (...) { + cout << "Unknown bad practice" << endl; + } + + return 0; +} \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 13/parallel1_main.cpp b/templates/_folder_Lectures/Lecture 13/parallel1_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b04d24ab6a90470f454e62ec98441e2d8f65a9e0 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 13/parallel1_main.cpp @@ -0,0 +1,98 @@ + +#include "std_lib_facilities.h" + +template<typename T> +void print(T a) { + std::cout << a << std::endl; +} + +template<typename T> +struct NotAVector { + T a; +}; + +#include <queue> +#include <deque> + +struct Vector2 { + float x; + float y; + + Vector2 operator+(Vector2& a) { + Vector2 out; + out.x = x + a.x; + out.y = y + a.y; + return out; + } +}; + +int main(int argc, char** argv) { + std::vector<std::string> parameters; + for(int i = 0; i < argc; i++) { + parameters.push_back(std::string(argv[i])); + std::cout << "Parameter " << i << ": " << parameters.at(i) << std::endl; + } + + + + std::queue<std::string> koo; + + koo.push("Number one"); + koo.push("Number two"); + koo.push("Number three"); + + while(!koo.empty()) { + std::cout << koo.front() << std::endl; + koo.pop(); + } + + std::deque<std::string> d; + + std::vector<int> list = {1, 6, 3, 8, 5, 3, 7, 4}; + + std::vector<Vector2> vecList = {{2, 5}, {2, 7}, {65, 87}}; + + Vector2 sum = std::accumulate(vecList.begin(), vecList.end(), Vector2{0, 0}); + + std::random_device device; + std::default_random_engine engine(device()); + std::shuffle(list.begin(), list.end(), engine); + + int a = 5; + int b = 4; + + //std::swap(a, b); + + //std::min(a, b); + //std::max(a, b); + std::sort(list.begin(), list.end()); + + std::fill(list.begin(), list.end(), 55); + + std::vector<int> anotherList(100); + std::copy(list.begin(), list.end(), anotherList.begin() + 5); + + anotherList.erase(anotherList.begin() + 3, anotherList.begin() + 5); + + + + + for(std::vector<int>::reverse_iterator it = list.rbegin(); it != list.rend(); it++) { + std::cout << *it << std::endl; + } + + //NotAVector<int> vec; + print<std::string>("a"); + print<int>(10); + print(10.0); + + std::array<int, 5> array; + std::map<std::string, int> aMap; + + std::vector<int> vec(10); + std::unique_ptr<int*> test; + std::map<std::string, int> map; + + return 0; +} + diff --git a/templates/_folder_Lectures/Lecture 13/parallel2_STL_main.cpp b/templates/_folder_Lectures/Lecture 13/parallel2_STL_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c1f59e2e780b0baa81c0e5015950ea9c94908d5 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 13/parallel2_STL_main.cpp @@ -0,0 +1,150 @@ +// Lecture 13, Examples 3 and 4: STL containers and algorithms, Dragana Laketic + +#include "std_lib_facilities.h" + +#include <queue> +#include <stack> +#include <list> +#include <algorithm> +#include <cassert> + +int main() { + // STL containers + std::queue<int> queue; // Queue is a First-In-First-Out (FIFO) data + // structure. In STL C++ standard library it is + // implemented as a template. + queue.push(1); // We use push() method to enqueue an element in queue + queue.push(2); + queue.push(3); + + while(!queue.empty()) { // The value of an element of a queue which is + // first to leave the queue when we call pop() method + // can be accessed by front() method. + cout << queue.front() << endl; + queue.pop(); + } + assert(queue.size() == 0); // repetition from last lecture: use of assert + // to make sure all the elements of the queue have left + // the queue (have been popped from the queue). + + std::stack<string> stack; // Stack is a Last-In-First-Out data structure. That means + // that the last element placed on stack will be the first to + // leave the stack when we call stack's pop() method. + stack.push("First on Stack"); + stack.push("Second on Stack"); + stack.push("Third on Stack"); + + while(!stack.empty()) { + cout << stack.top() << endl; // We use top() method to get the values of + // the element which is placed last on stack. + // It will be the first element to leave the stack + // when we call pop() method. + stack.pop(); + } + // Note how we use push() and pop() methods for two different containers - + // a queue and a stack - but how these methods work in accordance to the + // definition of each of them, i.e., the definition of a FIFO and a definition + // of a LIFO data structure. + + + // Back to vector. Although we know it very well, now we understand + // a "bigger picture" as well: it is yet another template container + // class from STL library. + std::vector<int> vec{50, 70, 20, 40, 80, 10, 90}; + // Usually we traverse its elements in a for-loop like this: + for (int i = 0; i < vec.size(); i++) { + cout << vec.at(i) << endl; // Here we use a range-checked method at() + // to access the vector's elements. + } + cout << endl; + + // Here is an example of traversing the same vector with the use + // of iterators. Iterators are members of STL containers which contain + // a pointer to an element of the container and thereby enable us to + // access the values stored in the container's elements. + // Note that STL containers also provide begin() and end() methods + // which return an iterator which points to the first element of + // the container and to the location after the last element of the + // container. In other words, an STL container contains the elements in + // the interval [STLcontainer.begin(), STLcontainer.end()) - where + // mathematical notation for open and close limit of the interval applies. + cout << "Vector traversed with iterator: " << endl; + // Pay attention to how the iterator type is declared! It reflects + // the instantiated template of a container! + for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) { + cout << *it << endl; + } + cout << endl; + + std::list<int> lst{1, 2, 3}; // Linked lists are containers which use pointers to connect + // the elements into it. There are two types of lists: + // singly linked lists and doubly linked lists. An element + // of a singly linked list beside the data value contains also + // a pointer to the next element in the list, while the doubly + // linked lists elements contain a pointer to a next element in + // the list and a pointer to the previous element in the list. + // With each insersion of a new element, search for an element of + // certain value or erasure of an element, the pointers to some + // memory locations where individual elements are stored must also + // be handled. This all takes much of the computing resources and + // increases the time needed for processing. Therefore, unless really + // necesary within the application at hand (or the task at the exam), + // they are advised to be avoided. Use vectors instead and + // whenever you can! + + cout << "List with iterator: " << endl; + // Pay attention to how the type of the iterator is declared in this case! + // Compare it with the iterator type from the vector traversal example! + for (std::list<int>::iterator it = lst.begin(); it != lst.end(); it++) { + cout << *it << endl; + } + cout << endl; + + // There exist also a reverse iterator which is analogous to an iterator + // discussed above with the distinction in the direction of the traversal + // which is illustrated in the following example: + cout << "Reverse iterator:" << endl; + for (std::list<int>::reverse_iterator rit = lst.rbegin(); rit != lst.rend(); rit++) { + cout << *rit << endl; + } + cout << endl; + + // STL algorithms + + // Iterators are especially handy when it comes to using algorithms from + // the STL standard library. + + // An example of calling the sort() algorithm for the first 4 + // elements of the vector vec defined above: + std::sort(vec.begin(), vec.begin() + 4); + cout << "Partially sorted vector:" << endl; + for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) { + cout << *it << endl; + } + cout << endl; + + // An example of using an algorithm from the STL library which + // processes the elements of two different types of containers. + // We provide iterators to the copy algorithm and invoke the copying + // of list lst elements from the first to the last to the first element + // of the vector and the subsequent ones: + std::copy(lst.begin(), lst.end(), vec.begin()); + cout << "Vector after copying from the list:" << endl; + for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) { + cout << *it << endl; + } + cout << endl; + // Note that the checks of the container limits are not performed + // so you need to take care of it. Test what would happen if instead + // of a vec.begin() you provided vec.end() / vec.end()-1 / vec.end()-2. + + // Am example of fill algorithm: + std::fill(vec.begin(), vec.begin()+5, 500); + cout << "Vector after fill:" << endl; + for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) { + cout << *it << endl; + } + cout << endl; + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 13/parallel2_main_main.cpp b/templates/_folder_Lectures/Lecture 13/parallel2_main_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cccd13ed9601d8fa9578b09a5c9b685c1116a0d --- /dev/null +++ b/templates/_folder_Lectures/Lecture 13/parallel2_main_main.cpp @@ -0,0 +1,39 @@ +// Lecture 13, Example 4: main() function, Dragana Laketic +#include <iostream> +#include <string> +#include <vector> + +// Extenden version of main() function has two arguments: +// int argc - total number of program arguments +// char** argv - array of strings which contains the arguments +// (char**-style is inherited from C programming language and +// stands for an array of char* variables (strings) where each +// char* element contains a string. In C, a string was represented +// as an array of char variables with special character '\0' +// at the end to denote the end of string.) + + // Run this program from the command line with some arguments listed, like this: + // <path_to_your_project>/builddir/ ./program 1001 textfile.txt binary + // What are the arguments written out in the terminal? + // How can you use these values passed to your program? +int main(int argc, char** argv) { + std::vector<std::string> arguments; + + // Each program has at least one argument and that + // is the location - the full path - of the program file within + // the file system where program is run. + std::cout << "I am a program with " << argc << " arguments:" << std::endl; + + // We can store arguments from argv array in a more C++-friendly + // manner, like in the example below within a vector of strings. + for (int i = 0; i < argc; i++) { + arguments.push_back(argv[i]); // Note how we use index operator + // on array variable argv. + } + // Her skriver vi ut argumenter fra vektoren: + for (int i = 0; i < arguments.size(); i++) { + std::cout << "Argument " << i << ": " << arguments.at(i) << std::endl; + } + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 13/parallel2_template_Points.h b/templates/_folder_Lectures/Lecture 13/parallel2_template_Points.h new file mode 100644 index 0000000000000000000000000000000000000000..6d6a0b47a73590d4f186bf5f30aacbdd7e490d57 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 13/parallel2_template_Points.h @@ -0,0 +1,82 @@ +// Lecture 13, Example 1: templates, Dragana Laketic + +#pragma once +#include "std_lib_facilities.h" + +// Templates enable the creation of classes and functions which have +// the same interface for different data types. The interface is +// written only once with the data type(s) passed in as parameters. +// Beside one or more data type parameters, there can also be values of +// some other type passed in to a template - most often it is integer +// values. +// When a template class or a template function is used in the program, +// we need to provide parameters - data type(s) and/or values - for the +// concrete class or function. When compiler comes across a templated +// class or function in the prgram file, it instantiates the corresponding +// template with exactly those parameters provided in the program. It is +// worth noting that this type-resolution and template instantiation +// happens at compile time. +// We keep template definitions - template class, template class member functions +// and template functions - within a header file. This is because it is only a template +// and the instantiated classes and functions, those which will be actually used +// in the program, are made by the compiler at compilation time. + + // 1) An example of a class template + // With template we use a keyword 'template' followed by + // keyword 'typename' and some name (as of our choice) between + // less than and greater than signs. The name of a typename parameter + // can be whatever you choose but often it is 'T' or some variation + // of it for data types. +template<typename T> +class Point{ + // Where ever there is 'T' in the template class definition + // there will be a concrete data type set by the compiler when + // it comes across our invocation of the templated class with + // that concrete parameter passed between '<' and '>'. + T x; + T y; +public: + Point(T xx, T yy) : x{xx}, y{yy} {} + T getX() const {return x;} + T getY() const {return y;} + void printMe() { + cout << "(" << x << ", " << y << ")" << endl; + } +}; + + // 2) An example of a template class which takes more than one parameter +template<typename T1, typename T2> +class ChoppedPoint { + T1 x; + T2 y; +public: + ChoppedPoint(T1 xx, T2 yy) : x{xx}, y{yy} {} + void printMe() { + cout << "(" << x << ", " << y << ")" << endl; + } +}; + + // 3) An example of a function template +template<typename TT> // note: here we use TT (our free choice) + //after 'typename' +void PrintValue(TT var) { + cout << "Template function: " << endl; + cout << var << endl; +} + + // 4) An example of integer value as a template parameter + // (compare with std::array<> where we also pass in an integer value + // as a template parameter) +template<typename T, int N> +class Collection { + T* collection; +public: + Collection() { + cout << "Constructor of template<typename T, int N> class Collection" << endl; + collection = new T[N]; + } + ~Collection() { + cout << "Destructor of template<typename T, int N> class Collection" << endl; + delete[] collection; + } +} diff --git a/templates/_folder_Lectures/Lecture 13/parallel2_template_main.cpp b/templates/_folder_Lectures/Lecture 13/parallel2_template_main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..115b784ec619feeb5e4ecf78ed58c670d5f74ed6 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 13/parallel2_template_main.cpp @@ -0,0 +1,41 @@ +// Lecture 13, Example 1: templates, Dragana Laketic + +#include "std_lib_facilities.h" +#include "Points.h" + +int main() { + // 1) Class template + Point<int> pointI{1, 3}; // Here the compiler instantiates template class Point + // to 'int' data type instead of generic 'T' ... + Point<double> pointD{10.5, 5.5}; // ... and here to 'double'. + + cout << "X coordinate int Point: " << pointI.getX() << endl; + pointD.PrintMe(); + + // 2) Class template with more than one typename parameter + ChoppedPoint<int, double> pointC{4, 7.5}; + pointC.PrintMe(); + + // 3) Function template + cout << "Function template:" << endl; + PrintValue<int>(5); // Providing explicitly data type to instantiate + // a function template with. + PrintValue<string>("ABC"); // Explicit instantiation of the function template + // with data type 'string'. + PrintValue(100); // An example of so-called template argument deduction when + // a compiler deduces which type the function template should + // be instantiated with based on the argument passed to a function. + // Here it was a simple case of a built-in data type int, but + // beware that for more complex types, for example user-defined + // classes, it is recommended providing an explicit data type + // for the function template instantiation like in the two examples + // above. + + // 4) Class template with one data type and one integer as parameters + // Note: during lecture we mentioned such case for std::array but here + // is an example of the use of a user-defined template with such parameters + Collection<int, 10> coll; // Note: for exercise, extend class Collection with + // some functions and call those functions ofr coll object. + + return 0; +} diff --git a/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.cpp b/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4be1c713aee747fd38ae5ad501e6a18470ac223 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.cpp @@ -0,0 +1,12 @@ +#include "Stopwatch.h" + +void Stopwatch::start() { + startTime = std::chrono::steady_clock::now(); +} + +double Stopwatch::stop() { + std::chrono::time_point endTime = std::chrono::steady_clock::now(); + long durationInMicroseconds = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count(); + double durationInSeconds = double(durationInMicroseconds)/1000000.0; + return durationInSeconds; +} \ No newline at end of file diff --git a/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.h b/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.h new file mode 100644 index 0000000000000000000000000000000000000000..307f3835665aae16d34019c05d3012e877da6200 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 14 - handout/Stopwatch.h @@ -0,0 +1,20 @@ +#pragma once +#include <iostream> +#include <chrono> + +// This class abstracts some (somewhat) nasty code that is +// definitely outside the scope of this course. +// Its main purpose is to return the amount of time +// taken by the program in main.cpp + +// Calling start() starts the stopwatch +// Calling stop() stops it and returns the amount of time +// that has elapsed since start() was called in seconds + +class Stopwatch { + std::chrono::time_point<std::chrono::steady_clock> startTime; + +public: + void start(); + double stop(); +}; \ No newline at end of file diff --git a/templates/_folder_Lectures/O10 - handout/Box.cpp b/templates/_folder_Lectures/O10 - handout/Box.cpp new file mode 100644 index 0000000000000000000000000000000000000000..460efb173cf5f259aefc5dc7194bd15d62bf6a82 --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/Box.cpp @@ -0,0 +1,17 @@ +#include "Box.h" + + +void Box::open() { + //hvis boksen er lukket, skal den åpnes (settes til trykket på) + //labelen skal settes til open-labelen + //label color skal settes til rød + +} + +void Box::close() { + // Lukk boksen + //sette riktig label og farge +} + + + diff --git a/templates/_folder_Lectures/O10 - handout/Box.h b/templates/_folder_Lectures/O10 - handout/Box.h new file mode 100644 index 0000000000000000000000000000000000000000..4e29bb401cd8fdf9edb3e79d49a54c36d104c3bc --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/Box.h @@ -0,0 +1,21 @@ +#pragma once +#include "widgets/Button.h" +#include <map> + +enum class Cell { closed, open }; + +class Box : public TDT4102::Button { + Cell state = Cell::closed; //begynner default som lukket + std::map<Cell, std::string> cellToSymbol { + {Cell::closed, "Trykk her!"}, + {Cell::open, "Bø"} + }; + +public: + Box(int x, int y, int width, int height) : TDT4102::Button(TDT4102::Point{x, y}, width, height, "Trykk her!") {}; + + void open(); //funksjon som skal åpne boksen + void close(); //funksjon som skal lukke boksen + + Cell getState() const { return state; }; +}; diff --git a/templates/_folder_Lectures/O10 - handout/ClickWindow.cpp b/templates/_folder_Lectures/O10 - handout/ClickWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae4011706ca50a2722d43a508c00bac5d59e697e --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/ClickWindow.cpp @@ -0,0 +1,55 @@ +#include "ClickWindow.h" + +ClickWindow::ClickWindow(int x, int y, int width, int height, int clicks, const std::string &title) : + // Initialiser medlemsvariabler, bruker konstruktoren til AnimationWindow-klassen + AnimationWindow{x, y, width, height, title}, + clicks{clicks}, + remainingClicks{clicks} + //initialisere de ulike knappene +{ + //legge til callback på de ulike knappene og adde dem til vinduet + + //Hvis det er noen knapper vi ikke vil skal synes fra start, kan vi kalle .setVisible(false) på dem + + +} + + +void ClickWindow::decreasing() { + //denne funksjonen skal kalles når man venstreklikker og skal telle ned antall klikk fra click variabelen + //remainingClicks må minke med 1 hver gang denne funksjonen kalles + + //Hvis remainingClicks = 0, skal man få opp quit og restart-knapper + + + //Hvis remainingClicks er mindre enn begynnende antall klikk, men større enn null, skal knappen være grønn + + //Hvis remainingClicks er mindre enn null, skal knappen hver gang man trykker få en random farge + + //I alle tilfellene skal labelen til knappen oppdateres slik at det står remainingClicks +} + +void ClickWindow::increasing() { + //funksjonen kalles når man høyreklikker. Da skal remainingClicks øke med 1 for hver gang + //Hvis remainingClicks er større enn antall klikk vi begynte med, skal knappen bli rød + //Husk å oppdatere knappens label +} + +void ClickWindow::click() { + + if (this->is_left_mouse_button_down()) { + decreasing(); + } + else if(this->is_right_mouse_button_down()){ + increasing(); + } +} + +void ClickWindow::restart() { + + //Funksjonen som kalles når man trykker på restart-knappen + //skal gjenopprette remainingClicks til clicks + //skjule restart og quit-knappene + //label og color for knappen må også gjøres om til det man begynte med +} + diff --git a/templates/_folder_Lectures/O10 - handout/ClickWindow.h b/templates/_folder_Lectures/O10 - handout/ClickWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..ef6ca0fb10046f972bb04c06f67c6e29305b0ef0 --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/ClickWindow.h @@ -0,0 +1,29 @@ +#pragma once +#include "AnimationWindow.h" +#include "widgets/TextInput.h" +#include "widgets/Button.h" +#include <random> + +class ClickWindow : public TDT4102::AnimationWindow { +public: + ClickWindow(int x, int y, int width, int height, int clicks, const std::string& title); + +private: + const int clicks; // Antall klikk + int remainingClicks; //Antall klikk igjen + + + void decreasing(); + void increasing(); + + //callback-funksjonene + void cb_quit() { this->close(); }; + void cb_restart() { this->restart(); } + void cb_click() { this->click(); }; + void restart(); + void click(); + + //Lage tre knapper (lukke, åpne, klikk) + + //Kan legge til en TDT4102::TextInput som skal gi en tilbakemelding til spilleren +}; diff --git a/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.cpp b/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..642fadc1078c77e62ba081c5374b511c5d1e6f68 --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.cpp @@ -0,0 +1,45 @@ +#include "MultiplyingWindow.h" + +MultiplyingWindow::MultiplyingWindow(int x, int y, int width, int height, int multipleNumber, const std::string &title) : + // Initialiser medlemsvariabler, bruker konstruktoren til AnimationWindow-klassen + AnimationWindow{x, y, width, height, title}, + multiple{multipleNumber}, + width{width}, + height{height} +{ + //Skal lage den første boksen som skal komme opp og legge den til i buttons-vektoren + //Vi må sette riktig label, legge til callback og adde den til vinduet +} + + +void MultiplyingWindow::multiplying() { + //når denne funksjonen kalles har det blitt trykt - skal lage flere knapper + //må huske å legge de til i buttons + //ønsker at de skal plasseres random i vinuet + + + //I tillegg må vi, hvis knappene er åpne, lukke dem og sette bredde/høyde til mindre + //hvis vi vil, kan vi gi dem en random farge + + +} + +void MultiplyingWindow::multiplyingRecursive(int count, int width, int height) { + +} + +void MultiplyingWindow::nothing() { + //når denne funksjonen kalles skal man åpne alle knappene i buttons-vektoren + +} + + +void MultiplyingWindow::click() { + + if (this->is_left_mouse_button_down()) { + multiplying(); + } else if (this->is_right_mouse_button_down()) { + nothing(); + } +} + diff --git a/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.h b/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..2e86413b4413242e2452b276c5719eb3625d1b36 --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/MultiplyingWindow.h @@ -0,0 +1,24 @@ +#pragma once +#include "AnimationWindow.h" +#include "Box.h" +#include <random> + + +class MultiplyingWindow : public TDT4102::AnimationWindow { +public: + MultiplyingWindow(int x, int y, int width, int height, int multipleNumber, const std::string& title); + +private: + const int multiple; //antall den skal multiplisere seg med + const int width; //bredden til vinduet + const int height; //høyden til vinduet + + std::vector<std::shared_ptr<Box>> buttons; //lagrer pekere til alle knappene i en vektor + + void multiplying(); + void multiplyingRecursive(int count, int width, int height); + void nothing(); + + void cb_click() { this->click(); }; //callback-funksjonen + void click(); +}; diff --git a/templates/_folder_Lectures/O10 - handout/main.cpp b/templates/_folder_Lectures/O10 - handout/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c928e1f52461be54ce1a3929ad5d776378bbd26a --- /dev/null +++ b/templates/_folder_Lectures/O10 - handout/main.cpp @@ -0,0 +1,18 @@ +#include "ClickWindow.h" +#include "MultiplyingWindow.h" +#include "Box.h" + +int main() { + + constexpr int width = 700; + constexpr int height = 700; + constexpr int clicks = 10; + constexpr int multiple = 5; + + TDT4102::Point startPoint{ 200, 300 }; + + // lag vindu og kall wait_for_close() + + + return 0; +}