diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 8003c66..e54148d 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,46 +1,50 @@ -name: CMake - -on: [push] - -env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Release - -jobs: - build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Create Build Environment - # Some projects don't allow in-source building, so create a separate build directory - # We'll use this as our working directory for all subsequent commands - run: cmake -E make_directory ${{github.workspace}}/build - - - name: Configure CMake - # Use a bash shell so we can use the same syntax for environment variable - # access regardless of the host operating system - shell: bash - working-directory: ${{github.workspace}}/build - # Note the current convention is to use the -S and -B options here to specify source - # and build directories, but this is only available with CMake 3.13 and higher. - # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - - name: Build - working-directory: ${{github.workspace}}/build - shell: bash - # Execute the build. You can specify a specific target with "--target " - run: cmake --build . --config $BUILD_TYPE - -# - name: Test -# working-directory: ${{github.workspace}}/build -# shell: bash -# # Execute tests defined by the CMake configuration. -# # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail -# run: ctest -C $BUILD_TYPE +name: CMake + +on: [push] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Clone Dependencies + run: git submodule update --init --recursive + working-directory: ${{github.workspace}}/ + + - name: Create Build Environment + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{github.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + shell: bash + working-directory: ${{github.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{github.workspace}}/build + shell: bash + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config $BUILD_TYPE + +# - name: Test +# working-directory: ${{github.workspace}}/build +# shell: bash +# # Execute tests defined by the CMake configuration. +# # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail +# run: ctest -C $BUILD_TYPE diff --git a/.gitignore b/.gitignore index e0ed712..9d9e831 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ experiment* delete* .vs +.vscode # i am not commiting this directory to git, it contains the pdcurses.lib and includes for pdcurses curses/ diff --git a/.gitmodules b/.gitmodules index 4fc3721..b129ef2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,15 @@ -[submodule "graphMat"] - path = graphMat - url = https://github.com/adi-g15/graphMat -[submodule "ext\\graphMat"] - path = ext\\graphMat - url = https://github.com/adi-g15/graphMat -[submodule "ext\\glfwpp"] +[submodule "graphMat"] + path = graphMat + url = https://github.com/adi-g15/graphMat +[submodule "ext\\graphMat"] + path = ext\\graphMat + url = https://github.com/adi-g15/graphMat +[submodule "ext\\glfwpp"] path = ext\\glfwpp url = https://github.com/janekb04/glfwpp +[submodule "ext/utilpp"] + path = ext/utilpp + url = https://github.com/adi-g15/utilpp +[submodule "ext/nanogui"] + path = ext/nanogui + url = https://github.com/mitsuba-renderer/nanogui.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e1bf23..d168953 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,52 +1,58 @@ -cmake_minimum_required(VERSION 3.10.0) -project(WorldLineSim - DESCRIPTION "WorldLine Simulator" - LANGUAGES CXX - VERSION 0.271 - ) - -# Set c++ standard to C+20 -set(CMAKE_CXX_STANDARD 17) - -if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ext/glfwpp/include") - message(FATAL_ERROR "The GLFW dependency (or it's wrapper glfwpp) are missing!! " - "You might not have cloned the repo with --recursive " - "You will need to clone the dependencies too, use \`git submodule --init --recursive\`" - ) -endif() - -file(GLOB SOURCES "src/Entities/*.cpp" "src/*.cpp") - -add_compile_definitions(GRAPH_MAT_NO_COORD) -add_executable(simulator main.cpp ${SOURCES}) -target_link_libraries(simulator PRIVATE display) - -include_directories(includes) -include_directories(.) -include_directories(ext/graphMat/includes/) -include_directories(ext/glfwpp/include/) - -set(DEBUG_MODE true) - -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) - -link_libraries(Threads::Threads) - -add_subdirectory(ext/glfwpp) -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE) -target_link_directories(simulator PRIVATE GLFWPP) - -# set(CMAKE_TOOLCHAIN_FILE "C:/Users/adity/libs/vcpkg/scripts/buildsystems/vcpkg.cmake") -# later distribute display into a library, and link to it -# file(GLOB DISP_SOURCES "display/src/*.cpp") -# add_library(display STATIC ${DISP_SOURCES}) -# Edit the 3 lines, according to your build of curses (ncurse or pdcurses) -# set(CURSES_INCLUDE_PATH "C:/Users/adity/libs/vcpkg/packages/pdcurses_x64-windows/include") -# set(CURSES_LIBRARY "C:/Users/adity/libs/vcpkg/packages/pdcurses_x64-windows/lib") -#target_include_directories(simulator PRIVATE curses/includes) -# Edit the previous 3 lines, according to your build of curses (ncurse or pdcurses) -# define a macro here "__DEBUG" -# include_directories(${CURSES_INCLUDE_PATH}) -# find_package(Curses REQUIRED) -# target_link_libraries(display PUBLIC ${CURSES_LIBRARY}/pdcurses.lib) +cmake_minimum_required(VERSION 3.10.0) +project(WorldLineSim + DESCRIPTION "WorldLine Simulator" + LANGUAGES CXX + VERSION 0.271 + ) +include(CTest) + +# Later utilise features in C++20 +set(CMAKE_CXX_STANDARD 17) + +if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ext/glfwpp/include") + message(FATAL_ERROR "The GLFW dependency (or it's wrapper glfwpp) are missing!! " + "You might not have cloned the repo with --recursive " + "You will need to clone the dependencies too, use \`git submodule --init --recursive\`" + ) +endif() + +include_directories(ext/graphMat/includes/) +include_directories(ext/utilpp/includes/) +include_directories(ext/glfwpp/include/) + +file(GLOB SOURCES "src/Entities/*.cpp" "src/*.cpp") + +#add_compile_definitions(GRAPH_MAT_NO_COORD) +add_compile_definitions(DEBUG) +add_executable(simulator main.cpp ${SOURCES}) +target_link_libraries(simulator PRIVATE display) + +include_directories(includes) +include_directories(.) + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +file(GLOB DISP_SOURCES "display/src/*.cpp") +add_library(display STATIC ${DISP_SOURCES}) +target_link_libraries(display PRIVATE GLFWPP) + +add_subdirectory(ext/glfwpp) +set(NANOGUI_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE) +set(GLFWPP_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE) +target_link_libraries(simulator PRIVATE Threads::Threads) +target_link_libraries(simulator PRIVATE display) + +# set(CMAKE_TOOLCHAIN_FILE "C:/Users/adity/libs/vcpkg/scripts/buildsystems/vcpkg.cmake") +# later distribute display into a library, and link to it +# file(GLOB DISP_SOURCES "display/src/*.cpp") +# add_library(display STATIC ${DISP_SOURCES}) +# Edit the 3 lines, according to your build of curses (ncurse or pdcurses) +# set(CURSES_INCLUDE_PATH "C:/Users/adity/libs/vcpkg/packages/pdcurses_x64-windows/include") +# set(CURSES_LIBRARY "C:/Users/adity/libs/vcpkg/packages/pdcurses_x64-windows/lib") +#target_include_directories(simulator PRIVATE curses/includes) +# Edit the previous 3 lines, according to your build of curses (ncurse or pdcurses) +# define a macro here "__DEBUG" +# include_directories(${CURSES_INCLUDE_PATH}) +# find_package(Curses REQUIRED) +# target_link_libraries(display PUBLIC ${CURSES_LIBRARY}/pdcurses.lib) diff --git a/CMakeSettings.json b/CMakeSettings.json index 99b6f71..c2f708b 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,41 +1,41 @@ -{ - "configurations": [ - { - "name": "x64-Debug (default)", - "generator": "Ninja", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${projectDir}\\out\\build\\${name}", - "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "", - "variables": [], - "intelliSenseMode": "windows-msvc-x64", - }, - { - "name": "x64-Release", - "generator": "Ninja", - "configurationType": "Debug", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "", - "inheritEnvironments": [ "msvc_x64_x64" ], - "variables": [] - }, - { - "name": "x64-ReleaseWithDeb", - "generator": "Ninja", - "configurationType": "RelWithDebInfo", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "", - "inheritEnvironments": [ "msvc_x64_x64" ], - "variables": [] - } - ] +{ + "configurations": [ + { + "name": "x64-Debug (default)", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "variables": [], + "intelliSenseMode": "windows-msvc-x64", + }, + { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [] + }, + { + "name": "x64-ReleaseWithDeb", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [] + } + ] } \ No newline at end of file diff --git a/README.md b/README.md index 44c20d2..75e4fe2 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,84 @@ -# World Line Simulator - -Wait... if you are thinking it's some big rendering project, sorry but it's not, -it enjoys this condition -> - -_Think about a world, in which 4 snakes keep moving automatically to get food_ - -And, this project generalises this idea to entities and actions, in different worlds and worldlines, as well theoretically different verses too, other than this -> -_And... you can go to a particular time in **past**, and change the position of one of the snakes... Baammm, a new world line is created in which this event happened, and the older world had the event not taken place... so there is a high chance, current state(lengths of the snakes) of the world will be different than what had been in the previous world line_ - -That's it, this project does this much mainly (though no limitations on what it may add later). - -It also features a constantly growing matrix (the world_plot). - -### Building - -**READ THE NOTE AFTER THESE COMMANDS** - -```sh -cd worldLineSim/build # if doesn't exist, then create -cmake .. -cmake --build . -``` - -> Now depending on your compiler, you will have a `simulator` or `simulator.exe`, which is the executable after building, you can run it then - -_NOTE_ - - 1. Still doesn't use all the functions. - 2. It has been built without linking(referencing) to all features(functions) just so to know how it works at that particular time - 3. There maybe commits in the master branch itself, that WON'T BUILD, but i will make sure to either build it, or remove the command area for the time being then - -### NOTE - -1. Currently all commits are on the master branch itself, and not on a separate dev branch, since i prefer to keep track of all my 'initial - work on master itself (this thing will change once the initial idea is done) -2. Initially the focus is that _internally_ the simulation happens, but maybe the display won't be very great now (Since, I don't have a ground in rendering things currently, if you have ideas, or suggestions do put in that pinned issue) - -## Flags used in code - -Various flags (inside comments), have been used to convey some messages to the developer -> -* `@todo` - These comments show that particular thing is to be done -* `@future` - These are tasks to be done, AFTER the basic idea is done, say for example, an improvement to the begaviour or algorithm -* `@note` - Some information about the code given to a user, or a simple note to let you know how it might behave -* `@warning` - A caution note to the reader (generally telling that you should call other function for cleaning the resources used (pointers, thread etc.)) -* `@debug` - These signify the part of code that is only there for debugging purposes, and should be removed later for actual accepted behaviour -* `@me` - Notes to myself -* `@deprecated` - Portions of codes, or functions that won't be used (likely not used in the code), and will be removed with the following commits - -Other than these, usual single line comments, are 'low-priority comments' more general than these - -And, multi line comments are generally for briefly telling about some struct or class - -# Class Chart - -> Made with draw.io - -![Class Chart](https://raw.githubusercontent.com/AdityaGupta150/Sources/main/worldLineSim.png "WorldLine Sim") - -## Future Ideas - -> There have been lots of ideas, all just in code, from now on, adding here, what i feel... - -* UI libraries -> - Consider using libraries that have been made for multi threaded applications, or better handle those cases. Some considerables are -> - 1. https://github.com/wjakob/nanogui - 2. https://github.com/dankamongmen/notcurses - -* I/O -> - Likely not required with the UI libraries, but likely for logging another stream maybe required. Some considerations are -> - 1. https://github.com/expnkx/fast_io - -* Multi-Threading -> - Since this project HEAVILY depends on asynchronous and multithreading approach, so better use a thread pool too in later time, for removing some of the overhead of creating and destroying threads again and again - There are likely multiple thread pool implementations, use one of them. - -## Source of Idea - - Steins Gate (Anime) - - and... - - My Interest, and thinking 😎😎 - - -:copyright: Aditya Gupta 2020 +# World Line Simulator + +Wait... if you are thinking it's some big rendering project, sorry but it's not, +it enjoys this condition -> + +_Think about a world, in which 4 snakes keep moving automatically to get food_ + +And, this project generalises this idea to entities and actions, in different worlds and worldlines, as well theoretically different verses too, other than this -> +_And... you can go to a particular time in **past**, and change the position of one of the snakes... Baammm, a new world line is created in which this event happened, and the older world had the event not taken place... so there is a high chance, current state(lengths of the snakes) of the world will be different than what had been in the previous world line_ + +That's it, this project does this much mainly (though no limitations on what it may add later). + +It also features a constantly growing matrix (the world_plot). + +### Building + +**READ THE NOTE AFTER THESE COMMANDS** + +```sh +cd worldLineSim/build # if doesn't exist, then create +cmake .. +cmake --build . +``` + +> Now depending on your compiler, you will have a `simulator` or `simulator.exe`, which is the executable after building, you can run it then + +_NOTE_ - + 1. Still doesn't use all the functions. + 2. It has been built without linking(referencing) to all features(functions) just so to know how it works at that particular time + 3. There maybe commits in the master branch itself, that WON'T BUILD, but i will make sure to either build it, or remove the command area for the time being then + +### NOTE - +1. Currently all commits are on the master branch itself, and not on a separate dev branch, since i prefer to keep track of all my 'initial + work on master itself (this thing will change once the initial idea is done) +2. Initially the focus is that _internally_ the simulation happens, but maybe the display won't be very great now (Since, I don't have a ground in rendering things currently, if you have ideas, or suggestions do put in that pinned issue) + +## Flags used in code + +Various flags (inside comments), have been used to convey some messages to the developer -> +* `@todo` - These comments show that particular thing is to be done +* `@future` - These are tasks to be done, AFTER the basic idea is done, say for example, an improvement to the begaviour or algorithm +* `@note` - Some information about the code given to a user, or a simple note to let you know how it might behave +* `@warning` - A caution note to the reader (generally telling that you should call other function for cleaning the resources used (pointers, thread etc.)) +* `@debug` - These signify the part of code that is only there for debugging purposes, and should be removed later for actual accepted behaviour +* `@me` - Notes to myself +* `@deprecated` - Portions of codes, or functions that won't be used (likely not used in the code), and will be removed with the following commits + +Other than these, usual single line comments, are 'low-priority comments' more general than these + +And, multi line comments are generally for briefly telling about some struct or class + +# Class Chart + +> Made with draw.io + +![Class Chart](https://raw.githubusercontent.com/AdityaGupta150/Sources/main/worldLineSim.png "WorldLine Sim") + +## Future Ideas + +> There have been lots of ideas, all just in code, from now on, adding here, what i feel... + +* UI libraries -> + Consider using libraries that have been made for multi threaded applications, or better handle those cases. Some considerables are -> + 1. https://github.com/wjakob/nanogui + 2. https://github.com/dankamongmen/notcurses + +* I/O -> + Likely not required with the UI libraries, but likely for logging another stream maybe required. Some considerations are -> + 1. https://github.com/expnkx/fast_io + +* Multi-Threading -> + Since this project HEAVILY depends on asynchronous and multithreading approach, so better use a thread pool too in later time, for removing some of the overhead of creating and destroying threads again and again + There are likely multiple thread pool implementations, use one of them. + +## Source of Idea + + Steins Gate (Anime) + + and... + + My Interest, and thinking 😎😎 + + +:copyright: Aditya Gupta 2020 diff --git a/display/display.hpp b/display/display.hpp index 9eaa7d0..af4a012 100644 --- a/display/display.hpp +++ b/display/display.hpp @@ -1,130 +1,35 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include // for std::call_once, and std::once_flag - -#include "forward_decl.hpp" -#include "multiTerm/single_term.hpp" -#include "display/curses_subwin.hpp" -#include "display/node_adapter.hpp" - - // @note - The queue member functions return World_Node* not the adapters (The adapters are meant to be modified by this class itself) -struct _8_node_queue{ // @note - It has been separately defined as a wrapper class to std::queue, specially to be used by class Display, and to avoid all these if statements checking always in different functions that will be operating with the queue - std::list data; // @note - We may need to use list, since we also want random access, say to the 5th node currently on display on the screen - // std::list> adapters; - std::list< std::weak_ptr > adapters; - - public: - // START - Typical Queue Operations - auto front() noexcept { - return data.front(); - } - - auto back() noexcept { - return data.back(); - } - - auto push(World_Node* node, std::shared_ptr& adapter) { - if (data.size() >= 8) this->pop(); - - this->data.push_back(node); - this->adapters.push_back(adapter); - } - - void pop(){ - this->data.pop_front(); - this->adapters.pop_front(); - } - - auto size() noexcept { // sure to be <= 8 - return data.size(); - } - // END - Typical Queue Operations - - _8_node_queue(){} - -}; - -/* This class will just `hold` everything, with all handling of `its members` being controlled by the parent verse object */ -class Display : protected single_term, public std::enable_shared_from_this{ - typedef std::shared_ptr SubWindow_Ptr; - typedef std::shared_ptr Display_Ptr; - -public: - bool paused{ true }; -// std::once_flag disp_once_flag; // @deprecated - Was in use when std::call_once was being used to call updateDisplay() - - std::shared_ptr newNodeAdapter(World_Node* node); - void runInitTasks() override; - void printScreen(); - void updateScreen(); - -// std::condition_variable event_convar; // not needed, work done by mutex - std::mutex event_mutex; // used to lock mutex so that ONLY ONE thread accesses it during each time interval the display is active - void startEventLoop(); - - /** - * @note - Display::render() shouldn't be used anymore - * @why - Since curses is not gauranteed to be thread safe - * - * What it was doing is, in a while loop, every 200ms it will update the screen - * Consider the scenario, when a node_adapter WRITES to it's own subwindow, (WHICH IS PART OF the main_area), and simultaneously, Display::render writes something at same position through main_area, this is the problem, this shouldn't be a problem but i am not sure if modifying a window and its subwindow is safe or not - * - * @implications -> Since we wont use it, we will need 3 functions -> printScreen(), updateScreen() AND a clickHandler() - * Also, i first decided to use std::call_once for calls to Display::updateScreen() - * But, now i have found std::timed_mutex, it seems more appropriate, ie. the function will be called once for the interval, and also it will be waiting for that much interval, GREAT - */ - void render(); - void showExit(); - void helpScreen(); // @bug - Doesn't work as of 21st Nov 20 - void optionScreen(); // shows options -> 1. View verse state; 2. View help - void runPreEndTasks(); - void resumeRendering(); - void pauseRendering(); - - Display(Display&) = delete; - Display(Verse*); - ~Display(); - -private: - Verse* parent_verse; - - static constexpr char QUIT_KEY{ 'q' }; - static constexpr char HELP_KEY{ 'h' }; - - int adapters_height{ 10 }; - int adapters_width{ 17 }; // these should be same for all, as of the current situation - // @future - Try to make these adapt to, for eg. more snakes, so ONLY the next code for determining the position should need change, after the y_length, and x_length aren't same for all node_adapters anymore - - _8_node_queue queue; // pointers to world_nodes - - SubWindow_Ptr top_area, main_area, legend_area; - - std::vector> occupy_table; /* the occupy table keeps record of what regions are occupied (also called, occupancy_table) */ - std::timed_mutex dispMutex; - - struct - { - private: - std::function kbhit = [](char key, Display_Ptr source) { - if (source == nullptr) { - throw std::invalid_argument("Source to kbhit handler is null"); - } - - if (key == Display::QUIT_KEY) { - source->reset_curses(); // free up memory - source->pauseRendering(); - } - }; - - friend void Display::startEventLoop(); // @note @important -> MUST be on a different thread than main thread - } handlers; - - friend class node_adapter; - friend class Verse; -}; +#pragma once + +#include "adapter.hpp" +#include + +class Verse; // forward-decl + +class Display { + bool shouldStop{false}; // apart from this the shouldWindowClose() will be considered too + Verse* parent_verse; + std::chrono::high_resolution_clock::time_point loggingStart; + +public: + void showInitiating(); + void startDisplay(); + void displayCurrentState() const; + void showExiting(); + void stopDisplay(); + + // not using node_adapter currently, not much deep info is needed + std::shared_ptr newNodeAdapter(World_Node* node); + + + void helpScreen(); + void updateScreen(); + + + bool paused{ false }; // @deprecated + void resumeRendering(); // @deprecated + void pauseRendering(); // @deprecated + + + void showExit(); + Display(Verse*); +}; diff --git a/display/ludo_disp.hpp b/display/ludo_disp.hpp deleted file mode 100644 index fb98ef0..0000000 --- a/display/ludo_disp.hpp +++ /dev/null @@ -1,79 +0,0 @@ - // @note - This is the new display to be used - -#pragma once - -#include "forward_decl.hpp" -#include "curses_subwin.hpp" - -#include "curses.h" - -#include -#include -#include - -class Display -{ - typedef int32_t dimen_t; - typedef std::shared_ptr SubWindow_Ptr; -private: - static void sig_handler(int signal); - std::array sub_windows; - SubWindow_Ptr titleBar{ nullptr }, - * boardArea{ nullptr }, - * scoreArea{ nullptr }, - * dieArea{ nullptr }; - - SubWindow_Ptr ludoBoard{ nullptr }; // subwindow of `boardArea` - dimen_t y_term_dimen, x_term_dimen; - -public: - static bool curses_initiated; - - static void endCurses(); - - Display(); - ~Display(); -}; - -Display::Display() -{ - initscr(); - signal( SIGINT, Display::sig_handler ); - - getmaxyx( stdscr, this->y_term_dimen, this->x_term_dimen ); - this->sub_windows[0].reset(new SubWindow(3, 0, 0, 0)); - this->sub_windows[1] = subwin(stdscr, 0, x_term_dimen*0.75f, 3, 0); - this->sub_windows[2] = subwin(stdscr, (y_term_dimen - 3) * 0.8f, 0, 3, x_term_dimen * 0.75f); - this->sub_windows[3] = subwin(stdscr, 0, 0, 3 + (y_term_dimen - 3) * 0.8f, x_term_dimen * 0.75f); - - this->titleBar = sub_windows[0]; - this->boardArea = sub_windows[1]; - this->scoreArea = sub_windows[2]; - this->dieArea = sub_windows[3]; - - // box( dieArea, ACS_LANTERN, ACS_HLINE ); - for (auto *win : this->sub_windows) - { - if( win ){ - box( win, ACS_VLINE, ACS_HLINE ); - } - } - - refresh(); -} - -Display::~Display() -{ - if( ! Display::curses_initiated ){ - Display::endCurses(); - } -} - -void Display::endCurses(){ - endwin(); - Display::curses_initiated = false; -} - -void Display::sig_handler(int signal){ - Display::endCurses(); -} diff --git a/display/node_adapter.hpp b/display/node_adapter.hpp deleted file mode 100644 index abdd83e..0000000 --- a/display/node_adapter.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "forward_decl.hpp" -#include "graphMat/util/coord.hpp" -#include "display/curses_subwin.hpp" - -class node_adapter{ - typedef util::_coord3D coordinate; // on a screen so won't need anything bigger than an int - typedef std::shared_ptr DispMngr; - typedef World_Node* World_Node_Ptr; -// private: -public: - SubWindow window; // @note @caution -> The node_adapter's SubWindow isn't meant to be passed around ! (If tried to create a shared_ptr from this, will give double free) - DispMngr dispMngr; // @todo - Make this a non-modifieable by this class (should always point to same dispMngr) - - // the further data can be replaced by having a pointer t the wrld_node instead of all this individually - size_t node_id; - const World_Node_Ptr node; - - node_adapter(DispMngr dispMngr, World_Node_Ptr world_node, int height, int width,int y_corner, int x_corner); - -public: - void disable(); // once disabled, can NOT be enabled again for NOW (since we can't chose which worlds to show and which ones not to show) ! - void update(); - - node_adapter() = delete; - ~node_adapter(){} - - friend class Display; -}; diff --git a/display/src/display.cpp b/display/src/display.cpp index 9394b77..95c4c33 100644 --- a/display/src/display.cpp +++ b/display/src/display.cpp @@ -1,326 +1,326 @@ -// @note @future -> Later try to get this into a single display.hpp for easier use with modifications later on - -#include "verse.hpp" -#include "display/display.hpp" -#include "display/node_adapter.hpp" - -void Display::pauseRendering(){ - this->paused = true; - - this->clearAll(); -} - -void Display::resumeRendering(){ - this->paused = false; -} - -// @note - Display::startEventLoop() MUST be on a different thread than main thread -void Display::startEventLoop() { // MUST BE CALLED ONLY ONCE DURING EACH INTERVAL IN WHICH THE DISPAY is active - if (!this->event_mutex.try_lock()) { - return; // return immediately if some other thread already is managing the event loop - } - - this->event_mutex.lock(); - - // to add other event sources to the event loop, other events can be added, for now ONLY kbhit even is there - auto kb_event = this->get_async_input(); - while ( ! this->paused ) - { - kb_event.wait(); // @caution -> It is blocking, but shouldn't actually be consuming all of CPU power ! - this->handlers.kbhit(kb_event.get(), this->shared_from_this()); - } - this->event_mutex.unlock(); -} - -std::shared_ptr Display::newNodeAdapter(World_Node* node){ - // @note - Not using the_occupy_currently - this->main_area->updateDimen(); - this->pauseRendering(); - - int y_corner; - int x_corner; - int index_num = queue.size(); - if(index_num == 8){ - queue.pop(); - - index_num = 7; - } - - int bigBox_coord_x; - int bigBox_coord_y; // the big box's corner coord - - bigBox_coord_y = ((main_area->getmax_y()+1)/2) * (index_num / 4); // first row or second row - bigBox_coord_x = ((main_area->getmax_x()+1)/4) * (index_num % 4); - - if( index_num %2 == 0 ){ - y_corner = bigBox_coord_y; - }else{ - y_corner = bigBox_coord_y + 2; // 2 lines below - } - - // here what we want is to `horizonatlly center` the node_adapter inside this big_box - x_corner = bigBox_coord_x + ( (main_area->getmax_x()+1)/4 - adapters_width ) / 2; - - std::shared_ptr adapter{ - new node_adapter( - this->shared_from_this(), - node, - this->adapters_height, - this->adapters_width, - y_corner, - x_corner - ) - }; - - queue.push(adapter->node, adapter); - - adapter->update(); // get it on screen - this->main_area->refresh(); - - return adapter; -} - -void Display::helpScreen(){ - using namespace std::chrono_literals; - - this->curses_init(); // @note - single_term itself manages if curses is already initialised - - this->resumeRendering(); - this->main_area->disable(); - this->legend_area->disable(); - - SubWindow helpArea{ 0, 0, 3, 0 }; // don't make it a raw pointer, since for it's destructor to be called, it's scope should end, which won't happen if we use new SubWindow, with raw pointer - - helpArea.box(); - auto async_input = this->get_async_input(); - - helpArea.addstr(1, 1, "Help Guide"); - helpArea.nladdstr("===================="); - - helpArea.newline(); - helpArea.nladdstr("*All worlds continue on diff. threads,w/o blocking the display, or the verse"); - - helpArea.newline(); - - helpArea.nladdstr("- Type the id to chose a particular world"); - - helpArea.nladdstr("- Commands"); - helpArea.nladdstr("- N - Namaste World(New)"); - helpArea.nladdstr("- P - Pause"); - helpArea.nladdstr("- R - Resume"); - helpArea.nladdstr("- T - Time Travel !!"); - helpArea.nladdstr("- L - Logs (of World)"); - helpArea.nladdstr("- V - Logs (of Verse)"); - - helpArea.addstr(-3, 1, "If you find a problem..."); - helpArea.nladdstr("Please solve it yourselves"); - helpArea.nladdstr(":copy: AdityaG15 :D"); - - top_area->addstr(title, position::MIDDLE); - - int cur_dimen_y, cur_dimen_x; - getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); - while( true ){ - main_area->updateDimen(); - legend_area->updateDimen(); - - getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); - if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ - this->clearAll(); // to clean out the previous borders - } - - top_area->box(); - main_area->box(); - legend_area->box(); - - this->refreshAll(); - - if( async_input.wait_for(100ms) == std::future_status::ready ){ - char c = async_input.get(); - try{ - if(c == Display::QUIT_KEY){ - this->reset_curses(); // free up memory - - return; - } - helpArea.refresh(); - }catch(std::future_error&){ - raise(SIGTERM); - - this->parent_verse->kaal_day("Display"); - return; - } - - if( c == Display::QUIT_KEY ) return; - helpArea.refresh(); - async_input = this->get_async_input(); // restart that task - } - - std::this_thread::sleep_for(200ms); - } - - this->optionScreen(); - -} - -void Display::optionScreen(){ - // @future @todo -> read comment in the declaration, and implement it -} - -void Display::printScreen(){ - this->runInitTasks(); // set the subwindows - - this->updateScreen(); -} - -void Display::updateScreen(){ - using namespace std::chrono_literals; - if ( ! this->dispMutex.try_lock_for(1s)) { // there will be gap of ATLEAST 1 second before any updations happen on screen - return; // so repeating threads in same interval of time, will exit - } - - this->dispMutex.lock(); - if( !top_area || !main_area || !legend_area ) - this->runInitTasks(); - - legend_area->addstr(1, 1, "Legend"); - - legend_area->nladdstr("*All worlds continue on diff. threads,w/o blocking the display, or the verse"); - - legend_area->newline(); - - legend_area->nladdstr("- Type the id to chose a particular world"); - - legend_area->nladdstr("- Commands"); - legend_area->nladdstr("- N - Namaste World(New)"); - legend_area->nladdstr("- P - Pause"); - legend_area->nladdstr("- R - Resume"); - legend_area->nladdstr("- T - Time Travel !!"); - legend_area->nladdstr("- L - Logs (of World)"); - legend_area->nladdstr("- V - Logs (of Verse)"); - - legend_area->addstr(-3, 1, "If you find a problem..."); - legend_area->nladdstr("Please solve it yourselves"); - legend_area->nladdstr(":copy: AdityaG15 :D"); - - int cur_dimen_y, cur_dimen_x; - getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); - - main_area->updateDimen(); - legend_area->updateDimen(); - - getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); - if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ - wclear(stdscr); // to clean out the previous borders - } - - top_area->box(); - main_area->box(); - legend_area->box(); - - top_area->moveCursor(1,1); - top_area->addstr(title, position::MIDDLE); - - wrefresh(stdscr); - this->dispMutex.unlock(); - -} - -void Display::runInitTasks(){ - - this->curses_init(); // also handles the case when curses wis already initialised - - if( !top_area ) this->top_area.reset( new SubWindow( 3, 0, 0, 0 ) ); - if( !main_area ) this->main_area.reset( new SubWindow( 0, 0.8f * _terminal_x, 3, 0 ) ); - if( !legend_area ) this->legend_area.reset( new SubWindow( 0, 0, 3, 0.8f*_terminal_x ) ); - - if( top_area->enabled ) this->top_area->enable(); - if( main_area->enabled ) this->top_area->enable(); - if( legend_area->enabled ) this->top_area->enable(); - - this->resumeRendering(); - std::thread(&Display::startEventLoop, this).detach(); // the event loop should be on a different thread - -} - -// @deprecated -void Display::render(){ - using namespace std::chrono_literals; - - printScreen(); // start of with an already printed screen - - auto async_input = this->get_async_input(); - - int cur_dimen_y, cur_dimen_x; - getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); - while( ! this->paused ){ - main_area->updateDimen(); - legend_area->updateDimen(); - - getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); - if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ - wclear(stdscr); // to clean out the previous borders - } - - top_area->box(); - main_area->box(); - legend_area->box(); - - top_area->moveCursor(1,1); - top_area->addstr(title, position::MIDDLE); - - wrefresh(stdscr); - - // time to take input - if( async_input.wait_for(100ms) == std::future_status::ready ){ - legend_area->addstr(static_cast(0.75f*legend_area->getmax_y()), 1, "You entered -> "); - char c; - try{ - c = async_input.get(); - legend_area->addch(c); - - if(c == Display::QUIT_KEY){ - this->reset_curses(); // free up memory - this->pauseRendering(); - - // @note - Or maybe use inter thread communication here, using condition_variable, so to wait till verse tells all done, then this will return, and the destructor again sends signal to verse after all things done in destructor, then verse can be sure that all destructed - // @note - UNCOMMENT next line, later - // return this->parent_verse->kaal_day("Display"); // also passing the source so that it doesn't actually try to end this - return; - }else if(c == Display::HELP_KEY) - { - this->clearAll(); - return this->helpScreen(); - } - - legend_area->refresh(); - }catch(std::future_error & e){ - raise(SIGTERM); - - this->parent_verse->kaal_day("Display"); - return; - } - - if( c == Display::QUIT_KEY ) return; - legend_area->refresh(); - async_input = this->get_async_input(); // restart that task - } - - std::this_thread::sleep_for(200ms); - } -} - -void Display::showExit(){ - clear(); - clearAll(); - - mvwaddstr(stdscr, this->_terminal_y/2, (this->_terminal_x - 15)/2, "About to Exit !"); -} - -Display::Display(Verse* parent) : - single_term("WorldLine Simulator v0.271", "Created by Aditya Gupta and Steins; Gate"), - parent_verse(parent){} - -Display::~Display(){ - -} +#include "../display.hpp" +// @note @future -> Later try to get this into a single display.hpp for easier use with modifications later on + +#include "adapter.hpp" +#include "verse.hpp" +#include "world_tree.hpp" + +#include + +using std::chrono::high_resolution_clock; +void Display::showInitiating() { + std::clog << '[' << (high_resolution_clock::now() - loggingStart).count() << ']' << " Initiating...\n"; +} + +void Display::displayCurrentState() const { + std::clog << "Total " << this->parent_verse->worldTree->num_nodes << " nodes in the world tree\n"; +} + +void Display::startDisplay() { + std::clog << '[' << (high_resolution_clock::now() - loggingStart).count() << ']' << " Display Started...\n"; + + while (!shouldStop) + { + displayCurrentState(); // only for console logging + + std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); // 60 Hz + } +} + +void Display::showExiting() { + //clear(); + //clearAll(); + + //mvwaddstr(stdscr, this->_terminal_y/2, (this->_terminal_x - 15)/2, "About to Exit !"); + std::clog << "Exiting..."; +} + +void Display::stopDisplay() { + std::clog << "Exiting NOW!"; +} + + +void Display::pauseRendering(){ + this->paused = true; +} + +void Display::resumeRendering(){ + this->paused = false; +} + +std::shared_ptr Display::newNodeAdapter(World_Node* node){ + // @note - Not using the_occupy_currently + //this->main_area->updateDimen(); + //this->pauseRendering(); + + //int y_corner; + //int x_corner; + //int index_num = queue.size(); + //if(index_num == 8){ + // queue.pop(); + + // index_num = 7; + //} + + //int bigBox_coord_x; + //int bigBox_coord_y; // the big box's corner coord + + //bigBox_coord_y = ((main_area->getmax_y()+1)/2) * (index_num / 4); // first row or second row + //bigBox_coord_x = ((main_area->getmax_x()+1)/4) * (index_num % 4); + + //if( index_num %2 == 0 ){ + // y_corner = bigBox_coord_y; + //}else{ + // y_corner = bigBox_coord_y + 2; // 2 lines below + //} + + // // here what we want is to `horizonatlly center` the DisplayAdapter inside this big_box + //x_corner = bigBox_coord_x + ( (main_area->getmax_x()+1)/4 - adapters_width ) / 2; + + //std::shared_ptr adapter{ + // new DisplayAdapter( + // this->shared_from_this(), + // node, + // this->adapters_height, + // this->adapters_width, + // y_corner, + // x_corner + // ) + //}; + + //queue.push(adapter->node, adapter); + + //adapter->update(); // get it on screen + //this->main_area->refresh(); + + //return adapter; + return nullptr; +} + +void Display::helpScreen(){ + //using namespace std::chrono_literals; + + //this->curses_init(); // @note - single_term itself manages if curses is already initialised + + //this->resumeRendering(); + //this->main_area->disable(); + //this->legend_area->disable(); + + //SubWindow helpArea{ 0, 0, 3, 0 }; // don't make it a raw pointer, since for it's destructor to be called, it's scope should end, which won't happen if we use new SubWindow, with raw pointer + + //helpArea.box(); + //auto async_input = this->get_async_input(); + // + //helpArea.addstr(1, 1, "Help Guide"); + //helpArea.nladdstr("===================="); + + //helpArea.newline(); + //helpArea.nladdstr("*All worlds continue on diff. threads,w/o blocking the display, or the verse"); + + //helpArea.newline(); + + //helpArea.nladdstr("- Type the id to chose a particular world"); + + //helpArea.nladdstr("- Commands"); + //helpArea.nladdstr("- N - Namaste World(New)"); + //helpArea.nladdstr("- P - Pause"); + //helpArea.nladdstr("- R - Resume"); + //helpArea.nladdstr("- T - Time Travel !!"); + //helpArea.nladdstr("- L - Logs (of World)"); + //helpArea.nladdstr("- V - Logs (of Verse)"); + + //helpArea.addstr(-3, 1, "If you find a problem..."); + //helpArea.nladdstr("Please solve it yourselves"); + //helpArea.nladdstr(":copy: AdityaG15 :D"); + + //top_area->addstr(title, position::MIDDLE); + + //int cur_dimen_y, cur_dimen_x; + //getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); + //while( true ){ + // main_area->updateDimen(); + // legend_area->updateDimen(); + + // getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); + // if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ + // this->clearAll(); // to clean out the previous borders + // } + + // top_area->box(); + // main_area->box(); + // legend_area->box(); + + // this->refreshAll(); + + // if( async_input.wait_for(100ms) == std::future_status::ready ){ + // char c = async_input.get(); + // try{ + // if(c == Display::QUIT_KEY){ + // this->reset_curses(); // free up memory + + // return; + // } + // helpArea.refresh(); + // }catch(std::future_error&){ + // raise(SIGTERM); + + // this->parent_verse->kaal_day("Display"); + // return; + // } + + // if( c == Display::QUIT_KEY ) return; + // helpArea.refresh(); + // async_input = this->get_async_input(); // restart that task + // } + + // std::this_thread::sleep_for(200ms); + //} + + //this->optionScreen(); + +} + +void Display::updateScreen(){ + //using namespace std::chrono_literals; + //if ( ! this->dispMutex.try_lock_for(1s)) { // there will be gap of ATLEAST 1 second before any updations happen on screen + // return; // so repeating threads in same interval of time, will exit + //} + + //this->dispMutex.lock(); + //if( !top_area || !main_area || !legend_area ) + // this->runInitTasks(); + + //legend_area->addstr(1, 1, "Legend"); + + //legend_area->nladdstr("*All worlds continue on diff. threads,w/o blocking the display, or the verse"); + + //legend_area->newline(); + + //legend_area->nladdstr("- Type the id to chose a particular world"); + + //legend_area->nladdstr("- Commands"); + //legend_area->nladdstr("- N - Namaste World(New)"); + //legend_area->nladdstr("- P - Pause"); + //legend_area->nladdstr("- R - Resume"); + //legend_area->nladdstr("- T - Time Travel !!"); + //legend_area->nladdstr("- L - Logs (of World)"); + //legend_area->nladdstr("- V - Logs (of Verse)"); + + //legend_area->addstr(-3, 1, "If you find a problem..."); + //legend_area->nladdstr("Please solve it yourselves"); + //legend_area->nladdstr(":copy: AdityaG15 :D"); + + //int cur_dimen_y, cur_dimen_x; + //getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); + + //main_area->updateDimen(); + //legend_area->updateDimen(); + + //getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); + //if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ + // wclear(stdscr); // to clean out the previous borders + //} + + //top_area->box(); + //main_area->box(); + //legend_area->box(); + + //top_area->moveCursor(1,1); + //top_area->addstr(title, position::MIDDLE); + + //wrefresh(stdscr); + //this->dispMutex.unlock(); + +} + +#if 0 +void Display::runInitTasks(){ + + this->curses_init(); // also handles the case when curses wis already initialised + + if( !top_area ) this->top_area.reset( new SubWindow( 3, 0, 0, 0 ) ); + if( !main_area ) this->main_area.reset( new SubWindow( 0, 0.8f * _terminal_x, 3, 0 ) ); + if( !legend_area ) this->legend_area.reset( new SubWindow( 0, 0, 3, 0.8f*_terminal_x ) ); + + if( top_area->enabled ) this->top_area->enable(); + if( main_area->enabled ) this->top_area->enable(); + if( legend_area->enabled ) this->top_area->enable(); + + this->resumeRendering(); + std::thread(&Display::startEventLoop, this).detach(); // the event loop should be on a different thread + +} + +// @deprecated +void Display::render(){ + using namespace std::chrono_literals; + + printScreen(); // start of with an already printed screen + + auto async_input = this->get_async_input(); + + int cur_dimen_y, cur_dimen_x; + getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); + while( ! this->paused ){ + main_area->updateDimen(); + legend_area->updateDimen(); + + getmaxyx(stdscr, cur_dimen_y, cur_dimen_x); + if( cur_dimen_y != _terminal_y || cur_dimen_x != _terminal_x ){ + wclear(stdscr); // to clean out the previous borders + } + + top_area->box(); + main_area->box(); + legend_area->box(); + + top_area->moveCursor(1,1); + top_area->addstr(title, position::MIDDLE); + + wrefresh(stdscr); + + // time to take input + if( async_input.wait_for(100ms) == std::future_status::ready ){ + legend_area->addstr(static_cast(0.75f*legend_area->getmax_y()), 1, "You entered -> "); + char c; + try{ + c = async_input.get(); + legend_area->addch(c); + + if(c == Display::QUIT_KEY){ + this->reset_curses(); // free up memory + this->pauseRendering(); + + // @note - Or maybe use inter thread communication here, using condition_variable, so to wait till verse tells all done, then this will return, and the destructor again sends signal to verse after all things done in destructor, then verse can be sure that all destructed + // @note - UNCOMMENT next line, later + // return this->parent_verse->kaal_day("Display"); // also passing the source so that it doesn't actually try to end this + return; + }else if(c == Display::HELP_KEY) + { + this->clearAll(); + return this->helpScreen(); + } + + legend_area->refresh(); + }catch(std::future_error & e){ + raise(SIGTERM); + + this->parent_verse->kaal_day("Display"); + return; + } + + if( c == Display::QUIT_KEY ) return; + legend_area->refresh(); + async_input = this->get_async_input(); // restart that task + } + + std::this_thread::sleep_for(200ms); + } +} +#endif + +Display::Display(Verse* parent) : + //title("WorldLine Simulator v0.271", "Created by Aditya Gupta and Steins; Gate"), + parent_verse(parent), + loggingStart(std::chrono::high_resolution_clock::now()) +{} diff --git a/display/src/node_adapter.cpp b/display/src/node_adapter.cpp deleted file mode 100644 index 1206a2c..0000000 --- a/display/src/node_adapter.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// there was a circular dependency b/w display.hpp and node_adapter.hpp, that's why this has been segregated - -#include // for std::call_once - -#include "display/node_adapter.hpp" -#include "display/display.hpp" -#include "display/curses_subwin.hpp" -#include "world_node.hpp" - -node_adapter::node_adapter(DispMngr dispMngr, World_Node_Ptr world_node, int height, int width,int y_corner, int x_corner) - : node(world_node), - dispMngr(dispMngr), - window(dispMngr->main_area, height, width, y_corner, x_corner) -{ - if (!node) throw std::invalid_argument("A non-null world pointer is required"); - - this->node_id = node->getId(); - - window.box(ACS_VLINE, '-'); - - window.moveCursor(1, 1); - window.addstr(std::to_string(this->node_id).data(), position::MIDDLE); - window.hline(); - - window.newline(); - window.printf("Dimen - (%, %)", this->node->get_world_dimen(), this->node->get_world_dimen()); - // window.printf("Dimen - (, )"); - - for (int i = 0; i < 4; i++) - { - window.newline(); - // window.printf("E - (, ), "); // snake number/id, head_coord.x, head_coord.y, points of snake - window.printf("E% - (%, %), %", i+1); // snake number/id, head_coord.x, head_coord.y, points of snake - } - - window.refresh(); - wrefresh(stdscr); -} - -void node_adapter::update(){ // updates the content on the window, with updated content from the world_naode that is linked - if( this->dispMngr->paused ) return; - - // @todo - Handle the display here - - dispMngr->updateScreen(); - //std::call_once( this->dispMngr->disp_once_flag, &Display::updateScreen, this->dispMngr ); -} diff --git a/display/src/curses_subwin.cpp b/display/src/subwin.cpp similarity index 96% rename from display/src/curses_subwin.cpp rename to display/src/subwin.cpp index f17b96d..f0fe562 100644 --- a/display/src/curses_subwin.cpp +++ b/display/src/subwin.cpp @@ -1,138 +1,142 @@ -#include "display/curses_subwin.hpp" -#include - -void SubWindow::box(chtype vline, chtype hline){ - if( this->win ){ - // ::box(win.get(), ((vline != '\0') ? vline: ACS_VLINE) , ((hline != '\0') ? hline: ACS_HLINE)); // calling the one available in global scope - ::box(win.get(), vline , hline); // calling the one available in global scope - } - this->boxed = true; - - this->updateDimen(); -} - -void SubWindow::hline(chtype ch){ - this->updateDimen(); - ++last_write_pos.n_row; - - ::mvwhline( - this->win.get(), - last_write_pos.n_row, - last_write_pos.n_col, - ch, - dimensions.n_col - (boxed ? 2: 0) /*if boxed then create the line with (width-2)*/ - ); -} - -void SubWindow::refresh(){ - ::wrefresh(this->win.get()); - this->updateDimen(); -} - -void SubWindow::refreshParent(){ - ::wrefresh(this->parent_win->win.get()); - this->updateDimen(); -} - -void SubWindow::disable(){ - if( !this->enabled ) return; - - if( this->win.use_count() == 1 ){ // @caution @ignore - Read about shared_ptr::unique and shared_ptr::use_count(), these are not really accurate in multi-threading cases, where another thread has a reference to this shared_ptr - delwin(this->win.get()); - } - this->win.reset(); - dimensions.n_col = 0; - dimensions.n_row = 0; - - this->enabled = false; -} - -bool SubWindow::isEnabled(){ - return this->enabled; -} - -void SubWindow::enable(){ - if( this->enabled ) return; - - if( !this->win ){ - if( !this->parent_win ) - this->win.reset(subwin(stdscr, dimensions.n_row, dimensions.n_col, y_corner, x_corner)); - else - this->win.reset(subwin(this->parent_win->win.get(), dimensions.n_row, dimensions.n_col, y_corner, x_corner)); - } - - this->enabled = true; - this->updateDimen(); -} - -// @note - It is expected that updateDimen() was called recently before accessing these getmax methods -int SubWindow::getmax_x(){ - return this->dimensions.n_row; -} -int SubWindow::getmax_y(){ - return this->dimensions.n_col; -} - -void SubWindow::updateDimen(){ - // @note - May require mutex locks, to prevent multiple threads trying to wriet to the same thing - getmaxyx(win.get(), dimensions.n_col, dimensions.n_row); -} - -void SubWindow::addch(char ch){ - waddch(this->win.get(), ch); -} - -void SubWindow::addstr(std::string_view str, position pos){ - if( pos != position::AT_CURS ){ - this->updateDimen(); - if( pos == position::LEFT ) - if( boxed ) this->moveCursor(last_write_pos.n_row, 1); - else this->moveCursor(last_write_pos.n_row, 0); - else if( pos == position::RIGHT ) - if( boxed ) this->moveCursor(last_write_pos.n_row, -1); - else this->moveCursor(last_write_pos.n_row, dimensions.n_col); - else if( pos == position::MIDDLE ) - this->moveCursor(last_write_pos.n_row, (dimensions.n_col - static_cast(str.size())) / 2); - } - - // if boxed, then see if, (str.size() - 2), 2 for the border (right and left) - if( (str.size() - (boxed ? 2 : 0)) > this->dimensions.n_col ){ - // @todo - Case when string length is larger than available screen space - } - waddstr(this->win.get(), str.data()); -} - -/** - * @note - If either of row or col is negative, then it will be understood as max-the_value, for eg. row = -1, will be row = getmaxx(this->win.get())-1 -*/ -void SubWindow::addstr(int row, int col, std::string_view str){ - if( row < 0 ) - row = getmaxy(this->win.get()) - row; - - if( col < 0 ) - col = getmaxx(this->win.get()) - col; - - this->moveCursor(row, col); - return this->addstr(str); -} - -// move to the next line (NL), and add str -void SubWindow::nladdstr(std::string_view str, position pos){ - this->newline(); - this->addstr(str, pos); -} - -void SubWindow::printf(const char* format){ - this->addstr(format); -} - -void SubWindow::moveCursor(int row, int col){ - wmove(this->win.get(), row, col); - - last_write_pos.n_row = row; - last_write_pos.n_col = col; -} - -void SubWindow::newline(){ - this->moveCursor(last_write_pos.n_row + 1, last_write_pos.n_col); -} +#if 0 + +#include "display/curses_subwin.hpp" +#include + +void SubWindow::box(chtype vline, chtype hline){ + if( this->win ){ + // ::box(win.get(), ((vline != '\0') ? vline: ACS_VLINE) , ((hline != '\0') ? hline: ACS_HLINE)); // calling the one available in global scope + ::box(win.get(), vline , hline); // calling the one available in global scope + } + this->boxed = true; + + this->updateDimen(); +} + +void SubWindow::hline(chtype ch){ + this->updateDimen(); + ++last_write_pos.n_row; + + ::mvwhline( + this->win.get(), + last_write_pos.n_row, + last_write_pos.n_col, + ch, + dimensions.n_col - (boxed ? 2: 0) /*if boxed then create the line with (width-2)*/ + ); +} + +void SubWindow::refresh(){ + ::wrefresh(this->win.get()); + this->updateDimen(); +} + +void SubWindow::refreshParent(){ + ::wrefresh(this->parent_win->win.get()); + this->updateDimen(); +} + +void SubWindow::disable(){ + if( !this->enabled ) return; + + if( this->win.use_count() == 1 ){ // @caution @ignore - Read about shared_ptr::unique and shared_ptr::use_count(), these are not really accurate in multi-threading cases, where another thread has a reference to this shared_ptr + delwin(this->win.get()); + } + this->win.reset(); + dimensions.n_col = 0; + dimensions.n_row = 0; + + this->enabled = false; +} + +bool SubWindow::isEnabled(){ + return this->enabled; +} + +void SubWindow::enable(){ + if( this->enabled ) return; + + if( !this->win ){ + if( !this->parent_win ) + this->win.reset(subwin(stdscr, dimensions.n_row, dimensions.n_col, y_corner, x_corner)); + else + this->win.reset(subwin(this->parent_win->win.get(), dimensions.n_row, dimensions.n_col, y_corner, x_corner)); + } + + this->enabled = true; + this->updateDimen(); +} + +// @note - It is expected that updateDimen() was called recently before accessing these getmax methods +int SubWindow::getmax_x(){ + return this->dimensions.n_row; +} +int SubWindow::getmax_y(){ + return this->dimensions.n_col; +} + +void SubWindow::updateDimen(){ + // @note - May require mutex locks, to prevent multiple threads trying to wriet to the same thing + getmaxyx(win.get(), dimensions.n_col, dimensions.n_row); +} + +void SubWindow::addch(char ch){ + waddch(this->win.get(), ch); +} + +void SubWindow::addstr(std::string_view str, position pos){ + if( pos != position::AT_CURS ){ + this->updateDimen(); + if( pos == position::LEFT ) + if( boxed ) this->moveCursor(last_write_pos.n_row, 1); + else this->moveCursor(last_write_pos.n_row, 0); + else if( pos == position::RIGHT ) + if( boxed ) this->moveCursor(last_write_pos.n_row, -1); + else this->moveCursor(last_write_pos.n_row, dimensions.n_col); + else if( pos == position::MIDDLE ) + this->moveCursor(last_write_pos.n_row, (dimensions.n_col - static_cast(str.size())) / 2); + } + + // if boxed, then see if, (str.size() - 2), 2 for the border (right and left) + if( (str.size() - (boxed ? 2 : 0)) > this->dimensions.n_col ){ + // @todo - Case when string length is larger than available screen space + } + waddstr(this->win.get(), str.data()); +} + +/** + * @note - If either of row or col is negative, then it will be understood as max-the_value, for eg. row = -1, will be row = getmaxx(this->win.get())-1 +*/ +void SubWindow::addstr(int row, int col, std::string_view str){ + if( row < 0 ) + row = getmaxy(this->win.get()) - row; + + if( col < 0 ) + col = getmaxx(this->win.get()) - col; + + this->moveCursor(row, col); + return this->addstr(str); +} + +// move to the next line (NL), and add str +void SubWindow::nladdstr(std::string_view str, position pos){ + this->newline(); + this->addstr(str, pos); +} + +void SubWindow::printf(const char* format){ + this->addstr(format); +} + +void SubWindow::moveCursor(int row, int col){ + wmove(this->win.get(), row, col); + + last_write_pos.n_row = row; + last_write_pos.n_col = col; +} + +void SubWindow::newline(){ + this->moveCursor(last_write_pos.n_row + 1, last_write_pos.n_col); +} + +#endif diff --git a/display/curses_subwin.hpp b/display/subwin.hpp similarity index 96% rename from display/curses_subwin.hpp rename to display/subwin.hpp index 67aebce..9260240 100644 --- a/display/curses_subwin.hpp +++ b/display/subwin.hpp @@ -1,156 +1,161 @@ -#pragma once - -#include -#include "curses.h" -#include "graphMat/util/coord.hpp" - -#include -#include // for std::to_string - -enum class position{ // only horizontal positions for now - LEFT, - MIDDLE, - RIGHT, - AT_CURS // don't change, just print AT the cursor position -}; - -/* @caution - DONT manipulate WINDOW* pointers directly - If newwin() is needed, create a new class Window to handle memory allocation for that, currently it's not needed so leaving - */ -class SubWindow{ - typedef std::shared_ptr SubWindow_Ptr; // NO OWNERSHIP for the parent will be held here -public: - bool enabled{ false }; - void box(chtype = ' ', chtype = ' '); - void refreshParent(); - void refresh(); - bool isEnabled(); - void disable(); // @brief -> RESETS this->win to nullptr (All data used to construct is still stored, to enable at later stage) - void enable(); // @brief -> ALLOCATES this->win to nullptr (All data used to construct is still stored, to enable at later stage) - int getmax_x(); - int getmax_y(); - void updateDimen(); // @brief - Updates contents of this->dimensions - void newline(); // move to the next line (uses last_write_pos) - void moveCursor(int row, int col); - void hline(chtype = ACS_HLINE); // @brief -> Draws a horizontal line on NEXT LINE - void hline(int y, int x, char, int len); // not defined now, not needed - - /** - * @brief - Wrappers around waddstr() and mvwaddstr() - * @params - str - String, - * position - Position to print at (LEFT(AT_CURS), MIDDLE, RIGHT) - * row - Y dimension to write at - * col - X dimension to write at - */ - void addstr(std::string_view str, position = position::AT_CURS); - void addstr(int row, int col, std::string_view str); - // @future - Later implement the wrapper to mvwprintw() too, since it provides the formatted output - // @brief - Move to a new line, and add a string, there - void nladdstr(std::string_view str, position = position::AT_CURS); - - void addch(char ch); - - void printf(const char*); - - // definition of this templated function is REQUIRED here, so that the particular function can be formed by any file that includes curses_subwin.hpp - template - void printf(const char* format, T first_val, Types... next_vals){ - for( int i = 0; format[i] != '\0'; ++i ){ - if( format[i] == '%' ){ - if( std::is_integral::value ){ - this->addstr(std::to_string(first_val)); - } else if( std::is_same::value ){ - this->addch(first_val); - } else{ - // else ignore any other type - } - return this->printf(format + i + 1, next_vals...); - - // #if std::is_integral::value - // #elif std::is_same::value - // this->addch(first_val); - // #elif std::is_same::value - // this->addstr(first_val); - // #elif std::is_same::value || std::is_same::value - // this->addstr(first_val.data()); - // #else - // #endif - } else{ - this->addch(format[i]); - } - } - } - template - void printf(const char* format, std::string_view first_val, Types... next_vals){ - for( int i = 0; format[i] != '\0'; ++i ){ - if( format[i] == '%' ){ - this->addstr(first_val.data()); - return this->printf(format + i + 1, next_vals...); - } else{ - this->addch(format[i]); - } - } - } - - /** - * @important @note - The pairs will be in the form of row*col - * @brief - Uses stdscr as the parent screen - */ - SubWindow(const std::pair& dimensions, const std::pair& start_yx) : - SubWindow(dimensions.first, dimensions.second, start_yx.first, start_yx.second) - { - this->enabled = true; - } - SubWindow(SubWindow_Ptr& parent_win, const std::pair& dimensions, const std::pair& start_yx) : - SubWindow(parent_win, dimensions.first, dimensions.second, start_yx.first, start_yx.second) - { - this->enabled = true; - } - - SubWindow(int height, int width, int y_corner, int x_corner) : - dimensions{height, width}, - y_corner(y_corner), - x_corner(x_corner), - win(subwin(stdscr, height, width, y_corner, x_corner)) - { - this->updateDimen(); - this->enabled = true; - } - SubWindow(SubWindow_Ptr& parent_win, int height, int width, int y_corner, int x_corner) : - dimensions{height, width}, - y_corner(y_corner), - x_corner(x_corner), - parent_win(parent_win), - win(subwin(parent_win->win.get(), height, width, y_corner + parent_win->dimensions.n_row + 1, x_corner + parent_win->dimensions.n_col + 1)) // the corner params assume to be wrt. to stdscr - { - this->updateDimen(); - this->enabled = true; - } - - ~SubWindow(){ - // @note @future - for multi-threading, this next if MUST be atomic (for eg. two owners release the pointers simulateusly but for both this if may give false, that's the problem) - if( win.use_count() == 1 ){ // only we ourselves remain as its owner - // @note @caution - Currently the delwin() calls have been commented, since it's causing double free, since the smart pointer also implicitly calls reset() - // delwin(win.get()); - } - if( parent_win && parent_win.use_count() == 1 ){ - // delwin(parent_win->win.get()); - } - } - -private: - const int y_corner, x_corner; // data required for enable disable - struct { - int n_row; - int n_col; - }dimensions; - struct { - int n_row{ 0 }; - int n_col{ 0 }; - }last_write_pos; // last locations to which we wrote anything - bool boxed{ false }; // @caution - Currently no function is available that resets this to false (though, since it's not required in our case, leaving) - std::shared_ptr win; - SubWindow_Ptr parent_win; // @note - this shared_ptr will hold NOTHING, when parent window is stdscr - - -}; +#pragma once + +class SubWindow {}; + +#if 0 +#include +#include "curses.h" +#include "util/coord.hpp" + +#include +#include // for std::to_string + +enum class position{ // only horizontal positions for now + LEFT, + MIDDLE, + RIGHT, + AT_CURS // don't change, just print AT the cursor position +}; + +/* @caution - DONT manipulate WINDOW* pointers directly + If newwin() is needed, create a new class Window to handle memory allocation for that, currently it's not needed so leaving + */ +class SubWindow{ + typedef std::shared_ptr SubWindow_Ptr; // NO OWNERSHIP for the parent will be held here +public: + bool enabled{ false }; + void box(chtype = ' ', chtype = ' '); + void refreshParent(); + void refresh(); + bool isEnabled(); + void disable(); // @brief -> RESETS this->win to nullptr (All data used to construct is still stored, to enable at later stage) + void enable(); // @brief -> ALLOCATES this->win to nullptr (All data used to construct is still stored, to enable at later stage) + int getmax_x(); + int getmax_y(); + void updateDimen(); // @brief - Updates contents of this->dimensions + void newline(); // move to the next line (uses last_write_pos) + void moveCursor(int row, int col); + void hline(chtype = ACS_HLINE); // @brief -> Draws a horizontal line on NEXT LINE + void hline(int y, int x, char, int len); // not defined now, not needed + + /** + * @brief - Wrappers around waddstr() and mvwaddstr() + * @params - str - String, + * position - Position to print at (LEFT(AT_CURS), MIDDLE, RIGHT) + * row - Y dimension to write at + * col - X dimension to write at + */ + void addstr(std::string_view str, position = position::AT_CURS); + void addstr(int row, int col, std::string_view str); + // @future - Later implement the wrapper to mvwprintw() too, since it provides the formatted output + // @brief - Move to a new line, and add a string, there + void nladdstr(std::string_view str, position = position::AT_CURS); + + void addch(char ch); + + void printf(const char*); + + // definition of this templated function is REQUIRED here, so that the particular function can be formed by any file that includes curses_subwin.hpp + template + void printf(const char* format, T first_val, Types... next_vals){ + for( int i = 0; format[i] != '\0'; ++i ){ + if( format[i] == '%' ){ + if( std::is_integral::value ){ + this->addstr(std::to_string(first_val)); + } else if( std::is_same::value ){ + this->addch(first_val); + } else{ + // else ignore any other type + } + return this->printf(format + i + 1, next_vals...); + + // #if std::is_integral::value + // #elif std::is_same::value + // this->addch(first_val); + // #elif std::is_same::value + // this->addstr(first_val); + // #elif std::is_same::value || std::is_same::value + // this->addstr(first_val.data()); + // #else + // #endif + } else{ + this->addch(format[i]); + } + } + } + template + void printf(const char* format, std::string_view first_val, Types... next_vals){ + for( int i = 0; format[i] != '\0'; ++i ){ + if( format[i] == '%' ){ + this->addstr(first_val.data()); + return this->printf(format + i + 1, next_vals...); + } else{ + this->addch(format[i]); + } + } + } + + /** + * @important @note - The pairs will be in the form of row*col + * @brief - Uses stdscr as the parent screen + */ + SubWindow(const std::pair& dimensions, const std::pair& start_yx) : + SubWindow(dimensions.first, dimensions.second, start_yx.first, start_yx.second) + { + this->enabled = true; + } + SubWindow(SubWindow_Ptr& parent_win, const std::pair& dimensions, const std::pair& start_yx) : + SubWindow(parent_win, dimensions.first, dimensions.second, start_yx.first, start_yx.second) + { + this->enabled = true; + } + + SubWindow(int height, int width, int y_corner, int x_corner) : + dimensions{height, width}, + y_corner(y_corner), + x_corner(x_corner), + win(subwin(stdscr, height, width, y_corner, x_corner)) + { + this->updateDimen(); + this->enabled = true; + } + SubWindow(SubWindow_Ptr& parent_win, int height, int width, int y_corner, int x_corner) : + dimensions{height, width}, + y_corner(y_corner), + x_corner(x_corner), + parent_win(parent_win), + win(subwin(parent_win->win.get(), height, width, y_corner + parent_win->dimensions.n_row + 1, x_corner + parent_win->dimensions.n_col + 1)) // the corner params assume to be wrt. to stdscr + { + this->updateDimen(); + this->enabled = true; + } + + ~SubWindow(){ + // @note @future - for multi-threading, this next if MUST be atomic (for eg. two owners release the pointers simulateusly but for both this if may give false, that's the problem) + if( win.use_count() == 1 ){ // only we ourselves remain as its owner + // @note @caution - Currently the delwin() calls have been commented, since it's causing double free, since the smart pointer also implicitly calls reset() + // delwin(win.get()); + } + if( parent_win && parent_win.use_count() == 1 ){ + // delwin(parent_win->win.get()); + } + } + +private: + const int y_corner, x_corner; // data required for enable disable + struct { + int n_row; + int n_col; + }dimensions; + struct { + int n_row{ 0 }; + int n_col{ 0 }; + }last_write_pos; // last locations to which we wrote anything + bool boxed{ false }; // @caution - Currently no function is available that resets this to false (though, since it's not required in our case, leaving) + std::shared_ptr win; + SubWindow_Ptr parent_win; // @note - this shared_ptr will hold NOTHING, when parent window is stdscr + + +}; + +#endif diff --git a/ext/graphMat b/ext/graphMat index c48780e..de0f1b2 160000 --- a/ext/graphMat +++ b/ext/graphMat @@ -1 +1 @@ -Subproject commit c48780e20edddca9024f79daabb38894c0e6eaf9 +Subproject commit de0f1b2ee5a3ed71d365b1d6cb3146efbad22d0b diff --git a/ext/nanogui b/ext/nanogui new file mode 160000 index 0000000..0146a88 --- /dev/null +++ b/ext/nanogui @@ -0,0 +1 @@ +Subproject commit 0146a88b2214cd5c5c29e6dfa8d3d3d0e9ab6d9d diff --git a/ext/utilpp b/ext/utilpp new file mode 160000 index 0000000..07a0270 --- /dev/null +++ b/ext/utilpp @@ -0,0 +1 @@ +Subproject commit 07a0270d11ac6cd910ada8567780da19700803b7 diff --git a/includes/Entities/human.hpp b/includes/Entities/human.hpp new file mode 100644 index 0000000..911c302 --- /dev/null +++ b/includes/Entities/human.hpp @@ -0,0 +1,28 @@ +#pragma once +// @future - For a small improvement, have a static member (like 3D bitset representing the areas found by humanity) + +// As of now, human justs keeps moving randomly + +#include "../entity.hpp" + +class Human : public Entity { + Entity_Point curr_pos; + World* parent_world; + bool should_wander{ false }; + const float TIME_DIFF_PER_MOVE{ 1.0f }; // ie. one `time unit` between each move + + void _Action1() override {} + void _Action2() override {} +public: + typedef World* World_Ptr; + + //static std::vector> > humanities_exploration; + //static GraphMatrix3D humanities_exploration; + + std::optional getPrimaryPos() const override; + void simulateExistence() override; + void pauseExistence() override; + + explicit Human(World_Ptr const world); + //Human(World_Ptr const world, Human const* parter) : Entity(); // the human will be together with the partner, or at least distance +}; diff --git a/includes/Entities/rock.hpp b/includes/Entities/rock.hpp index 76607a0..9118327 100644 --- a/includes/Entities/rock.hpp +++ b/includes/Entities/rock.hpp @@ -1,18 +1,20 @@ -#pragma once - -#include "entity.hpp" - -class Rock: public Entity { - typedef World* World_Ptr; - -public: - const Entity_Point location; - void _Action1() override {} - void _Action2() override {} - - std::optional Entity::getPrimaryPos(void) const override { return this->location; } - void simulateExistence() override {} - - Rock(World_Ptr); - Rock(World_Ptr, const coord&); -}; +#pragma once + +#include "entity.hpp" + +class World; // forward-declaration + +class Rock: public Entity { + typedef World* World_Ptr; + +public: + const Entity_Point location; + void _Action1() override {} + void _Action2() override {} + + std::optional getPrimaryPos(void) const override { return this->location; } + void simulateExistence() override {} + + Rock(World_Ptr); + Rock(World_Ptr, const coord&); +}; diff --git a/includes/Entities/snake.hpp b/includes/Entities/snake.hpp index bcfb54c..f69d829 100644 --- a/includes/Entities/snake.hpp +++ b/includes/Entities/snake.hpp @@ -7,6 +7,7 @@ #include "graphMat/3d_graph_box.hpp" #include +#include #include #include #include diff --git a/includes/adapter.hpp b/includes/adapter.hpp new file mode 100644 index 0000000..67eac08 --- /dev/null +++ b/includes/adapter.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +#include "forward_decl.hpp" +#include "declarations.hpp" +#include "display/subwin.hpp" + +class DisplayAdapter{ + typedef util::_coord3D coordinate; // on a screen so won't need anything bigger than an int + typedef std::shared_ptr DisplayManager; + typedef World_Node* World_Node_Ptr; +// private: +public: + SubWindow window; // @note @caution -> The DisplayAdapter's SubWindow isn't meant to be passed around ! (If tried to create a shared_ptr from this, will give double free) + DisplayManager dispMngr; // @todo - Make this a non-modifieable by this class (should always point to same dispMngr) + + // the further data can be replaced by having a pointer t the wrld_node instead of all this individually + size_t node_id; + const World_Node_Ptr node; + + DisplayAdapter(DisplayManager dispMngr, World_Node_Ptr world_node, int height, int width,int y_corner, int x_corner); + +public: + void disable(); // once disabled, can NOT be enabled again for NOW (since we can't chose which worlds to show and which ones not to show) ! + void update(); + + DisplayAdapter() = delete; + ~DisplayAdapter(){} + + friend class Display; +}; diff --git a/includes/config.hpp b/includes/config.hpp index bb59aca..a21bcf5 100644 --- a/includes/config.hpp +++ b/includes/config.hpp @@ -1,22 +1,22 @@ -#pragma once - -typedef uint64_t _timePoint; -typedef _timePoint _timeDiff; -namespace statics -{ - typedef int32_t dimen_t; - // static constexpr std::pair< uint16_t, uint16_t > MAX_BOUNDS{ 1000, 1000 }; //applicable to ALL WORLDS CREATED - // static constexpr std::pair< uint16_t, uint16_t > init_Max_Bound{ 40, 40 }; //applicable to A NEW WORLD - // Currently using square matrix as parent, since it will be equally expanding later - static constexpr uint16_t MAX_BOUND{ 1000 }; //applicable to ALL WORLDS CREATED - static constexpr uint16_t init_Bound{ 40, }; //applicable to A NEW WORLD - - static constexpr float max_free_space = 1000.0f; //so that space doesn't just get wasted - static constexpr float min_free_space = 100.0f; //if it falls below this, in a particular worlPlot, the expansion rate will be increased - - static constexpr _timePoint BIG_BANG_TIME = 0; //can be time::now() later too - static constexpr float UNIT_TIME = 1.0f; //in terms of human world seconds - - static constexpr uint8_t init_expansion_speed{ 1 }; // @future - allow negative growths too - -} // namespace statics +#pragma once + +typedef uint64_t _timePoint; +typedef _timePoint _timeDiff; +namespace statics +{ + typedef int32_t dimen_t; + // static constexpr std::pair< uint16_t, uint16_t > MAX_BOUNDS{ 1000, 1000 }; //applicable to ALL WORLDS CREATED + // static constexpr std::pair< uint16_t, uint16_t > init_Max_Bound{ 40, 40 }; //applicable to A NEW WORLD + // Currently using square matrix as parent, since it will be equally expanding later + static constexpr uint16_t MAX_BOUND{ 1000 }; //applicable to ALL WORLDS CREATED + static constexpr uint16_t init_Bound{ 40, }; //applicable to A NEW WORLD + + static constexpr float max_free_space = 1000.0f; //so that space doesn't just get wasted + static constexpr float min_free_space = 100.0f; //if it falls below this, in a particular worlPlot, the expansion rate will be increased + + static constexpr _timePoint BIG_BANG_TIME = 0; //can be time::now() later too + static constexpr float UNIT_TIME = 1.0f; //in terms of human world seconds + + static constexpr uint8_t init_expansion_speed{ 1 }; // @future - allow negative growths too + +} // namespace statics diff --git a/includes/declarations.hpp b/includes/declarations.hpp index ef9a34d..131cc32 100644 --- a/includes/declarations.hpp +++ b/includes/declarations.hpp @@ -1,54 +1,54 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "graphMat/direction.hpp" -#include "graphMat/../../util/coord.hpp" // not recommended like this, @me @note - Update when Utilities become a library of themselves -#include "util/ranges.hpp" // for util::contains function - -#include "config.hpp" - -typedef util::_coord3D coord; -class Entity; // forward decl - -struct Box{ //Just as extension, to add more variables to the graph_box -// Direction __dir_came_from; //stores the direction from which this node was reached - - const Entity* entity{nullptr}; - //std::forward_list entities; // @todo - Add any entity to the the box's entities vector which is entered by an entity - -public: - bool hasEntities() const noexcept { return this->entity != nullptr; } - //inline void addEntity(const Entity* entity) { - inline void addEntity(const Entity* entity) { - if(entity == nullptr) this->entity = entity; - //entities.emplace_front(entity); - } - inline void remEntity(const Entity* entity) noexcept { // noexcept gaurantee, if not found then no action - //entities.remove(entity); - if (this->entity == entity) this->entity = nullptr; - -#ifdef DEBUG - assert(std::find(std::cbegin(entities), std::cend(entities), entity) != entities.cend()); - "The box currently doesn't hold any reference to the entity" -#endif // DEBUG - } - - Box() noexcept {} - // bool isEmpty() const noexcept {return entities.empty();} //maybe removed -}; - -enum class Event{ //for logging puposes - ENTITY_BIRTH, - ENTITY_DEATH, - ENTITY_MOVE, - ENTITY_GROW, - NEW_WORLD, - WORLD_PAUSE, - // WORLD_RESUME, //won't be used now - //BIG_BANG happens only once, so not must to include -}; +#pragma once + +#include +#include +#include +#include +#include + +#include "graphMat/direction.hpp" +#include "graphMat/../../util/coord.hpp" // not recommended like this, @me @note - Update when Utilities become a library of themselves +#include "util/ranges.hpp" // for util::contains function + +#include "config.hpp" + +typedef util::_coord3D coord; +class Entity; // forward decl + +struct Box{ //Just as extension, to add more variables to the graph_box +// Direction __dir_came_from; //stores the direction from which this node was reached + + const Entity* entity{nullptr}; + //std::forward_list entities; // @todo - Add any entity to the the box's entities vector which is entered by an entity + +public: + bool hasEntities() const noexcept { return this->entity != nullptr; } + //inline void addEntity(const Entity* entity) { + inline void addEntity(const Entity* entity) { + if(this->entity == nullptr) this->entity = entity; + //entities.emplace_front(entity); + } + inline void remEntity(const Entity* entity) noexcept { // noexcept gaurantee, if not found then no action + //entities.remove(entity); + if (this->entity == entity) this->entity = nullptr; + +//#ifdef DEBUG +// assert(std::find(std::cbegin(entities), std::cend(entities), entity) != entities.cend()); +// "The box currently doesn't hold any reference to the entity" +//#endif // DEBUG + } + + Box() noexcept {} + // bool isEmpty() const noexcept {return entities.empty();} //maybe removed +}; + +enum class Event{ //for logging puposes + ENTITY_BIRTH, + ENTITY_DEATH, + ENTITY_MOVE, + ENTITY_GROW, + NEW_WORLD, + WORLD_PAUSE, + // WORLD_RESUME, //won't be used now + //BIG_BANG happens only once, so not must to include +}; diff --git a/includes/entity.hpp b/includes/entity.hpp index 41945da..c437e12 100644 --- a/includes/entity.hpp +++ b/includes/entity.hpp @@ -1,69 +1,71 @@ -#pragma once - -#include -#include -#include -#include -#include -#include // for std::reference_wrapper - -#include "declarations.hpp" -#include "id_creator.hpp" -#include "graphMat/3d_graph_box.hpp" // for Graph_Box - -typedef void (*Action_Ptr)(void); - -struct Prop{ // @future - See the @future comment on the Entity::getUniqProp() function - std::any data; -}; - -struct SnakeProp: Prop{ - // int data; // for snake, the unique property (ie. this `data`) will be an int, ie. length -}; - -enum class entity_Types: uint8_t { - SNAKE, - ROCK - // more can be added later, it's made to be expandible, though do see the member declarations as for what ANY entity must have -}; - -struct Entity_Point { // a general class, since each object will have at least 1 POINT, for example for the snake this will be its head, for a planet, this can be its center, while a square may store 4 Entity_Point - Graph_Box_3D* graph_box; - - coord point_coord; - - void reset(Graph_Box_3D* new_box, coord& new_coord) { - this->graph_box = new_box; - this->point_coord = new_coord; - } - - Entity_Point(Graph_Box_3D* initial_box, const coord& coordinate) noexcept: graph_box(initial_box), point_coord(coordinate) {} -}; - -class Entity: public _ID{ - typedef statics::dimen_t dimen_t; -protected: - std::vector supported_Operations; - // std::vector supported_Operations; - // std::vector supported_Operations; //same as above -public: - const entity_Types type; - // @warning -> Check for any additional copy being created due to use of std::reference_wrapper::get() over the places in code - virtual std::optional getPrimaryPos() const = 0; // optional since NOT mandatory that every entity will be having a entity_point - virtual void _Action1() = 0; //only 2 actions supported as of now - virtual void _Action2() = 0; - - virtual void simulateExistence() = 0; // simulate the work when on a single thread - - Entity(entity_Types type): - _ID(), - type(type) - { - // supported_Operations.push_back( &foo ); //works, void(void) in global scope - // supported_Operations.push_back( &Entity::_Action1 ); //doesn't work - // supported_Operations.push_back( &Entity::_Action1 ); //doesn't work - // supported_Operations = {&Entity::_Action1, &Entity::_Action2}; - } - - friend class World; -}; +#pragma once + +#include +#include +#include +#include +#include +#include // for std::reference_wrapper + +#include "declarations.hpp" +#include "id_creator.hpp" +#include "graphMat/3d_graph_box.hpp" // for Graph_Box + +typedef void (*Action_Ptr)(void); + +struct Prop{ // @future - See the @future comment on the Entity::getUniqProp() function + std::any data; +}; + +struct SnakeProp: Prop{ + // int data; // for snake, the unique property (ie. this `data`) will be an int, ie. length +}; + +enum class Entity_Types { + SNAKE, + ROCK, + HUMAN + // more can be added later, it's made to be expandible, though do see the member declarations as for what ANY entity must have +}; + +struct Entity_Point { // a general class, since each object will have at least 1 POINT, for example for the snake this will be its head, for a planet, this can be its center, while a square may store 4 Entity_Point + Graph_Box_3D* graph_box; + + coord point_coord; + + void reset(Graph_Box_3D* new_box, coord& new_coord) { + this->graph_box = new_box; + this->point_coord = new_coord; + } + + Entity_Point(Graph_Box_3D* initial_box, const coord& coordinate) noexcept: graph_box(initial_box), point_coord(coordinate) {} +}; + +class Entity: public _ID{ + typedef statics::dimen_t dimen_t; +protected: + //std::vector supported_Operations; + // std::vector supported_Operations; + // std::vector supported_Operations; //same as above +public: + const Entity_Types type; + // @warning -> Check for any additional copy being created due to use of std::reference_wrapper::get() over the places in code + virtual std::optional getPrimaryPos() const = 0; // optional since NOT mandatory that every entity will be having a entity_point + virtual void _Action1() = 0; //only 2 actions supported as of now + virtual void _Action2() = 0; + + virtual void simulateExistence() = 0; // simulate the work when on a single thread + virtual void pauseExistence() = 0; + + Entity(Entity_Types type): + _ID(), + type(type) + { + // supported_Operations.push_back( &foo ); //works, void(void) in global scope + // supported_Operations.push_back( &Entity::_Action1 ); //doesn't work + // supported_Operations.push_back( &Entity::_Action1 ); //doesn't work + // supported_Operations = {&Entity::_Action1, &Entity::_Action2}; + } + + friend class World; +}; diff --git a/includes/logger.hpp b/includes/logger.hpp index 1fa2112..bcfef7b 100644 --- a/includes/logger.hpp +++ b/includes/logger.hpp @@ -1,11 +1,12 @@ #pragma once -#include "curses.h" #include "log.hpp" #include "declarations.hpp" #include +// UPDATE: 3rd Feb - Will be using the console for logging + /* NOTE - For now, i will be making its methods static, though later on a logger object can be local member to each object of `Verse` class, @@ -13,9 +14,6 @@ since that would allow something like a `Multiverse`, in each of which only one but each Verse's current World will all keep working */ class LOGGER{ //actual logger class that logs the data to a file, or some stream - static SCREEN* _logger_screen; - static const SCREEN* _verse_screen; //will need this to store to use set_term() (in case used later in log_it()) - static std::mutex _screen_mutex; public: @@ -26,10 +24,9 @@ class LOGGER{ //actual logger class that logs the data to a file, or some strea } - static void startLogger( const SCREEN* verse_screen ){ + static void startLogger(){ // @note - Will likely create a new window and store // _logger_screen = newterm(); - _verse_screen = verse_screen; // logger_screen_mutex // @todo diff --git a/includes/path_finder.hpp b/includes/path_finder.hpp index 6c729e9..e471dac 100644 --- a/includes/path_finder.hpp +++ b/includes/path_finder.hpp @@ -1,32 +1,32 @@ -#pragma once - -#include "graphMat/direction.hpp" -#include "entity.hpp" - -class WorldPlot; // forward-decl - -class Path_Finder -{ - WorldPlot* plot; - -public: - directionalPath&& getPath(const Entity_Point& entity, bool shortest = false) const; // if shortest is false, the algorithm is free to chose whichever algo givces the path - - directionalPath&& getPath(const Entity_Point& entity, Graph_Box_3D& final_dest, bool shortest = false) = delete; /** @not_implemented */ - directionalPath&& getPath(const Entity_Point& entity, util::_coord3D& final_dest, bool shortest = false) = delete; /** @not_implemented */ - bool is_path_clean(const Graph_Box_3D*, const directionalPath&) const; - - Path_Finder(WorldPlot* fun_space); - ~Path_Finder(); - -private: - /*PATHFINDERS START*/ - // @note - Some private path finders won't check if the path is clear or not, do that yourself, one such is basic_path() - directionalPath&& basic_rect(const Entity_Point&, const coord&) const; // just gives a basic rectangular path with only a single turn - directionalPath&& rand_basic_rect(const Entity_Point&, const coord&) const; // just gives a basic rectangular path with only a single turn - - directionalPath&& shortest_path(const Entity_Point&) const; /** @not_implemented */ // uses the food position as the ending point - directionalPath&& shortest_path(const Entity_Point&, Graph_Box_3D&) const; /** @not_implemented */ - /*PATHFINDERS END*/ - -}; +#pragma once + +#include "graphMat/direction.hpp" +#include "entity.hpp" + +class WorldPlot; // forward-decl + +class Path_Finder +{ + WorldPlot* plot; + +public: + directionalPath getPath(const Entity_Point& entity, bool shortest = false) const; // if shortest is false, the algorithm is free to chose whichever algo givces the path + + directionalPath getPath(const Entity_Point& entity, Graph_Box_3D& final_dest, bool shortest = false) = delete; /** @not_implemented */ + directionalPath getPath(const Entity_Point& entity, util::_coord3D& final_dest, bool shortest = false) = delete; /** @not_implemented */ + bool is_path_clean(const Graph_Box_3D*, const directionalPath&) const; + + Path_Finder(WorldPlot* fun_space); + ~Path_Finder(); + +private: + /*PATHFINDERS START*/ + // @note - Some private path finders won't check if the path is clear or not, do that yourself, one such is basic_path() + directionalPath basic_rect(const Entity_Point&, const coord&) const; // just gives a basic rectangular path with only a single turn + directionalPath rand_basic_rect(const Entity_Point&, const coord&) const; // just gives a basic rectangular path with only a single turn + + directionalPath shortest_path(const Entity_Point&) const; /** @not_implemented */ // uses the food position as the ending point + directionalPath shortest_path(const Entity_Point&, Graph_Box_3D&) const; /** @not_implemented */ + /*PATHFINDERS END*/ + +}; diff --git a/includes/verse.hpp b/includes/verse.hpp index 240a8a1..9773179 100644 --- a/includes/verse.hpp +++ b/includes/verse.hpp @@ -14,7 +14,7 @@ class Verse{ public: std::promise creation_promise; // shouldn't be required now, but still letting it remain for now - std::future big_bang(); // brambha, the creator + void big_bang(); // brambha, the creator void render_screen(); // vishnu, the carer void kaal_day(std::string_view origin); // mahesh, the destroyer // @don't try to destruct the origin, since that will just be kind of a deadlock like situation, both trying to stop the other diff --git a/includes/world_node.hpp b/includes/world_node.hpp index 6a3d132..7aaa6d8 100644 --- a/includes/world_node.hpp +++ b/includes/world_node.hpp @@ -5,8 +5,7 @@ #include "id_creator.hpp" #include "state.hpp" #include "world_tree.hpp" - -class node_adapter; //forward-declaration +#include "adapter.hpp" typedef int32_t dimen_t; struct StatePlusPlus{ @@ -20,7 +19,7 @@ class World_Node : public _ID{ public: // std::shared_ptr dispManager; // @note - May be needed, else it will have to go this way: this->world->verse->display to get to the display class, and then use the data - std::shared_ptr adapter; // the display controller, shoudl be unique_ptr, but is shared_ptr, since we need a reference in the queue in the Display class, which we do by using a weak_ptr + std::shared_ptr adapter; // the display controller, shoudl be unique_ptr, but is shared_ptr, since we need a reference in the queue in the Display class, which we do by using a weak_ptr World_Tree* tree; void update_disp(); diff --git a/includes/world_plot.hpp b/includes/world_plot.hpp index 6964dc7..36fe7b5 100644 --- a/includes/world_plot.hpp +++ b/includes/world_plot.hpp @@ -51,7 +51,7 @@ class WorldPlot: public Cube_Matrix{ const graph_box_type* get_box(const coord& position) const{ return this->operator[](position); } - directionalPath&& getShortestPathToFood(const Entity_Point& origin) const; + directionalPath getShortestPathToFood(const Entity_Point& origin) const; public: const auto& get_food() const{ diff --git a/includes/world_tree.hpp b/includes/world_tree.hpp index 4bd518c..53fa841 100644 --- a/includes/world_tree.hpp +++ b/includes/world_tree.hpp @@ -6,7 +6,6 @@ #include #include -#include "util/tree.hpp" #include "forward_decl.hpp" /* @@ -20,7 +19,7 @@ class World_Tree{ // typedef _tree_node* World_Node_Ptr; private: std::shared_ptr displayManager; // the displayManager for the verse - const Verse const* parent_verse; + Verse const* parent_verse; World_Node_Ptr root; int16_t num_nodes{0}; @@ -40,6 +39,12 @@ class World_Tree{ bool initTree(std::promise& creation_promise); void destructTree(); + World_Node_Ptr const getRootNode() const { + return this->root; + } + + friend class Display; + World_Tree(Verse*, std::shared_ptr displayManager); ~World_Tree(); }; diff --git a/main.cpp b/main.cpp index 348ae70..ce907a0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,20 +1,19 @@ -#include -#include -//#include - -#include "verse.hpp" -#include "logger.hpp" - -// put it here, since putting it in id_creator.hpp will give multiple definiton link error (there ARE ways like having it in id_creator.cpp, ) -//id_type _ID::_curr_ID = util::Random::random(100000); // @note - Maybe temporarily, so that ids dont' just start with 0,1,2 and so on - -static Verse verse; - -int main(int argc, char const *argv[]) -{ - //LOGGER::startLogger( verse.displayManager.getScreen() ); - - verse.big_bang(); - - return 0; -} +#include +#include + +#include "verse.hpp" +#include "logger.hpp" + +// put it here, since putting it in id_creator.hpp will give multiple definiton link error (there ARE ways like having it in id_creator.cpp, ) +//id_type _ID::_curr_ID = util::Random::random(100000); // @note - Maybe temporarily, so that ids dont' just start with 0,1,2 and so on + +static Verse verse; + +int main(int argc, char const *argv[]) +{ + //LOGGER::startLogger( verse.displayManager.getScreen() ); + + verse.big_bang(); + + return 0; +} diff --git a/multiTerm/.vscode/launch.json b/multiTerm/.vscode/launch.json deleted file mode 100644 index a48214b..0000000 --- a/multiTerm/.vscode/launch.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "g++ - Build and debug active file", - "type": "cppdbg", - "request": "launch", - "program": "${fileDirname}/test", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": true, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "C/C++: g++ build active file", - "miDebuggerPath": "/usr/bin/gdb" - } - ] -} \ No newline at end of file diff --git a/multiTerm/.vscode/settings.json b/multiTerm/.vscode/settings.json deleted file mode 100644 index 0a3757a..0000000 --- a/multiTerm/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "files.associations": { - "*.tcc": "cpp", - "vector": "cpp" - } -} \ No newline at end of file diff --git a/multiTerm/.vscode/tasks.json b/multiTerm/.vscode/tasks.json deleted file mode 100644 index d83b5c0..0000000 --- a/multiTerm/.vscode/tasks.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "type": "shell", - "label": "C/C++: g++ build active file", - "command": "/usr/bin/g++", - "args": [ - "-g", - "${fileDirname}/test.cxx", - "-lncurses", - "-std=c++17", - "-o", - "${fileDirname}/test" - ], - "options": { - "cwd": "${workspaceFolder}" - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} \ No newline at end of file diff --git a/multiTerm/Makefile b/multiTerm/Makefile deleted file mode 100644 index c0d7322..0000000 --- a/multiTerm/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -EXCUTABLE=test - -${EXCUTABLE}: test.cxx - g++ test.cxx -std=c++17 -lncurses -o ${EXCUTABLE} - make run - -run: ${EXCUTABLE} - ./${EXCUTABLE} - -clean: - rm ${EXCUTABLE} \ No newline at end of file diff --git a/multiTerm/README.md b/multiTerm/README.md deleted file mode 100644 index 7fb9bc1..0000000 --- a/multiTerm/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Testing for creating and controlling multiple terminal screen with curses. - -If time permits (before 100DaysOfCode ends), will create this into a class that can be used to do this more easily, and in an encapsulated manner, rather than free functions taking pointers (nothing bad, with that, though i prefer not to pass the safe thing again and again, and that the pointers should relate to the class using it) diff --git a/multiTerm/learning_phase/boxing_windows.md b/multiTerm/learning_phase/boxing_windows.md deleted file mode 100644 index 54c0571..0000000 --- a/multiTerm/learning_phase/boxing_windows.md +++ /dev/null @@ -1,16 +0,0 @@ -```cpp - // ACS_BSBS -> Horizonal line - // ACS_BULLET -> Like Dots - // ACS_CKBOARD -> ▒▒▒▒▒ - // ACS_DARROW -> ┴┴┴┴┴┴ - // ACS_DEGREE -> ° - // ACS_DIAMOND -> ◆◆◆◆◆◆◆◆◆◆◆◆◆ - // ASC_GEQUAL -> ≥≥≥≥≥≥≥ - // ACS_LANTERN -> ␋␋␋␋␋␋ - // ACS_LEQUAL -> ≤≤≤≤≤ - // ACS_NEQUAL -> ≠≠≠≠≠≠≠≠≠ - // ACS_LTEE -> ├ - - box(stdscr, ACS_VLINE, ACS_HLINE); - -``` \ No newline at end of file diff --git a/multiTerm/learning_phase/coloured_chars.md b/multiTerm/learning_phase/coloured_chars.md deleted file mode 100644 index f2b72ed..0000000 --- a/multiTerm/learning_phase/coloured_chars.md +++ /dev/null @@ -1,30 +0,0 @@ -Will be Useful in Ludo The Game -> - -> this currently prints due to noecho disabled - -```cpp - if( has_colors() ){ - start_color(); - - /* - COLOR ASSIGNMENT. Not necessary to do like here only - */ - init_pair(1, COLOR_RED, COLOR_BLACK); - init_pair(2, COLOR_GREEN, COLOR_WHITE); - init_pair(3, COLOR_YELLOW, COLOR_RED); - init_pair(4, COLOR_BLUE, COLOR_BLACK); - init_pair(5, COLOR_CYAN, COLOR_BLACK); - init_pair(6, COLOR_MAGENTA, COLOR_BLACK); - init_pair(7, COLOR_WHITE, COLOR_BLACK); - } - - int num = 0; - - while (true) - { - int c = getch(); - attrset(COLOR_PAIR( num%8 )); - num++; - - } -``` \ No newline at end of file diff --git a/multiTerm/learning_phase/ncurses_extensions.md b/multiTerm/learning_phase/ncurses_extensions.md deleted file mode 100644 index b4a9bd5..0000000 --- a/multiTerm/learning_phase/ncurses_extensions.md +++ /dev/null @@ -1,4 +0,0 @@ -Read from this -> -https://invisible-island.net/ncurses/ Writing Programs with NCURSES - -Use the extensions like forms and menu (especially form for taking the time) diff --git a/multiTerm/multi_term.hpp b/multiTerm/multi_term.hpp deleted file mode 100644 index 2078055..0000000 --- a/multiTerm/multi_term.hpp +++ /dev/null @@ -1,203 +0,0 @@ -#pragma once - -#include "curses.h" -#include - -// @todo - Make the display responsive - -class single_term{ -private: - std::vector< WINDOW* > windows; - - int term_height; - int term_width; - -public: - single_term(); - ~single_term(); -}; - -#include -#include -void temp2(void){ - std::vector mWindows; - - mWindows.resize(3); // Separate the screen to three windows - initscr(); - - // If there wasn't any key pressed don't wait for keypress - nodelay(stdscr, true); - // Turn on keypad control - keypad(stdscr, true); - noecho(); // No echo for the key pressed - - curs_set(0); // No cursor show - - int mGameBoardWidth, mGameBoardHeight, mScreenWidth, mScreenHeight, mInstructionWidth=18, mInformationHeight =6 ; - // Get screen and board parameters - getmaxyx(stdscr, mScreenHeight, mScreenWidth); - mGameBoardWidth = mScreenWidth - mInstructionWidth; - mGameBoardHeight = mScreenHeight - mInformationHeight; - - // createInformationBoard(); - int startY = 0; - int startX = 0; - mWindows[0] = newwin(mInformationHeight, mScreenWidth, startY, startX); - - // createGameBoard(); - startY = mInformationHeight; - startX = 0; - mWindows[1] = newwin(mScreenHeight - mInformationHeight, mScreenWidth - mInstructionWidth, startY, startX); - - - // createInstructionBoard(); - startY = mInformationHeight; - startX = mScreenWidth - mInstructionWidth; - mWindows[2] = newwin(mScreenHeight - mInformationHeight, mInstructionWidth, startY, startX); - - - using namespace std; - char s[45]="Hit here"; - mvaddstr(50,10,s); - - box(mWindows[2], '+', '-'); - - refresh(); - // wrefresh(mWindows[1]); - - getch(); - getch(); - getch(); - - this_thread::sleep_for(5s); - - - for( int i = 0; i < mWindows.size(); i++ ){ - delwin(mWindows[i]); - } - endwin(); - -} - -void temp(void){ - int BoardWidth=60, BoardHeight=20; - WINDOW* menu; - int width = BoardWidth * 0.5; - int height = BoardHeight * 0.5; - int startX = BoardWidth * 0.25; - int startY = BoardHeight * 0.25 + 5; - - menu = newwin(height, width, startY, startX); - box(menu, '-', '|'); - std::vector menuItems = { "Restart", "Quit" }; - - int index = 0; - int offset = 4; - mvwprintw(menu, 1, 1, "Your Final Score:"); - std::string pointString = std::to_string(20); - mvwprintw(menu, 2, 1, pointString.c_str()); - wattron(menu, A_STANDOUT); - mvwprintw(menu, 0 + offset, 1, menuItems[0].c_str()); - wattroff(menu, A_STANDOUT); - mvwprintw(menu, 1 + offset, 1, menuItems[1].c_str()); - - wrefresh(menu); - - int key; - while( true ){ - key = getch(); - switch( key ){ - case 'W': - case 'w': - case KEY_UP: - { - mvwprintw(menu, index + offset, 1, menuItems[index].c_str()); - index--; - index = (index < 0) ? menuItems.size() - 1 : index; - wattron(menu, A_STANDOUT); - mvwprintw(menu, index + offset, 1, menuItems[index].c_str()); - wattroff(menu, A_STANDOUT); - break; - } - case 'S': - case 's': - case KEY_DOWN: - { - mvwprintw(menu, index + offset, 1, menuItems[index].c_str()); - index++; - index = (index > menuItems.size() - 1) ? 0 : index; - wattron(menu, A_STANDOUT); - mvwprintw(menu, index + offset, 1, menuItems[index].c_str()); - wattroff(menu, A_STANDOUT); - break; - } - } - wrefresh(menu); - if( key == ' ' || key == 10 ){ - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - delwin(menu); - - // if( index == 0 ){ - // return true; - // } else{ - // return false; - // } - -} - -single_term::single_term(): windows(3){ - initscr(); //initialise the curses library - getmaxyx(stdscr, term_width, term_height); - - // for now it will have three windows - // windows.push_back(newwin()); - windows.push_back(newwin(45,20,2,4)); - - /* - LEARNT - initscr() basically sets up the routines to use current terminal characteristics, as well as allocate space for stdscr and curscr - */ - keypad(stdscr, true); // enable keyboard mapping, for arrow and function keys - nonl(); // no newlines or control feeds in curses - cbreak(); // take chars one at a time, don't wait for '\n' to be pressed - noecho(); //when echo is enabled, getch() actually itself calls addch() to output entered character to screen - - // @note - scrollok() and leaveok() are somethings i may use in some other programs later - - int num = 0; - - // box(stdscr, ACS_VLINE, ACS_HLINE); - - temp(); - -#if 0 - box(windows[0], ACS_VLINE, ACS_HLINE); - mvaddstr(0,0,"There"); - mvaddstr(4,40,"Hi there"); - wrefresh(windows[0]); - refresh(); -#endif - - // while (true) - // { - // int c = getch(); - // attrset(COLOR_PAIR( num%8 )); - // // COLOR_PAIR( num%8 ); - // addch(c); - // getmaxyx(stdscr, term_width, term_height); - // // resize_term(term_width, term_height); - // num++; - - // if(c == 'q') break; - - // } - - getch(); - -} - -single_term::~single_term(){ - endwin(); -} diff --git a/multiTerm/single_term.hpp b/multiTerm/single_term.hpp deleted file mode 100644 index 78c0274..0000000 --- a/multiTerm/single_term.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "signal.h" -#include "curses.h" - -static void sig_handler(int SIGNAL){ // @warning -> It doesn't close the program itself, do that yourself (since way of doing so can be different according to preferences, for eg. i prefer using exceptions many a times) - static bool sig_handled = false; - if( sig_handled ) return; // if signal already handles, then silently return - // @note - This handler maybe called twice due to the reason, a function calls single_term::reset_curses, and also raise(SIGTERM) is called (see for example, display::runInitTasks, where entering 'q' first calls reset_curses and then raise(SIGTERM) too), these cases may just have the raise() call removed, but it's there to make sense - - endwin(); - sig_handled = true; -} - - -/* - Meant to be inherited from -*/ -class single_term{ //initially will have 3 windows, a square one at bottom left, rectangular at bottom right, and a rectangular intoduction at top - bool curses_initialized{ false }; - std::vector< WINDOW* > _Windows; // not in use currently, in Display class - protected: - std::string title; - std::string description; // @note - Not now (not enough space) - - std::vector> _win_Dimensions; //windows dimensions - - int _terminal_y; - int _terminal_x; - - public: - void printMsg(int win_index, const std::string& msg, int row = 0, int col = 0){ - if( win_index >= this->_Windows.size() ){ - // @future - After logger support is added, modify this - // verse::LOGGER << "Window index passed is not available"; - return; - } - - mvwaddstr(this->_Windows[win_index], row, col, msg.data()); - this->refreshWindow(win_index); - } - - void clearAll(){ - wclear(stdscr); - } - - void refreshAll(){ - wrefresh(stdscr); - } - - void refreshWindow(int win_index){ - wrefresh(this->_Windows[win_index]); - } - - void checkResize(){ - // @future @me - Currently it will be managed inside the overloaded runInitTasks() member function, by the child class, though this function may contain a template like stuff for such a support, though it should not be used here - } - - static std::future get_async_input(){ - return std::async( - std::launch::async, - [](){ - char ch; - std::cin >> ch; - - return ch; - } - ); - } - - void reset_curses(){ - if( !this->curses_initialized ) return; - - for( WINDOW* win : _Windows ){ - delwin(win); - } - - raise(SIGTERM); // which then calls endwin() - } - - // @note - by default, curses_init will show an empty box - void curses_init(){ - // @warning - Before calling raise(), be sure to call - signal(SIGTERM, &sig_handler); // @fix_me - 2nd argument's type isn't according to the declaration of signal() function - - #if defined(_IOSTREAM_) || defined(_GLIBCXX_IOSTREAM) - std::ios_base::sync_with_stdio(false); // only this maybe enough, depending on what is used inside single_term::get_async_input - std::cin.tie(0); - std::cout.tie(0); - #endif - - if( this->curses_initialized ){ - return; - } - - initscr(); - curs_set(FALSE); // cursor won't show - keypad(stdscr, TRUE); // not being used in worldLine simulator - nonl(); // tells cursor not to do NL -> CR/NL on output - noecho(); - cbreak(); // no wait for '\n', one char at a time - - this->curses_initialized = true; - getmaxyx(stdscr, this->_terminal_y, this->_terminal_x); - - this->clearAll(); - } - virtual void runInitTasks() = 0; - - //currently number of windows is fixed, since this is not the primary goal, this will be as such for some time maybe - single_term() = default; - single_term(std::string_view title,std::string_view desc) : title(title), description(desc){} - ~single_term(){ - if( !curses_initialized ){ - return; - } - - for( WINDOW* win : _Windows ){ - delwin(win); - } - - endwin(); - } -}; diff --git a/multiTerm/test b/multiTerm/test deleted file mode 100644 index 84431ce..0000000 Binary files a/multiTerm/test and /dev/null differ diff --git a/multiTerm/test.cxx b/multiTerm/test.cxx deleted file mode 100644 index e3b3892..0000000 --- a/multiTerm/test.cxx +++ /dev/null @@ -1,85 +0,0 @@ -#include - -#include -#include - -#include "curses.h" - -// #include "multi_term.hpp" -#include "single_term.hpp" - -using namespace std; - -int main(int, char const* []){ - - single_term s("Aditya", "This is something"); - this_thread::sleep_for(3s); - -#if 0 - initscr(); - noecho(); - cbreak(); - nodelay(stdscr, TRUE); - - curs_set(FALSE); //don't display the cursor - - int row, col; - int bottom = 6; - - getmaxyx(stdscr, row, col); - // cout< Human::getPrimaryPos() const +{ + return this->curr_pos; +} + +void Human::simulateExistence() +{ + this->should_wander = true; + + while (this->should_wander) + { + graphMat::NeighbourIterator iter(this->curr_pos.graph_box); + + for (; iter ; ++iter) + { + auto box_ptr = iter.operator->(); + if ( ! iter->getData().hasEntities()) { + this->curr_pos.graph_box = box_ptr; + coord increment_coord = iter._getIncrementCoords(); + + if (curr_pos.graph_box != iter.center_box) { + // if it's not the center box we passed to initialiser, then it is EITHER FRONT_FACING or BACK_FACING + increment_coord.mZ = (curr_pos.graph_box->FRONT_FACING == iter.center_box) ? 1 : -1; + } + + this->curr_pos.point_coord += increment_coord; + } + } + + std::this_thread::sleep_for(std::chrono::seconds( static_cast( statics::UNIT_TIME * TIME_DIFF_PER_MOVE ))); + } +} + +void Human::pauseExistence() +{ + this->should_wander = false; +} + +Human::Human(World_Ptr const world): + Entity(Entity_Types::HUMAN), + parent_world(world), + curr_pos(nullptr, world->world_plot.getRandomCoord()) +{ + this->curr_pos.graph_box = this->parent_world->get_box(curr_pos.point_coord); + assert(curr_pos.graph_box != nullptr); // remove this assert after tests written that getRandomCoord() always returns correct one +} diff --git a/src/Entities/rock.cpp b/src/Entities/rock.cpp index ba6a0c4..e580959 100644 --- a/src/Entities/rock.cpp +++ b/src/Entities/rock.cpp @@ -1,10 +1,10 @@ -#include "Entities/rock.hpp" -#include "world.hpp" - -Rock::Rock(World_Ptr world) : Rock(world, world->world_plot.getRandomCoord()) {} - -Rock::Rock(World_Ptr world, const coord& location): Entity(entity_Types::ROCK), location(world->world_plot[location], location) { - assert(this->location.graph_box != nullptr); // ie. we received valid coordinate, AND that coordinate is still in matrix - - this->location.graph_box->getDataRef().addEntity(this); -} +#include "Entities/rock.hpp" +#include "world.hpp" + +Rock::Rock(World_Ptr world) : Rock(world, world->world_plot.getRandomCoord()) {} + +Rock::Rock(World_Ptr world, const coord& location): Entity(Entity_Types::ROCK), location(world->world_plot[location], location) { + assert(this->location.graph_box != nullptr); // ie. we received valid coordinate, AND that coordinate is still in matrix + + this->location.graph_box->getDataRef().addEntity(this); +} diff --git a/src/Entities/snake.cpp b/src/Entities/snake.cpp index 8dca5bc..f7bc5af 100644 --- a/src/Entities/snake.cpp +++ b/src/Entities/snake.cpp @@ -1,12 +1,14 @@ -#include "Entities/snake.hpp" -#include "world.hpp" -#include "declarations.hpp" -#include "util/random.hpp" +#include +#include #include #include #include +#include "Entities/snake.hpp" +#include "world.hpp" +#include "declarations.hpp" + void Snake::_Action1(){ this->eatFood(); // @note - Ignoring returned boolean from eatFood(), if that's required use eatFood() directly, this method is just for the sake for generalisation using Entity } @@ -15,8 +17,8 @@ void Snake::_Action2(){ this->moveForward(); } -std::optional Snake::getPrimaryPos() const -{ +std::optional Snake::getPrimaryPos() const +{ return this->head; } @@ -24,11 +26,7 @@ void Snake::simulateExistence() { // @future -> Can add more logic here, when more interaction options between entities are added // a one time check, before an entity starts existing -#ifdef DEBUG - assert(std::this_thread::get_id() == this->parent_world->_shared_concurrent_data.get_world_thread_id()); - - //"Entities should be on a different thread, than the world. In case, you don't want this behaviour, then pass -DNO_THREAD_ENTITY (To define NO_THREAD_ENTITY)"); -#endif // DEBUG + //assert(std::this_thread::get_id() == this->parent_world->_shared_concurrent_data.get_world_thread_id()); // instead of using convar, we could have used promise::set_value_at_thread_exit() this->isSimulating = true; // ysa @@ -52,8 +50,8 @@ void Snake::pauseExistence() { std::unique_lock lock(m); this->isSimulating = false; - this->sim_convar.wait_for(lock, std::chrono::milliseconds(80)); - // this is to prevent infinite loop or waiting, since the next line can cause blocking if the notify_one is earlier than wait() + this->sim_convar.wait_for(lock, std::chrono::milliseconds(80)); + // this is to prevent infinite loop or waiting, since the next line can cause blocking if the notify_one is earlier than wait() } bool Snake::eatFood(){ //can only eat, if AT the position @@ -71,21 +69,21 @@ bool Snake::hasRoundTrips() const{ auto& temp_bucket = this->__temp.bucket; std::fill(temp_bucket.begin(), temp_bucket.end(), 0); // ensuring all of the array are zero - for (auto& dir : this->body) - { - temp_bucket[static_cast(dir)]++; - } - - for (auto i = 0; i < temp_bucket.size(); ++i) - { - auto& num_curr = temp_bucket[i]; - auto& num_curr_oposite = temp_bucket[static_cast(static_cast(num_curr))]; - if (num_curr != num_curr_oposite) { - return false; - } - - num_curr = num_curr_oposite = 0; - } + for (auto& dir : this->body) + { + temp_bucket[static_cast(dir)]++; + } + + for (auto i = 0; i < temp_bucket.size(); ++i) + { + auto& num_curr = temp_bucket[i]; + auto& num_curr_oposite = temp_bucket[static_cast(static_cast(num_curr))]; + if (num_curr != num_curr_oposite) { + return false; + } + + num_curr = num_curr_oposite = 0; + } return true; } @@ -108,77 +106,77 @@ bool Snake::isSnakeBodyOK() const{ **/ void Snake::moveForward(){ // this will also be on the snake's thread, and not the world_thread - // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) + // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) this->parent_world->getShortestPathToFood(this->head, this->curr_Path); - this->__temp.last_dir = curr_Path.next_dir(); - curr_Path.pop(); + this->__temp.last_dir = curr_Path.next_dir(); + curr_Path.pop(); this->head.graph_box = this->head.graph_box->get_adj_box(__temp.last_dir); this->_add_dir_to_coord( this->head.point_coord, __temp.last_dir); - + if (this->curr_Path.empty() && this->eatFood()) { body.grow(__temp.last_dir); } else { body.move( __temp.last_dir ); } -} - -void Snake::_add_dir_to_coord(coord& c, Direction dir) const -{ - switch (dir) - { - case Direction::UTTAR: - c += std::array{0, 1, 0}; - break; - case Direction::PURVA: - c += std::array{1, 0, 0}; - break; - case Direction::PASHCHIM: - c += std::array{-1, 0, 0}; - break; - case Direction::DAKSHIN: - c += std::array{0, -1, 0}; - break; - case Direction::ISHANYA: - c += std::array{1, 1, 0}; - break; - case Direction::AGNEYA: - c += std::array{1, -1, 0}; - break; - case Direction::NAIRUTYA: - c += std::array{-1, -1, 0}; - break; - case Direction::VAYAVYA: - c += std::array{-1, 1, 0}; - break; - case Direction::URDHWA: - c += std::array{0, 0, 1}; - break; - case Direction::ADHARASTHA: - c += std::array{0, 0, -1}; - break; - } +} + +void Snake::_add_dir_to_coord(coord& c, Direction dir) const +{ + switch (dir) + { + case Direction::UTTAR: + c += std::array{0, 1, 0}; + break; + case Direction::PURVA: + c += std::array{1, 0, 0}; + break; + case Direction::PASHCHIM: + c += std::array{-1, 0, 0}; + break; + case Direction::DAKSHIN: + c += std::array{0, -1, 0}; + break; + case Direction::ISHANYA: + c += std::array{1, 1, 0}; + break; + case Direction::AGNEYA: + c += std::array{1, -1, 0}; + break; + case Direction::NAIRUTYA: + c += std::array{-1, -1, 0}; + break; + case Direction::VAYAVYA: + c += std::array{-1, 1, 0}; + break; + case Direction::URDHWA: + c += std::array{0, 0, 1}; + break; + case Direction::ADHARASTHA: + c += std::array{0, 0, -1}; + break; + } } const Entity_Point& Snake::getHead() const{ return this->head; -} - -const Entity_Point& Snake::getTail() const -{ +} + +const Entity_Point& Snake::getTail() const +{ return this->tail; } int Snake::getUniqProp() const{ return this->getLength(); -} - -int Snake::getLength() const -{ - return static_cast( this->body.length() + 1 ); +} + +int Snake::getLength() const +{ + return static_cast( this->body.length() + 1 ); } Snake::Snake(const World_Ptr world) : Snake(world, world->_init_SnakeLength){} @@ -194,7 +192,7 @@ Snake::Snake(const World_Ptr world) : Snake(world, world->_init_SnakeLength){} */ // @note - Entities shoud start existence from the start (constructor) itself... though be sure to handle the case when the food is still being created, since the current logic creates the Entities JUST AFTER the snakes, since the createFood logic currently needs the positions of snakes too Snake::Snake(const World_Ptr world, uint16_t init_len) : - Entity(entity_Types::SNAKE), + Entity(Entity_Types::SNAKE), parent_world(world), body(this), head(nullptr, world->world_plot.getRandomCoord()), @@ -203,75 +201,81 @@ Snake::Snake(const World_Ptr world, uint16_t init_len) : this->head.graph_box = this->parent_world->get_box(head.point_coord); assert(head.graph_box != nullptr); + this->head.graph_box->getDataRef().addEntity(this); // head is a part of the entity + this->tail = this->head; // @note @future - To optimise path finding later, better modify this to only chose dimensions within some distance from 0,0,0 - Direction rand_direction; - this->tail.point_coord = this->head.point_coord; - this->tail.graph_box = this->head.graph_box; - do { - this->body.removeAndClearBody(); // we are repeating this over and over again, till we have okay body, that's why we are doing this + this->tail.point_coord = this->head.point_coord; + this->tail.graph_box = this->head.graph_box; + do { + this->body.removeAndClearBody(); // we are repeating this over and over again, till we have okay body, that's why we are doing this auto* prev_box = this->head.graph_box; for (auto i = 0; i < init_len - 1; i++) { - rand_direction = statics::directions[util::Random::random(statics::directions.size())]; - - while ( prev_box && prev_box->getData().hasEntities()) { // to chose a entity free box - prev_box = prev_box->get_adj_box(rand_direction); - rand_direction = statics::directions[util::Random::random(4)]; + // @future @note @me - The earlier implementation used randomly getting directions, then add_dir_to_coord neighbours + + graphMat::NeighbourIterator iter(prev_box); + for (; iter; ++iter) + { + // + if (!iter->getData().hasEntities()) { + prev_box = iter.curr_box; + break; + } } - - if (!prev_box) { + if (!iter) { std::cerr << "Not enough space could be traversed to allocate snake to that area"; return; } - prev_box = prev_box->get_adj_box(rand_direction); + prev_box->getDataRef().addEntity(this); - this->body.body.push_back(rand_direction); + this->body.body.push_back(iter._getLastTurnedDirection().value()); // getLastTurnedDirection() MUST have a value std::clog << "Added unit to snake's body: " << this->_id << '\n'; this->tail.graph_box = prev_box; - _add_dir_to_coord(this->tail.point_coord, rand_direction); + this->tail.point_coord += iter._getIncrementCoords(); + //_add_dir_to_coord(this->tail.point_coord, rand_direction); if (!this->isSnakeBodyOK()) break; } - } while ( !isSnakeBodyOK() ); -} - -Snake::~Snake() -{ - this->pauseExistence(); -} - -void SnakeBody::grow(Direction move_dir) -{ - // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) - body.push_front( - util::getOppositeDirection(move_dir) - ); -} - -void SnakeBody::move(Direction move_dir) -{ - // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) - this->grow(move_dir); - this->pop_back(); + } while ( !isSnakeBodyOK() ); +} + +Snake::~Snake() +{ + this->pauseExistence(); } - + +void SnakeBody::grow(Direction move_dir) +{ + // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) + body.push_front( + util::getOppositeDirection(move_dir) + ); +} + +void SnakeBody::move(Direction move_dir) +{ + // @todo - Change for tail (Can also move head and tail to snake body, but let moveForward like methods outside) + this->grow(move_dir); + this->pop_back(); +} + // doesn't remove the head void SnakeBody::removeAndClearBody() { auto tmp_box = this->snake_ptr->head.graph_box; - for (auto& dir : this->body) - { - tmp_box = tmp_box->get_adj_box(dir); - tmp_box->getDataRef().remEntity(snake_ptr); + for (auto& dir : this->body) + { + tmp_box = tmp_box->get_adj_box(dir); + tmp_box->getDataRef().remEntity(snake_ptr); } snake_ptr->tail = snake_ptr->head; return body.clear(); } - + SnakeBody::SnakeBody(Snake* snake_ptr) : snake_ptr(snake_ptr) {} diff --git a/src/adapter.cpp b/src/adapter.cpp new file mode 100644 index 0000000..fff8f53 --- /dev/null +++ b/src/adapter.cpp @@ -0,0 +1,46 @@ +// there was a circular dependency b/w display.hpp and DisplayAdapter.hpp, that's why this has been segregated + +#include // for std::call_once + +#include "adapter.hpp" +#include "display/display.hpp" +#include "world_node.hpp" + +//DisplayAdapter::DisplayAdapter(DisplayManager dispMngr, World_Node_Ptr world_node, int height, int width,int y_corner, int x_corner) +// : node(world_node), +// dispMngr(dispMngr), +// window(dispMngr->main_area, height, width, y_corner, x_corner) +//{ +// if (!node) throw std::invalid_argument("A non-null world pointer is required"); +// +// this->node_id = node->getId(); +// +// window.box(ACS_VLINE, '-'); +// +// window.moveCursor(1, 1); +// window.addstr(std::to_string(this->node_id).data(), position::MIDDLE); +// window.hline(); +// +// window.newline(); +// window.printf("Dimen - (%, %)", this->node->get_world_dimen(), this->node->get_world_dimen()); +// // window.printf("Dimen - (, )"); +// +// for (int i = 0; i < 4; i++) +// { +// window.newline(); +// // window.printf("E - (, ), "); // snake number/id, head_coord.x, head_coord.y, points of snake +// window.printf("E% - (%, %), %", i+1); // snake number/id, head_coord.x, head_coord.y, points of snake +// } +// +// window.refresh(); +// wrefresh(stdscr); +//} + +void DisplayAdapter::update(){ // updates the content on the window, with updated content from the world_naode that is linked + //if( this->dispMngr->paused ) return; + + //// @todo - Handle the display here + + //dispMngr->updateScreen(); + //std::call_once( this->dispMngr->disp_once_flag, &Display::updateScreen, this->dispMngr ); +} diff --git a/src/path_finder.cpp b/src/path_finder.cpp index 3a77f4b..1daab80 100644 --- a/src/path_finder.cpp +++ b/src/path_finder.cpp @@ -1,99 +1,99 @@ -#include "path_finder.hpp" -#include "world_plot.hpp" - - // @note - basic_rect doesn't check if the path is empty or not -directionalPath&& Path_Finder::basic_rect( const Entity_Point& start, const coord& end ) const // start is a graph box, only to efficiently check if a path is clean or not -{ - directionalPath path; - path.reserve( std::abs( start.point_coord.mX - end.mX ) + std::abs(start.point_coord.mY - end.mY) ); - - if (end.mX < start.point_coord.mX) { - path.data.insert(path.data.end(), std::abs(start.point_coord.mX - end.mX), Direction::PASHCHIM ); - }else{ - path.data.insert(path.data.end(), std::abs(start.point_coord.mX - end.mX), Direction::PURVA); - } - - if ( end.mY < start.point_coord.mY ) { - path.data.insert(path.data.end(), std::abs(start.point_coord.mY - end.mY), Direction::DAKSHIN); - } - else { - path.data.insert(path.data.end(), std::abs(start.point_coord.mY - end.mY), Direction::UTTAR); - } - - if (end.mZ < start.point_coord.mZ) { - path.data.insert(path.data.end(), std::abs(start.point_coord.mZ - end.mZ), Direction::ADHARASTHA); // downwards - } - else { - path.data.insert(path.data.end(), std::abs(start.point_coord.mZ - end.mZ), Direction::URDHWA); // upwards - } - - return std::move(path); -} - -directionalPath&& Path_Finder::rand_basic_rect(const Entity_Point& start, const coord& end) const -{ - directionalPath path ( this->basic_rect(start, end) ) ; - - while ( ! this->is_path_clean(start.graph_box, path) ) { - std::shuffle(path.begin(), path.end(), util::Random::generator); // logically the start point and end point will stillbe connected - } - - return std::move(path); -} - -bool Path_Finder::is_path_clean(const Graph_Box_3D* start, const directionalPath& path) const -{ - auto* tmp{ start }; // we don't check for the start position, it already has an entity_point, ie. Hum khud ! :D - - for (auto& dir : path) - { - tmp = tmp->get_adj_box(dir); - if (tmp->getData().hasEntities()) return false; - } - - return true; -} - -directionalPath&& Path_Finder::shortest_path(const Entity_Point& start) const // end defaults to food position -{ - directionalPath path; - // @todo @not_priority - return std::move(path); -} - -directionalPath&& Path_Finder::shortest_path(const Entity_Point& start, Graph_Box_3D& end) const -{ - directionalPath path; - // @todo @not_priority - return std::move(path); -} - -directionalPath&& Path_Finder::getPath(const Entity_Point& entity_point, bool shortest) const -{ - directionalPath path; - if (shortest) { - path = this->shortest_path(entity_point); - } - else - { - path = this->basic_rect(entity_point, this->plot->food.coordinate); - } - if (!is_path_clean(entity_point.graph_box, path)) { - if ( ! shortest ) { // that is the basic rect path was used, and it can cause problems at times, so now dcall shortest paths to find a new path - return this->getPath(entity_point, true); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(400)); // check for a new path after 400ms (This behaviour may change as more path finder methods are added) - return this->getPath(entity_point, true); - } - - return std::move(path); -} - -Path_Finder::Path_Finder(WorldPlot* fun_space): plot(fun_space) -{ -} - -Path_Finder::~Path_Finder() -{ +#include "path_finder.hpp" +#include "world_plot.hpp" + + // @note - basic_rect doesn't check if the path is empty or not +directionalPath Path_Finder::basic_rect( const Entity_Point& start, const coord& end ) const // start is a graph box, only to efficiently check if a path is clean or not +{ + directionalPath path; + path.reserve( std::abs( start.point_coord.mX - end.mX ) + std::abs(start.point_coord.mY - end.mY) ); + + if (end.mX < start.point_coord.mX) { + path.data.insert(path.data.end(), std::abs(start.point_coord.mX - end.mX), Direction::PASHCHIM ); + }else{ + path.data.insert(path.data.end(), std::abs(start.point_coord.mX - end.mX), Direction::PURVA); + } + + if ( end.mY < start.point_coord.mY ) { + path.data.insert(path.data.end(), std::abs(start.point_coord.mY - end.mY), Direction::DAKSHIN); + } + else { + path.data.insert(path.data.end(), std::abs(start.point_coord.mY - end.mY), Direction::UTTAR); + } + + if (end.mZ < start.point_coord.mZ) { + path.data.insert(path.data.end(), std::abs(start.point_coord.mZ - end.mZ), Direction::ADHARASTHA); // downwards + } + else { + path.data.insert(path.data.end(), std::abs(start.point_coord.mZ - end.mZ), Direction::URDHWA); // upwards + } + + return path; +} + +directionalPath Path_Finder::rand_basic_rect(const Entity_Point& start, const coord& end) const +{ + directionalPath path ( this->basic_rect(start, end) ) ; + + while ( ! this->is_path_clean(start.graph_box, path) ) { + std::shuffle(path.begin(), path.end(), util::Random::generator); // logically the start point and end point will stillbe connected + } + + return path; +} + +bool Path_Finder::is_path_clean(const Graph_Box_3D* start, const directionalPath& path) const +{ + auto* tmp{ start }; // we don't check for the start position, it already has an entity_point, ie. Hum khud ! :D + + for (auto& dir : path) + { + tmp = tmp->get_adj_box(dir); + if (tmp->getData().hasEntities()) return false; + } + + return true; +} + +directionalPath Path_Finder::shortest_path(const Entity_Point& start) const // end defaults to food position +{ + directionalPath path; + // @todo @not_priority + return path; +} + +directionalPath Path_Finder::shortest_path(const Entity_Point& start, Graph_Box_3D& end) const +{ + directionalPath path; + // @todo @not_priority + return path; +} + +directionalPath Path_Finder::getPath(const Entity_Point& entity_point, bool shortest) const +{ + directionalPath path; + if (shortest) { + path = this->shortest_path(entity_point); + } + else + { + path = this->basic_rect(entity_point, this->plot->food.coordinate); + } + if (!is_path_clean(entity_point.graph_box, path)) { + if ( ! shortest ) { // that is the basic rect path was used, and it can cause problems at times, so now dcall shortest paths to find a new path + return this->getPath(entity_point, true); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(400)); // check for a new path after 400ms (This behaviour may change as more path finder methods are added) + return this->getPath(entity_point, true); + } + + return path; +} + +Path_Finder::Path_Finder(WorldPlot* fun_space): plot(fun_space) +{ +} + +Path_Finder::~Path_Finder() +{ } \ No newline at end of file diff --git a/src/verse.cpp b/src/verse.cpp index 3062300..447d204 100644 --- a/src/verse.cpp +++ b/src/verse.cpp @@ -9,21 +9,28 @@ #include #include + // Update: Feb 4 -> It no longer returns a promise or a future, display takes over the main thread, and BLOCKS // @note - it should be more like, returning a promise, rather than a future... only logically it should hold that the receiver can poll this object, to know whether the task is completed -std::future Verse::big_bang(){ - // init_tree should be ASYNCHRONOUS, and also starts, and manages the simulation itself +void Verse::big_bang(){ + this->displayManager->showInitiating(); + // init_tree should be ASYNCHRONOUS, and also starts, and manages the simulation itself // creation of the first world, to ever exist in the particular verse this->worldTree->initTree(this->creation_promise); // WorldTree::init() will create the first node - this->render_screen(); - - return this->creation_promise.get_future(); // @dropped_idea - use a std::condition_variable to return in initTree + this->displayManager->startDisplay(); } // @note - Blocks until everything is stopped void Verse::kaal_day(std::string_view origin){ + if (origin != "Shiv") { + this->displayManager->showExiting(); // show Exit message on the screen, till the displayManger is automatically gets destructed after its destrcutor is called, and that is when everything is removed + } + this->worldTree->destructTree(); + if (origin != "Shiv") { // if not destructor then show these messages + this->displayManager->stopDisplay(); + } // @future @log - Stop the logger here too // this->logger.stop(); } @@ -52,8 +59,6 @@ Verse::Verse(): displayManager(new Display(this)) { } Verse::~Verse(){ - this->displayManager->showExit(); // show Exit message on the screen, till the displayManger is automatically gets destructed after its destrcutor is called, and that is when everything is removed - this->kaal_day("Shiv"); // source = "Shiv" means the destructor is the 'origin' (see the declaration of kaal_day) // LOGGER << "Verse has been destructed" diff --git a/src/world.cpp b/src/world.cpp index 11aebb9..d3d1f10 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -20,24 +20,24 @@ #include // inlining this function gives Unresolved External Symbol to call to this EXACT function in World_Node's constructor -_timePoint World::getCurrentTime() const noexcept -{ - return this->world_plot.currentTime; -} - -const coord& World::getFoodCoord() -{ - return world_plot.get_food().coordinate; -} - -bool World::lockFood(const Snake*) -{ - if (!this->food_mutex.try_lock()) return false; - - this->food_mutex.lock(); - return true; -} - +_timePoint World::getCurrentTime() const noexcept +{ + return this->world_plot.currentTime; +} + +const coord& World::getFoodCoord() +{ + return world_plot.get_food().coordinate; +} + +bool World::lockFood(const Snake*) +{ + if (!this->food_mutex.try_lock()) return false; + + this->food_mutex.lock(); + return true; +} + void World::ateFood(const Snake*){ //which snake ate it, log it, then randomize the food again //log the event, with snakeId @@ -47,11 +47,11 @@ void World::ateFood(const Snake*){ //which snake ate it, log it, then randomize // this->createFood(); } -World::udimen_t World::getWorldDimen() const -{ - return this->world_plot.getOrder(); -} - +World::udimen_t World::getWorldDimen() const +{ + return this->world_plot.getOrder(); +} + bool World::_RangeCheck(const coord_type& c) const{ return this->world_plot.getOrder() > c.mX || this->world_plot.getOrder() > c.mY; } @@ -75,11 +75,11 @@ World::World() : simulationRunning(false), world_plot(this, statics::BIG_BANG_TI // @todo this->entities.reserve(this->_MAX_NumSnakes); - for (auto i = 0; i < this->_MAX_NumSnakes; i++) - { + for (auto i = 0; i < this->_MAX_NumSnakes; i++) + { this->entities.push_back( //later when simulated, let all entities run on a different thread new Snake(this, util::Random::random(2, 5)) - ); + ); } // DEBUG - Disabled existence for now @@ -87,28 +87,28 @@ World::World() : simulationRunning(false), world_plot(this, statics::BIG_BANG_TI // std::thread(&Snake::simulateExistence, snake).detach(); //} - // COME HERE - Decide how is time incremented - //while (this->simulationRunning) - //{ - // ++this->currentTime; - // std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(statics::UNIT_TIME * 1000))); - //} -} - -World::~World() -{ - this->_shared_concurrent_data.reset_world_running(); - for (auto& entity : entities) - { - delete entity; - } - this->entities.clear(); - // the next loop isn't actually required, but can still be used - //for (auto& snake_thread : entity_threads) - //{ - // if (snake_thread.joinable()) snake_thread.join(); + // COME HERE - Decide how is time incremented + //while (this->simulationRunning) + //{ + // ++this->currentTime; + // std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(statics::UNIT_TIME * 1000))); //} - this->world_plot.pause_auto_expansion(); +} + +World::~World() +{ + this->_shared_concurrent_data.reset_world_running(); + for (auto& entity : entities) + { + delete entity; + } + this->entities.clear(); + // the next loop isn't actually required, but can still be used + //for (auto& snake_thread : entity_threads) + //{ + // if (snake_thread.joinable()) snake_thread.join(); + //} + this->world_plot.pause_auto_expansion(); } void World::getShortestPathToFood(const Entity_Point& origin, directionalPath& old_path) const{ diff --git a/src/world_node.cpp b/src/world_node.cpp index c9b8485..ce8f2cd 100644 --- a/src/world_node.cpp +++ b/src/world_node.cpp @@ -1,7 +1,7 @@ #include "world.hpp" #include "world_node.hpp" #include "display/display.hpp" -#include "display/node_adapter.hpp" +#include "adapter.hpp" void World_Node::captureState(){ this->paused_time = this->world->getCurrentTime(); @@ -110,12 +110,12 @@ World_Node::World_Node( World_Tree* tree, World_Node* parent_node, _timePoint t, }else if(parent_node != nullptr) { this->world = parent_node->world; - } - else - { - // ie. the root node... create a new world - this->world = new World(); - } + } + else + { + // ie. the root node... create a new world + this->world = new World(); + } this->paused_time = world->getCurrentTime(); //initially diff --git a/src/world_plot.cpp b/src/world_plot.cpp index dafb73d..657add7 100644 --- a/src/world_plot.cpp +++ b/src/world_plot.cpp @@ -9,7 +9,7 @@ void WorldPlot::createFood(){ std::vector tmp_list; for (const auto& en : this->parent_world->entities) { - if(en->type == entity_Types::SNAKE) + if(en->type == Entity_Types::SNAKE) tmp_list.push_back(en->getPrimaryPos().value().point_coord); // directly used optional<>::value since entities depending on this food will have it, as of now } @@ -174,7 +174,7 @@ WorldPlot::dimen_t WorldPlot::getFreeSpace() const{ for (auto& snake : this->parent_world->entities) { - if (snake->type != entity_Types::SNAKE) continue; + if (snake->type != Entity_Types::SNAKE) continue; min_x = std::min(static_cast(snake)->getHead().point_coord.mX, min_x); max_x = std::max(static_cast(snake)->getHead().point_coord.mX, max_x); @@ -237,7 +237,7 @@ void WorldPlot::getShortestPathToFood(const Entity_Point& origin, directionalPat else old_path = this->getShortestPathToFood(origin); } -directionalPath&& WorldPlot::getShortestPathToFood(const Entity_Point& origin) const{ +inline directionalPath WorldPlot::getShortestPathToFood(const Entity_Point& origin) const{ // @important @note - snake class expects the path to be like a stack, ie. the first move, will be the last one, which will be popped, then move_on return this->path_finder.getPath(origin); diff --git a/src/world_tree.cpp b/src/world_tree.cpp index a94ed96..c63b1e7 100644 --- a/src/world_tree.cpp +++ b/src/world_tree.cpp @@ -21,11 +21,11 @@ bool World_Tree::initTree(std::promise& creation_promise){ creation_promise.set_value(); return true; // @debug -} - -// @note - Blocks until the tree is destructed -void World_Tree::destructTree() -{ +} + +// @note - Blocks until the tree is destructed +void World_Tree::destructTree() +{ std::stack st; World_Node_Ptr temp; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..79e9e66 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/tests) +set(CTEST_BINARY_DIRECTORY ${PROJECT_BINARY_DIR}/tests) + +file(GLOB TEST_SOURCES "*.cpp") + +foreach(file ${TEST_SOURCES}) + string(REGEX REPLACE "(^.*/|\\.[^.]*$)" "" file_without_ext ${file}) + add_executable(${file_without_ext} ${file}) + target_link_libraries(${file_without_ext} ${PROJECT_LIBS}) + add_test(${file_without_ext} ${file_without_ext}) + set_tests_properties(${file_without_ext} + PROPERTIES + PASS_REGULAR_EXPRESSION "Test passed") + set_tests_properties(${file_without_ext} + PROPERTIES + FAIL_REGULAR_EXPRESSION "(Exception|Test failed)") + set_tests_properties(${file_without_ext} + PROPERTIES + TIMEOUT 120) +endforeach() diff --git a/tests/Entities/test_snake.cpp b/tests/Entities/test_snake.cpp new file mode 100644 index 0000000..569b0c4 --- /dev/null +++ b/tests/Entities/test_snake.cpp @@ -0,0 +1,9 @@ +#include "Entities/test_snake.cpp" + +namespace TESTS { + class SnakeTest { + void verify_snake_length() { + + } + }; +} diff --git a/util/converters.hpp b/util/converters.hpp deleted file mode 100644 index 833f811..0000000 --- a/util/converters.hpp +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// @warning - The functions that are taking a string_view aren't supposed to be used in the multi-threaded situation, since string_vie holds the pointer to the string, which may have been deleted -namespace util{ - namespace converter - { - namespace __private - { - enum class Priority: uint8_t{ - INVALID = 0, LOW, MID, HIGH, HIGHEST, KANEKI // kaneki is more like infinity here - }; - - inline Priority getPriority(char opr){ - switch (opr) - { - case '(': return Priority::KANEKI; - case '^': return Priority::HIGHEST; // considered as `power` - case '%': - case '*': - case '\\': - case '/': return Priority::HIGH; - case '+': - case '-': return Priority::MID; - default: return Priority::INVALID; - } - } - - inline bool isOperator(char ch){ - return ch == '^' || ch == '%' || ch == '*' || ch == '/' || ch == '\\' || ch == '+' || ch == '-'; - } - - // by default spaces will be inserted by this, since that is to be expected for strings - std::string numeric_inToPost(std::string_view); - } // namespace __private - - /** - * @warning - This function will only process string, considering variables in it it, with single character character names - * @tip - You may first pass the string with variable to this, then use std::replace or something to replace the variables with the numerical values you want - * @param - string_view: infix expression - * bool: spaced (`spaced` is a bool showing, whether spaces should be inserted in string, or not, by default true) - */ - std::string inToPost(std::string_view, bool spaced = true); - // std::string preToPost(std::string_view); - // std::string postToPre(std::string_view); - - } // namespace converter - namespace evaluator - { - /** - * @brief - Gives out an integer value after evaluating the postfix expression passed - */ - int32_t evalPostFix( std::string_view ); - } // namespace evaluator - -} - -std::string util::converter::__private::numeric_inToPost( std::string_view infix ){ - std::stack < char > stack; - std::string postfix; - postfix.reserve(2*infix.size() - 1); // size-1 space for spaces - - char ch; - for (auto i = 0; i < infix.size(); ++i) - { - ch = infix[i]; - if( std::isspace(ch) ) continue; // skip whitespaces - - if( ch == '(' ){ - stack.push(ch); - }else if ( ch == ')' ) - { - while ( ! stack.empty() && stack.top() != '(' ) - { - postfix.push_back( stack.top() ); - postfix.push_back(' '); // pushing a space - stack.pop(); - } - if( stack.top() == '(' ) stack.pop(); - }else if ( __private::isOperator( ch ) ) - { - while ( ! stack.empty() && ( __private::getPriority( stack.top() ) >= __private::getPriority( ch ) ) && stack.top() != '(' ) - { - postfix.push_back( stack.top() ); - postfix.push_back(' '); // pushing a space - stack.pop(); - } - stack.push( ch ); - }else - { // NUMBER OR operand - /* @logic of below for loop -> - for eg. these three expressions -> A+65+C (multiple digit number in b/w) - A+65 +C (space in b/w) - (A+65)+C (parenthesis in b/w) - What this loop tries to do is... KEEP READING UNTIL YOU GET either a space, parenthesis OR an operator (so "A" , "65" , "C" are treated as 3 single units, and hence no space between those, for eg. no space b/w '6' and '5') - Till then whatever is read is considered as single unit, hence even variable names as well as numbers can be read as well - */ - for ( ; infix[i] != '(' && infix[i] != ')' && ( !isspace(infix[i]) && !isOperator(infix[i]) ) && i < infix.size(); ++i ){ - postfix.push_back( infix[i] ); - } - --i; // the above for loop MUST DEFINITELY RUN atleast once, or else this line may cause infinite loop - - postfix.push_back(' '); // pushing a space - } - } - while ( !stack.empty() ){ - postfix.push_back( stack.top() ); - postfix.push_back(' '); // pushing a space - stack.pop(); - } - postfix.pop_back(); - postfix.shrink_to_fit(); - - return postfix; -} - -std::string util::converter::inToPost( std::string_view infix, bool spaced){ - std::stack < char > stack; - std::string postfix; - postfix.reserve(2*infix.size() - 1); // size-1 space for spaces - if( std::any_of(infix.begin(), infix.end(), [](char ch){ return ch >= '0' && ch <= '9'; }) ){ - return __private::numeric_inToPost( infix ); // this function only has a 1 LINE DIFFERENCE, but i wanted to use the for range, as well as keep it more segregated - } - - for (auto &&ch : infix){ - if( std::isspace(ch) ) continue; // skip whitespaces - - if( ch == '(' ){ - stack.push('('); - }else if ( ch == ')' ) - { - while ( ! stack.empty() && stack.top() != '(' ) - { - postfix.push_back( stack.top() ); - if(spaced) postfix.push_back(' '); // pushing a space - stack.pop(); - } - if( stack.top() == '(' ) stack.pop(); - }else if ( __private::isOperator( ch ) ) - { - while ( ! stack.empty() && ( __private::getPriority( stack.top() ) >= __private::getPriority( ch ) ) && stack.top() != '(' ) - { - postfix.push_back( stack.top() ); - if(spaced) postfix.push_back(' '); // pushing a space - stack.pop(); - } - stack.push( ch ); - }else - { // operand or NUMBER - postfix.push_back( ch ); - if(spaced) postfix.push_back(' '); // pushing a space - } - } - while ( !stack.empty() ){ - postfix.push_back( stack.top() ); - if(spaced) postfix.push_back(' '); // pushing a space - stack.pop(); - } - - if(postfix.back() == ' ') postfix.pop_back(); // removing the last space inserted - postfix.shrink_to_fit(); - - return postfix; -} diff --git a/util/math.hpp b/util/math.hpp deleted file mode 100644 index 360c644..0000000 --- a/util/math.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include - -namespace util -{ - template - int num_digits(T number){ - static_assert( std::is_integral::value == true ); - - int count = 0; - number = number > 0 ? number : -number; - while (number != 0){ - number /= 10; - ++count; - } - - return count; - } - - template - bool min(T1 a, T2 b){ - static_assert( std::is_integral_v == true && std::is_integral_v == true ); - - return a < b ? a : b; - } - - template - bool abs(T a){ - static_assert( std::is_integral_v == true ); - - return a > 0 ? a : -a; - } - -} // namespace util diff --git a/util/random.hpp b/util/random.hpp deleted file mode 100644 index 89b46fc..0000000 --- a/util/random.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -namespace util{ - class Random{ //gives out non-zero values only - public: - template // so that, if signed BUT positive integer type is required, it can be given (it required narrowing conversions) - static T random(){ - static_assert(std::is_integral_v); - - return random(0, std::numeric_limits::max() ); - } - - template - static T random(uint32_t max){ - static_assert( std::is_integral_v ); - - return random(0, max); - } - - template - static T random(uint32_t min, uint32_t max){ // [`min`, `max`) ie. max excluded - static_assert( std::is_integral_v ); - - //static std::random_device Random::device; - //static std::mt19937 Random::generator(Random::device()); - uint32_t num = std::random_device{}(); - // @future - Later use this generator too - - // @fix_me - Fix later-> won't work when (num-min) < 0 - //return static_cast((((num-min)%max) + num )); - return static_cast((num%(max-min)) + min ); - } - - inline static std::random_device device; - inline static std::mt19937 generator{ device() }; - - }; -} diff --git a/util/ranges.hpp b/util/ranges.hpp deleted file mode 100644 index 0d8e19b..0000000 --- a/util/ranges.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace util { - template - bool contains(Collection&& collection, typename std::remove_reference_t::value_type& val) { - return - std::find(std::cbegin(collection), std::cend(collection), val) - != - std::cend(collection); - } -} diff --git a/util/tree.hpp b/util/tree.hpp deleted file mode 100644 index 2e568a5..0000000 --- a/util/tree.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - -template -struct _tree_node{ - typedef _tree_node tree_node; - typedef tree_node* tree_node_ptr; - -private: -// std::list nodes; - data_type data; -public: - - _tree_node(data_type&& data): data(data){} -}; - - -template< typename node_dtype > -class Tree{ - node_dtype* root; // could have been unique_ptr, but we need a pointer in World for the `current active world` - std::list< node_dtype > nodes; // we can't have std::list of raw references (though using wrapper should work, but not needed here) - - public: - Tree(): root(nullptr){} - Tree(node_dtype& root): root(root){ - this->root = root; - } - - node_dtype& find(); //@todo - should take a lambda - void insert(node_dtype&); - size_t size(); -};