v1.0 (#1)
* init rework * Update LICENSE * removing tests * adding Gui Component system * added spdlog library * Fixed input restriction bug * nothing * Making the default button stand out * Setting up run Component * changing components * restarted because i cant do it visualising sorting through value/step diagrams * g * working (kinda) * fixed sqrt comp error * added debug flag * abbandoning Lua... Error in runtime * fixing errors, making cuts * removing unnessecary dependencies * Improving UI
This commit is contained in:
parent
96e6514337
commit
a89b27d456
36 changed files with 1665 additions and 1228 deletions
33
src/LuaSortList.hpp
Normal file
33
src/LuaSortList.hpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
class LuaSortList
|
||||
{
|
||||
public:
|
||||
std::vector<uint16_t> list;
|
||||
|
||||
void swap(size_t i1, size_t i2)
|
||||
{
|
||||
std::swap(list[i1], list[i2]);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return list.size();
|
||||
}
|
||||
|
||||
uint16_t at(size_t i) const
|
||||
{
|
||||
return list[i];
|
||||
}
|
||||
|
||||
bool sorted() const
|
||||
{
|
||||
for (int i = 1; i < list.size(); ++i)
|
||||
{
|
||||
if (list[i - 1] > list[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
#include "Renderer.h"
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
|
@ -1,47 +0,0 @@
|
|||
#include "SortingTester.h"
|
||||
|
||||
|
||||
SortingTester::SortingTester() : list(10)
|
||||
{
|
||||
std::cout << "Loading lua" << std::endl;
|
||||
|
||||
lua.lua.open_libraries(sol::lib::coroutine, sol::lib::table);
|
||||
lua.lua.new_usertype<SortingTester>("List",
|
||||
"size", &SortingTester::list_size,
|
||||
"swap", &SortingTester::list_swap,
|
||||
"greater", &SortingTester::list_greater,
|
||||
"less", &SortingTester::list_less,
|
||||
"equal", &SortingTester::list_equal
|
||||
);
|
||||
|
||||
lua.lua["list"] = this;
|
||||
}
|
||||
|
||||
void SortingTester::load(const std::string& script)
|
||||
{
|
||||
if(lua.load(script) != safesol::LuaResultType::SUCCESS)
|
||||
{
|
||||
std::cerr << "Error loading file" << std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
#include "internal_script.hpp"
|
||||
|
||||
void SortingTester::load_internal()
|
||||
{
|
||||
if (lua.script(std_intern_sorting_script) != safesol::LuaResultType::SUCCESS)
|
||||
{
|
||||
std::cerr << "Error loading internal script" << std::endl;
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void SortingTester::populate(const populate_function& f)
|
||||
{
|
||||
for (size_t i = 0; i < list.size(); i++)
|
||||
{
|
||||
f(i, list[i]);
|
||||
}
|
||||
std::cout << list << std::endl;
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
#pragma once
|
||||
#define SVA_LIST_CALLBACKS
|
||||
#include <std.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include "lua/safesol.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class SortingTester
|
||||
{
|
||||
List<u64> list;
|
||||
|
||||
safesol lua;
|
||||
|
||||
Timer timer = Timer(Timer::State::paused);
|
||||
|
||||
using populate_function = std::function<void(size_t, u64&)>;
|
||||
|
||||
template<typename ...Args>
|
||||
sol::protected_function_result run_function(const sol::protected_function& function, Args&&... args)
|
||||
{
|
||||
timer.set_state(Timer::State::running);
|
||||
sol::protected_function_result result = function(std::forward<Args>(args)...);
|
||||
timer.set_state(Timer::State::paused);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool list_greater(size_t index1, size_t index2)
|
||||
{
|
||||
if (active_result)
|
||||
++active_result->count_greater;
|
||||
return list[index1] > list[index2];
|
||||
}
|
||||
|
||||
bool list_less(size_t index1, size_t index2)
|
||||
{
|
||||
if (active_result)
|
||||
++active_result->count_less;
|
||||
return list[index1] < list[index2];
|
||||
}
|
||||
|
||||
bool list_equal(size_t index1, size_t index2)
|
||||
{
|
||||
if (active_result)
|
||||
++active_result->count_equal;
|
||||
return list[index1] == list[index2];
|
||||
}
|
||||
|
||||
void list_swap(size_t index1, size_t index2)
|
||||
{
|
||||
if (active_result)
|
||||
++active_result->count_swaps;
|
||||
// list[index1] ^= list[index2];
|
||||
// list[index2] ^= list[index1];
|
||||
// list[index1] ^= list[index2];
|
||||
auto tmp = list[index1];
|
||||
list[index1] = list[index2];
|
||||
list[index2] = tmp;
|
||||
}
|
||||
|
||||
size_t list_size() const
|
||||
{
|
||||
return list.size();
|
||||
}
|
||||
|
||||
bool is_sorted()
|
||||
{
|
||||
if (list.size() <= 1)
|
||||
return true;
|
||||
for (size_t i = 1; i < list.size(); i++)
|
||||
{
|
||||
if (list[i - 1] > list[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
struct run_result
|
||||
{
|
||||
timer_result timer;
|
||||
// counts
|
||||
u64 count_swaps = 0;
|
||||
u64 count_greater = 0;
|
||||
u64 count_less = 0;
|
||||
u64 count_equal = 0;
|
||||
// counts for comparisons
|
||||
u64 count_comparisons = 0;
|
||||
};
|
||||
private:
|
||||
run_result* active_result = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
SortingTester();
|
||||
|
||||
void load(const std::string& script);
|
||||
void load_internal();
|
||||
|
||||
template<typename ...Args>
|
||||
run_result run(const std::string& function_name, Args&&... args)
|
||||
{
|
||||
run_result result;
|
||||
timer.result.emplace(&result.timer);
|
||||
timer.reset(Timer::State::paused);
|
||||
active_result = &result;
|
||||
|
||||
// Create a bound member function using std::bind
|
||||
auto bound_run_function = std::bind(&SortingTester::run_function<Args...>,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::forward<Args>(args)...);
|
||||
|
||||
safesol::LuaResultType runstate = lua.run_on_caller(function_name, bound_run_function);
|
||||
|
||||
if (runstate != safesol::LuaResultType::SUCCESS)
|
||||
{
|
||||
std::cerr << "Error running function \"" << function_name << "\": " << static_cast<u16>(runstate) << std::endl;
|
||||
exit(static_cast<int>(runstate));
|
||||
}
|
||||
|
||||
if (!is_sorted())
|
||||
{
|
||||
std::cerr << "[ERROR] The algorithm \"" << function_name << "\" did not sort the list" << std::endl;
|
||||
std::cerr << list << std::endl;
|
||||
std::flush(std::cerr);
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
result.count_comparisons = result.count_equal + result.count_greater + result.count_less;
|
||||
|
||||
active_result = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void populate(const populate_function& f);
|
||||
};
|
|
@ -1,60 +0,0 @@
|
|||
#include "drawing_helper.hpp"
|
||||
|
||||
namespace sva
|
||||
{
|
||||
std::vector<std::string> split(const std::string& str, char delim)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
std::string token;
|
||||
std::istringstream tokenStream(str);
|
||||
while (std::getline(tokenStream, token, delim))
|
||||
{
|
||||
tokens.push_back(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Color sva::GetThemeColor(GuiControlProperty property)
|
||||
{
|
||||
return GetColor(GuiGetStyle(DEFAULT, TEXT_COLOR_NORMAL));
|
||||
}
|
||||
|
||||
void sva::DrawText(const std::string& text, vec2i pos, int size, Color color, TEXT_ALIGNMENT alignment)
|
||||
{
|
||||
switch (alignment)
|
||||
{
|
||||
case TEXT_ALIGN_LEFT:
|
||||
return DrawText(text.c_str(), pos.x, pos.y, size, color);
|
||||
case TEXT_ALIGN_RIGHT:
|
||||
if (text.find('\n') != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> lines = split(text, '\n');
|
||||
for (auto& line : lines)
|
||||
{
|
||||
pos.x -= MeasureText(line.c_str(), size);
|
||||
DrawText(line.c_str(), pos.x, pos.y, size, color);
|
||||
pos.y += size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos.x -= MeasureText(text.c_str(), size);
|
||||
return DrawText(text.c_str(), pos.x, pos.y, size, color);
|
||||
|
||||
case TEXT_ALIGN_CENTER:
|
||||
if (text.find('\n') != std::string::npos)
|
||||
{
|
||||
std::vector<std::string> lines = sva::split(text, '\n');
|
||||
for (auto& line : lines)
|
||||
{
|
||||
pos.x -= MeasureText(line.c_str(), size) / 2;
|
||||
DrawText(line.c_str(), pos.x, pos.y, size, color);
|
||||
pos.y += size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos.x -= MeasureText(text.c_str(), size) / 2;
|
||||
DrawText(text.c_str(), pos.x, pos.y, size, color);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
#include <raylib.h>
|
||||
#include <raylibs/raygui.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
namespace sva
|
||||
{
|
||||
template<typename T>
|
||||
struct TVector2
|
||||
{
|
||||
T x, y;
|
||||
};
|
||||
typedef TVector2<int> vec2i;
|
||||
typedef TVector2<float> vec2f;
|
||||
|
||||
enum TEXT_ALIGNMENT
|
||||
{
|
||||
TEXT_ALIGN_LEFT,
|
||||
TEXT_ALIGN_CENTER,
|
||||
TEXT_ALIGN_RIGHT
|
||||
};
|
||||
|
||||
|
||||
Color GetThemeColor(GuiControlProperty property);
|
||||
|
||||
void DrawText(const std::string& text, vec2i pos, int size, Color color = GetColor(GuiGetStyle(DEFAULT, TEXT_COLOR_NORMAL)), TEXT_ALIGNMENT alignment = TEXT_ALIGN_LEFT);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
#define RAYGUI_IMPLEMENTATION
|
||||
#include <raylibs/raygui.h>
|
|
@ -1,42 +0,0 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// StyleAsCode exporter v2.0 - Style data exported as a values array //
|
||||
// //
|
||||
// USAGE: On init call: GuiLoadStyleDark(); //
|
||||
// //
|
||||
// more info and bugs-report: github.com/raysan5/raygui //
|
||||
// feedback and support: ray[at]raylibtech.com //
|
||||
// //
|
||||
// Copyright (c) 2020-2023 raylib technologies (@raylibtech) //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define DARK_STYLE_PROPS_COUNT 8
|
||||
|
||||
// Custom style name: dark
|
||||
static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
|
||||
{ 0, 0, 0x7b7b7bff }, // DEFAULT_BORDER_COLOR_NORMAL
|
||||
{ 0, 1, 0x595959ff }, // DEFAULT_BASE_COLOR_NORMAL
|
||||
{ 0, 2, 0xdededeff }, // DEFAULT_TEXT_COLOR_NORMAL
|
||||
{ 0, 9, 0x232323ff }, // DEFAULT_BORDER_COLOR_DISABLED
|
||||
{ 0, 10, 0x606060ff }, // DEFAULT_BASE_COLOR_DISABLED
|
||||
{ 0, 11, 0x9f9f9fff }, // DEFAULT_TEXT_COLOR_DISABLED
|
||||
{ 0, 18, 0x68cbd0ff }, // DEFAULT_LINE_COLOR
|
||||
{ 0, 19, 0x262626ff }, // DEFAULT_BACKGROUND_COLOR
|
||||
};
|
||||
|
||||
// Style loading function: dark
|
||||
static void GuiLoadStyleDark(void)
|
||||
{
|
||||
// Load style properties provided
|
||||
// NOTE: Default properties are propagated
|
||||
for (int i = 0; i < DARK_STYLE_PROPS_COUNT; i++)
|
||||
{
|
||||
GuiSetStyle(darkStyleProps[i].controlId, darkStyleProps[i].propertyId, darkStyleProps[i].propertyValue);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
// TODO: Custom user style setup: Set specific properties here (if required)
|
||||
// i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
inline const char* std_intern_sorting_script = R"(
|
||||
-- bubble sort
|
||||
function bubble_sort()
|
||||
local isSorted = false
|
||||
while not isSorted do
|
||||
local movedElements = 0
|
||||
for x = 0, list:size() - 2 do
|
||||
if list:greater(x, x+1) then
|
||||
movedElements = movedElements + 1
|
||||
list:swap(x, x+1)
|
||||
end
|
||||
end
|
||||
if movedElements == 0 then
|
||||
isSorted = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function do_nothing()
|
||||
end
|
||||
|
||||
-- other functions
|
||||
|
||||
|
||||
)";
|
7
src/libimpl.cpp
Normal file
7
src/libimpl.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#define RAYGUI_IMPLEMENTATION
|
||||
#include <raylibs/raygui.h>
|
||||
|
||||
#undef RAYGUI_IMPLEMENTATION
|
||||
#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
|
||||
#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
|
||||
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
16
src/lua/Future.lua
Normal file
16
src/lua/Future.lua
Normal file
|
@ -0,0 +1,16 @@
|
|||
Future = {
|
||||
state = {}
|
||||
}
|
||||
|
||||
function Future:new(state)
|
||||
local f = {}
|
||||
setmetatable(f, self)
|
||||
self.__index = self
|
||||
f["state"] = state or {}
|
||||
|
||||
return f
|
||||
end
|
||||
|
||||
function Future:pull()
|
||||
return true
|
||||
end
|
35
src/lua/FutureLua.hpp
Normal file
35
src/lua/FutureLua.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
static inline const char lua_future_class[] = R"(
|
||||
Future = {
|
||||
state = {}
|
||||
}
|
||||
|
||||
function Future:new(state)
|
||||
local f = {}
|
||||
setmetatable(f, self)
|
||||
self.__index = self
|
||||
f["state"] = state or {}
|
||||
|
||||
return f
|
||||
end
|
||||
|
||||
function Future:poll()
|
||||
return true
|
||||
end
|
||||
|
||||
function Future.get(t, ...)
|
||||
return t:poll(unpack(arg))
|
||||
end
|
||||
)";
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
class Future
|
||||
{
|
||||
public:
|
||||
virtual ~Future() = default;
|
||||
virtual bool poll() = 0;
|
||||
virtual T& get() = 0;
|
||||
};
|
|
@ -1,61 +0,0 @@
|
|||
#include "safesol.h"
|
||||
|
||||
safesol::LuaResultType safesol::script(const std::string& script)
|
||||
{
|
||||
sol::load_result result = lua.load(script);
|
||||
if (!result.valid()) {
|
||||
sol::error err = result;
|
||||
std::cout << "Error loading script: " << err.what() << std::endl;
|
||||
return LuaResultType::LOAD_ERROR;
|
||||
}
|
||||
|
||||
sol::protected_function_result script_result = result();
|
||||
|
||||
if (!script_result.valid()) {
|
||||
sol::error err = script_result;
|
||||
std::cout << "Error running script: " << err.what() << std::endl;
|
||||
return LuaResultType::SCRIPT_ERROR;
|
||||
}
|
||||
|
||||
return LuaResultType::SUCCESS;
|
||||
}
|
||||
|
||||
safesol::LuaResultType safesol::script(const char* script)
|
||||
{
|
||||
sol::load_result result = lua.load(script);
|
||||
if (!result.valid()) {
|
||||
sol::error err = result;
|
||||
std::cout << "Error loading script: " << err.what() << std::endl;
|
||||
return LuaResultType::LOAD_ERROR;
|
||||
}
|
||||
|
||||
sol::protected_function_result script_result = result();
|
||||
|
||||
if (!script_result.valid()) {
|
||||
sol::error err = script_result;
|
||||
std::cout << "Error running script: " << err.what() << std::endl;
|
||||
return LuaResultType::SCRIPT_ERROR;
|
||||
}
|
||||
|
||||
return LuaResultType::SUCCESS;
|
||||
}
|
||||
|
||||
safesol::LuaResultType safesol::load(const std::string& file)
|
||||
{
|
||||
sol::load_result result = lua.load_file(file);
|
||||
if (!result.valid()) {
|
||||
sol::error err = result;
|
||||
std::cout << "Error loading file: " << err.what() << std::endl;
|
||||
return LuaResultType::LOAD_ERROR;
|
||||
}
|
||||
|
||||
sol::protected_function_result script_result = result();
|
||||
|
||||
if (!script_result.valid()) {
|
||||
sol::error err = script_result;
|
||||
std::cout << "Error running script: " << err.what() << std::endl;
|
||||
return LuaResultType::SCRIPT_ERROR;
|
||||
}
|
||||
|
||||
return LuaResultType::SUCCESS;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
#pragma once
|
||||
#include <std.hpp>
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
class safesol
|
||||
{
|
||||
public:
|
||||
enum class LuaResultType : u8
|
||||
{
|
||||
SUCCESS = 0,
|
||||
LOAD_ERROR = 1,
|
||||
SCRIPT_ERROR,
|
||||
RUN_ERROR,
|
||||
UNKNOWN_ERROR
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
|
||||
|
||||
LuaResultType script(const std::string& script);
|
||||
LuaResultType script(const char* script);
|
||||
|
||||
LuaResultType load(const std::string& file);
|
||||
|
||||
template<typename ...Args>
|
||||
sol::protected_function_result default_caller(const sol::protected_function& function, Args&&... args)
|
||||
{
|
||||
return function(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
LuaResultType run(const std::string& function_name, Args&&... args)
|
||||
{
|
||||
return run_on_caller(function_name, default_caller, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...Args, typename Caller = std::function<sol::protected_function_result(const sol::protected_function&, Args&&...)>>
|
||||
LuaResultType run_on_caller(const std::string& function_name, const Caller& caller, Args&&... args)
|
||||
{
|
||||
std::cout << "Looking for function: " << function_name << std::endl;
|
||||
|
||||
auto function = lua[function_name];
|
||||
if (!function.valid()) {
|
||||
std::cout << "Error: function " << function_name << " not found" << std::endl;
|
||||
return LuaResultType::RUN_ERROR;
|
||||
}
|
||||
|
||||
std::cout << "Found function, attempting to run" << std::endl;
|
||||
|
||||
auto result = caller(function, std::forward<Args>(args)...);
|
||||
if (!result.valid()) {
|
||||
sol::error err = result;
|
||||
std::cout << "Error running function " << function_name << ": " << err.what() << std::endl;
|
||||
return LuaResultType::RUN_ERROR;
|
||||
}
|
||||
|
||||
return LuaResultType::SUCCESS;
|
||||
}
|
||||
};
|
214
src/main.cpp
214
src/main.cpp
|
@ -1,213 +1,21 @@
|
|||
#include <iostream>
|
||||
#include <raylib.h>
|
||||
#include <raylibs/raygui.h>
|
||||
#include "sva.hpp"
|
||||
|
||||
|
||||
#include "gui/drawing_helper.hpp"
|
||||
|
||||
#define RESOURCES_PATH "G:/School/Belegarbeit/sortiva/res/"
|
||||
|
||||
#define SETTINGS_PATH "./.config.cfg"
|
||||
|
||||
#define NO_GUI
|
||||
|
||||
|
||||
#ifndef NO_GUI
|
||||
|
||||
int screenWidth = 1280;
|
||||
int screenHeight = 720;
|
||||
|
||||
enum GAME_STATES
|
||||
{
|
||||
SVA_STATE_TITLE,
|
||||
SVA_STATE_GAMEPLAY,
|
||||
};
|
||||
|
||||
GAME_STATES gameState = SVA_STATE_TITLE;
|
||||
|
||||
void UpdateDrawFrame(); // Update and Draw one frame
|
||||
|
||||
#include "gui/themes/dark.h"
|
||||
#include "gui/Views/ViewManager.h"
|
||||
#endif
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
#ifdef NO_GUI
|
||||
#include "SortingTester.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include <random>
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<u64> dis(0, 10);
|
||||
|
||||
void populate(size_t index, u64& value)
|
||||
{
|
||||
value = dis(gen);
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sortiva/sortiva.hpp"
|
||||
|
||||
//#undef _DEBUG
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
sva_console_init();
|
||||
|
||||
#ifdef NO_GUI
|
||||
|
||||
std::cout << "Sortiva - Sorting Algorithm Visualizer" << std::endl;
|
||||
std::cout << "No GUI mode" << std::endl;
|
||||
|
||||
SortingTester tester;
|
||||
tester.populate( populate );
|
||||
|
||||
tester.load_internal();
|
||||
|
||||
SortingTester::run_result result = tester.run("bubble_sort");
|
||||
|
||||
std::cout << "Time: " << result.timer.seconds << " seconds" << std::endl;
|
||||
std::cout << "Difftime: " << result.timer.difftime << std::endl;
|
||||
|
||||
|
||||
std::cout << "Count swaps: " << result.count_swaps << std::endl;
|
||||
std::cout << "Count comparisons: " << result.count_comparisons << std::endl;
|
||||
std::cout << "\tCount greater: " << result.count_greater << std::endl;
|
||||
std::cout << "\tCount less: " << result.count_less << std::endl;
|
||||
std::cout << "\tCount equal: " << result.count_equal << std::endl;
|
||||
|
||||
std::cout << "\n\n";
|
||||
|
||||
|
||||
std::cout << "\nPress any key to exit..." << std::endl;
|
||||
// getchar();
|
||||
|
||||
printf("Darling, I'm Home!\n");
|
||||
#ifdef _DEBUG
|
||||
try {
|
||||
#endif
|
||||
|
||||
#ifndef NO_GUI
|
||||
if(!DirectoryExists(RESOURCES_PATH))
|
||||
{
|
||||
std::cerr << "Resources folder not found!" << std::endl;
|
||||
return -1;
|
||||
Sortiva app;
|
||||
app.run();
|
||||
#ifdef _DEBUG
|
||||
}
|
||||
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "Sortiva - Sorting Algorithm Visualizer");
|
||||
|
||||
SetWindowIcon(LoadImage(RESOURCES_PATH "/images/sva-logo.png"));
|
||||
|
||||
SetWindowMinSize(screenWidth, screenHeight);
|
||||
SetWindowState(FLAG_WINDOW_RESIZABLE);
|
||||
SetExitKey(0);
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
GuiLoadStyleDark();
|
||||
GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
catch (std::exception& e)
|
||||
{
|
||||
if (IsWindowResized())
|
||||
{
|
||||
screenWidth = GetScreenWidth();
|
||||
screenHeight = GetScreenHeight();
|
||||
}
|
||||
UpdateDrawFrame();
|
||||
printf("\nError: %s\n\n", e.what());
|
||||
}
|
||||
CloseWindow();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NO_GUI
|
||||
//----------------------------------------------------------------------------------
|
||||
// Render Functions
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
void RenderGameplayState();
|
||||
|
||||
|
||||
Rectangle ButtonRects[] = {
|
||||
{50, 150, 150, 40},
|
||||
{50, 200, 150, 40},
|
||||
{50, 300, 150, 40},
|
||||
};
|
||||
|
||||
void UpdateDrawFrame()
|
||||
{
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
|
||||
|
||||
switch (gameState)
|
||||
{
|
||||
case SVA_STATE_TITLE:
|
||||
sva::DrawText("Sortiva", {screenWidth/2, 20}, 100, sva::GetThemeColor(TEXT_COLOR_NORMAL), sva::TEXT_ALIGN_CENTER);
|
||||
|
||||
if(GuiButton(ButtonRects[0], "Öffnen"))
|
||||
{
|
||||
gameState = SVA_STATE_GAMEPLAY;
|
||||
}
|
||||
if(GuiButton(ButtonRects[1], "Speichern"))
|
||||
{
|
||||
gameState = SVA_STATE_GAMEPLAY;
|
||||
}
|
||||
if(GuiButton(ButtonRects[2], "Schließen"))
|
||||
{
|
||||
CloseWindow();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
break;
|
||||
case SVA_STATE_GAMEPLAY:
|
||||
if(IsKeyPressed(KEY_ESCAPE))
|
||||
{
|
||||
gameState = SVA_STATE_TITLE;
|
||||
}
|
||||
RenderGameplayState();
|
||||
break;
|
||||
}
|
||||
EndDrawing();
|
||||
}
|
||||
#include <numbers>
|
||||
|
||||
#define PI_2 std::numbers::pi_v<float> / 2
|
||||
|
||||
#define sin3(x) pow((-cos(PI_2+ ##x)),3)
|
||||
|
||||
#include <cmath>
|
||||
|
||||
Vector2 heart_position = Vector2{static_cast<float>(screenWidth)/2, static_cast<float>(screenHeight)/2.5f};
|
||||
Vector2 heart_function(float t, float scale)
|
||||
{
|
||||
return Vector2{
|
||||
((16 * static_cast<float>(sin3(t))) * scale) + heart_position.x,
|
||||
((13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)) * -scale) + heart_position.y
|
||||
};
|
||||
}
|
||||
|
||||
#define STEPS 1000
|
||||
#define STEP_SIZE 0.01f
|
||||
|
||||
void RenderGameplayState()
|
||||
{
|
||||
for (int i = 0; i < STEPS; i++)
|
||||
{
|
||||
Vector2 pos = heart_function(static_cast<float>(i) * STEP_SIZE, 20);
|
||||
Vector2 pos2 = heart_function(static_cast<float>(i) * STEP_SIZE + STEP_SIZE, 20);
|
||||
DrawLine(
|
||||
pos.x,
|
||||
pos.y,
|
||||
pos2.x,
|
||||
pos2.y,
|
||||
GetColor(GuiGetStyle(DEFAULT, LINE_COLOR))
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
45
src/sortiva/GuiFileDialog.cpp
Normal file
45
src/sortiva/GuiFileDialog.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "GuiFileDialog.hpp"
|
||||
#include <raylibs/raygui.h>
|
||||
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
||||
|
||||
|
||||
Gui_WindowFileDialog::Gui_WindowFileDialog()
|
||||
{
|
||||
fileDialogState = new GuiWindowFileDialogState(InitGuiWindowFileDialog(GetWorkingDirectory()));
|
||||
fileDialogState->windowBounds = { 10, 10, fileDialogState->windowBounds.height, fileDialogState->windowBounds.height };
|
||||
}
|
||||
|
||||
bool Gui_WindowFileDialog::update()
|
||||
{
|
||||
bool file_opened = false;
|
||||
if (fileDialogState->SelectFilePressed)
|
||||
{
|
||||
// Load image file (if supported extension)
|
||||
if (IsFileExtension(fileDialogState->fileNameText, ".lua"))
|
||||
{
|
||||
strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState->dirPathText, fileDialogState->fileNameText));
|
||||
openedFile = fileNameToLoad;
|
||||
file_opened = true;
|
||||
}
|
||||
|
||||
fileDialogState->SelectFilePressed = false;
|
||||
}
|
||||
return file_opened;
|
||||
}
|
||||
|
||||
void Gui_WindowFileDialog::draw()
|
||||
{
|
||||
// raygui: controls drawing
|
||||
//----------------------------------------------------------------------------------
|
||||
if (fileDialogState->windowActive) GuiLock();
|
||||
|
||||
if (GuiButton({ 20, 20, 140, 30 }, GuiIconText(GuiIconName::ICON_FILE_OPEN, "Open Image"))) fileDialogState->windowActive = true;
|
||||
|
||||
GuiUnlock();
|
||||
|
||||
// GUI: Dialog Window
|
||||
//--------------------------------------------------------------------------------
|
||||
GuiWindowFileDialog(fileDialogState);
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
}
|
19
src/sortiva/GuiFileDialog.hpp
Normal file
19
src/sortiva/GuiFileDialog.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
class Gui_WindowFileDialog
|
||||
{
|
||||
GuiWindowFileDialogState* fileDialogState;
|
||||
char fileNameToLoad[512] = { 0 };
|
||||
public:
|
||||
Gui_WindowFileDialog();
|
||||
|
||||
std::string openedFile;
|
||||
|
||||
bool update();
|
||||
|
||||
void draw();
|
||||
};
|
210
src/sortiva/sortiva-draw.cpp
Normal file
210
src/sortiva/sortiva-draw.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "sortiva.hpp"
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
constexpr Color sorter_colors[] = {
|
||||
{ 253, 249, 0, 255 }, // Yellow
|
||||
{ 255, 203, 0, 255 }, // Gold
|
||||
{ 255, 161, 0, 255 }, // Orange
|
||||
{ 255, 109, 194, 255 }, // Pink
|
||||
{ 230, 41, 55, 255 }, // Red
|
||||
{ 190, 33, 55, 255 }, // Maroon
|
||||
{ 0, 228, 48, 255 }, // Green
|
||||
{ 0, 158, 47, 255 }, // Lime
|
||||
{ 0, 117, 44, 255 }, // Dark Green
|
||||
{ 102, 191, 255, 255 }, // Sky Blue
|
||||
{ 0, 121, 241, 255 }, // Blue
|
||||
{ 0, 82, 172, 255 }, // Dark Blue
|
||||
{ 255, 0, 255, 255 }, // Magenta
|
||||
{ 200, 122, 255, 255 }, // Purple
|
||||
{ 135, 60, 190, 255 }, // Violet
|
||||
{ 112, 31, 126, 255 }, // Dark Purple
|
||||
{ 211, 176, 131, 255 }, // Beige
|
||||
{ 127, 106, 79, 255 }, // Brown
|
||||
{ 76, 63, 47, 255 }, // Dark Brown
|
||||
};
|
||||
|
||||
constexpr int sorter_colors_size = sizeof(sorter_colors) / sizeof(Color);
|
||||
|
||||
constexpr Color sorter_block_colors[] = {
|
||||
{ 200, 200, 200, 255 }, // Light Gray
|
||||
{ 80, 80, 80, 255 }, // Dark Gray
|
||||
};
|
||||
|
||||
constexpr int sorter_block_colors_size = sizeof(sorter_block_colors) / sizeof(Color);
|
||||
|
||||
|
||||
void Sortiva::draw()
|
||||
{
|
||||
Vector2 margin = {
|
||||
.x = m_Width * 0.01f,
|
||||
.y = 70
|
||||
};
|
||||
DrawRectangleV(margin, { m_Width - 2 * margin.x, m_Height - 2 * margin.y }, { 60, 60, 60, 255 });
|
||||
|
||||
|
||||
margin = {
|
||||
.x = m_Width * 0.02f,
|
||||
.y = 80
|
||||
};
|
||||
|
||||
Rectangle plane = {
|
||||
.x = margin.x,
|
||||
.y = margin.y,
|
||||
.width = m_Width - margin.x * 2,
|
||||
.height = m_Height - margin.y * 2
|
||||
};
|
||||
|
||||
if (m_Steps->empty())
|
||||
{
|
||||
static const char* msg = "Press \"Run\" to start a sorting";
|
||||
static int width = MeasureText(msg, 20);
|
||||
DrawText(msg, plane.x + plane.width / 2 - width / 2, plane.y + plane.height / 2 - 10, 20, { 245, 245, 245, 255 });
|
||||
return;
|
||||
}
|
||||
|
||||
// +2 for start points and end points; will be removed later in the function
|
||||
size_t cvals = m_Steps->size();
|
||||
|
||||
size_t steps = m_Steps->at(0).depth();
|
||||
for (size_t i = 1; i < cvals; ++i)
|
||||
{
|
||||
steps = std::min(steps, m_Steps->at(i).depth());
|
||||
}
|
||||
|
||||
steps += 1;
|
||||
|
||||
// ui distance values
|
||||
int w = static_cast<int>(plane.width / static_cast<float>(steps));
|
||||
int g = plane.height / static_cast<float>(cvals + 1);
|
||||
int h = (plane.height - static_cast<float>(cvals - 1) * g) / 2;
|
||||
int e = w / 2;
|
||||
float wf = static_cast<float>(w);
|
||||
|
||||
float pwhd = sqrtf(plane.width * plane.width + plane.height * plane.height);
|
||||
float pw = plane.width / pwhd - 0.01f;
|
||||
float ph = plane.height / pwhd;
|
||||
float l = pw * ph * pwhd * 0.02f - static_cast<float>(steps) / 2; // Make more fitting
|
||||
|
||||
for (size_t i = 0; i < steps; ++i)
|
||||
{
|
||||
DrawRectangle(
|
||||
static_cast<int>(i) * w + static_cast<int>(plane.x),
|
||||
plane.y,
|
||||
w,
|
||||
plane.height,
|
||||
sorter_block_colors[i % sorter_block_colors_size]
|
||||
);
|
||||
}
|
||||
steps -= 1;
|
||||
|
||||
// colors to values - ratio ; adds high variance to the color selection
|
||||
int colid = sorter_colors_size / cvals;
|
||||
|
||||
// font settings
|
||||
constexpr Color textColor = { 0, 0, 0, 255 };
|
||||
int l3 = static_cast<int>(l * 3);
|
||||
|
||||
#ifdef _DEBUG
|
||||
DrawFPS(5, 5);
|
||||
#endif
|
||||
|
||||
for (int v = 0; v < cvals; ++v)
|
||||
{
|
||||
linked_list<uint16_t>* list = &m_Steps->at(v);
|
||||
uint16_t value = list->value;
|
||||
Color col = sorter_colors[(v * colid) % sorter_colors_size];
|
||||
|
||||
|
||||
|
||||
|
||||
int s = 0;
|
||||
for (; list->next; list = list->next)
|
||||
{
|
||||
float sf = static_cast<float>(s);
|
||||
|
||||
value = list->value;
|
||||
uint16_t nvalue = list->next->value;
|
||||
float y = plane.y + h + g * (value - 1);
|
||||
float yt = plane.y + h + g * (nvalue - 1);
|
||||
|
||||
|
||||
DrawSplineSegmentBezierCubic(
|
||||
{ (sf + 1.f) * wf + plane.x - 1, y },
|
||||
{ (sf + 2.f) * wf + plane.x, y },
|
||||
{ (sf + 1.f) * wf + plane.x, yt },
|
||||
{ (sf + 2.f) * wf + plane.x, yt },
|
||||
l,
|
||||
col
|
||||
);
|
||||
|
||||
#ifdef _DEBUG
|
||||
float font_size = l * 1.2f;
|
||||
int yd = y - yt < 0 ? -font_size : +font_size;
|
||||
yd *= 2;
|
||||
DrawText(
|
||||
TextFormat("%d -> %d", value, nvalue),
|
||||
(sf + 1.f) * wf + plane.x + 10,
|
||||
y + yd,
|
||||
font_size,
|
||||
col);
|
||||
#endif
|
||||
++s;
|
||||
}
|
||||
|
||||
value = list->value;
|
||||
|
||||
Vector2 pos = { wf * steps + e + plane.x, h + (value - 1) * g + plane.y };
|
||||
DrawCircleV(pos, l3, col);
|
||||
|
||||
DrawLineEx(
|
||||
{ pos.x - e - 1, pos.y },
|
||||
pos,
|
||||
l,
|
||||
col
|
||||
);
|
||||
|
||||
const char* strv = TextFormat("%d", v + 1);
|
||||
DrawText(
|
||||
strv,
|
||||
static_cast<int>(pos.x) + e / 2,
|
||||
static_cast<int>(pos.y) - l3 / 2,
|
||||
l3,
|
||||
textColor
|
||||
);
|
||||
|
||||
if (list->first)
|
||||
list = list->first;
|
||||
value = list->value;
|
||||
pos = { wf - e + plane.x, h + (value - 1) * g + plane.y };
|
||||
|
||||
DrawText(
|
||||
strv,
|
||||
static_cast<int>(pos.x) - e / 2 - l3 / 2,
|
||||
static_cast<int>(pos.y) - l3 / 2,
|
||||
l3,
|
||||
textColor
|
||||
);
|
||||
|
||||
DrawRing(
|
||||
pos,
|
||||
l * 2,
|
||||
l3,
|
||||
20.f,
|
||||
340.f,
|
||||
10,
|
||||
col
|
||||
);
|
||||
|
||||
DrawLineEx(
|
||||
pos,
|
||||
{ pos.x + e, pos.y },
|
||||
l,
|
||||
col
|
||||
);
|
||||
}
|
||||
|
||||
}
|
33
src/sortiva/sortiva-draw_overlay.cpp
Normal file
33
src/sortiva/sortiva-draw_overlay.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "sortiva.hpp"
|
||||
|
||||
#include <raylibs/raygui.h>
|
||||
|
||||
|
||||
void Sortiva::draw_overlay()
|
||||
{
|
||||
//static bool edit_mode = false;
|
||||
//
|
||||
//GuiUnlock();
|
||||
//
|
||||
//static int active = 0;
|
||||
//if (GuiDropdownBox({ 250,20,200,30 }, m_Lua.SorterListStr.c_str(), &active, edit_mode)) edit_mode = !edit_mode;
|
||||
//
|
||||
//if (edit_mode) GuiLock();
|
||||
|
||||
if (GuiButton({ 20, 15, 100, 40 }, "Run"))
|
||||
{
|
||||
setup();
|
||||
m_SortingFinished = false;
|
||||
}
|
||||
if (GuiButton({ 140, 15, 100, 40 }, m_SortingFinished ? "Continue" : "Pause"))
|
||||
{
|
||||
if (!m_SortingFinished || !m_Steps->empty()) {
|
||||
m_SortingFinished = !m_SortingFinished;
|
||||
}
|
||||
}
|
||||
|
||||
if (GuiButton({ 20, static_cast<float>(GetScreenHeight()) - 15 - 40, 100, 40 }, "Reset"))
|
||||
{
|
||||
m_Steps->clear();
|
||||
}
|
||||
}
|
22
src/sortiva/sortiva-update.cpp
Normal file
22
src/sortiva/sortiva-update.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "sortiva.hpp"
|
||||
|
||||
|
||||
void Sortiva::update(double dt) {
|
||||
if (m_Ticker.update(std::chrono::duration<float>(dt)))
|
||||
{
|
||||
if (!m_SortingFinished) {
|
||||
if (m_Sorter.poll())
|
||||
{
|
||||
m_SortingFinished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LuaSortList& list = m_Sorter.get();
|
||||
for (uint16_t i = 0; i < list.size(); ++i)
|
||||
{
|
||||
m_Steps->at(list.at(i) - 1).put(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
src/sortiva/sortiva.cpp
Normal file
81
src/sortiva/sortiva.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include "sortiva.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
|
||||
Sortiva::Sortiva() : m_Ticker(std::chrono::seconds(1))
|
||||
{
|
||||
m_Sorter.set(m_List);
|
||||
|
||||
m_Steps = std::make_unique<val_step_diag>();
|
||||
|
||||
InitWindow(1280, 720, "Sortiva");
|
||||
if (!IsWindowReady()) exit(2);
|
||||
|
||||
m_Width = GetRenderWidth();
|
||||
m_Height = GetRenderHeight();
|
||||
SetWindowMinSize(static_cast<int>(1280 * 0.25f), static_cast<int>(720 * 0.25f));
|
||||
SetWindowState(ConfigFlags::FLAG_WINDOW_RESIZABLE | ConfigFlags::FLAG_VSYNC_HINT);
|
||||
|
||||
SetTargetFPS(60);
|
||||
|
||||
MaximizeWindow();
|
||||
}
|
||||
|
||||
Sortiva::~Sortiva()
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
void Sortiva::run()
|
||||
{
|
||||
while (m_Running)
|
||||
{
|
||||
if (WindowShouldClose()) m_Running = false;
|
||||
if (IsWindowResized())
|
||||
{
|
||||
m_Width = GetScreenWidth();
|
||||
m_Height = GetScreenHeight();
|
||||
}
|
||||
|
||||
ClearBackground({ 25, 25, 25, 255 });
|
||||
BeginDrawing();
|
||||
|
||||
update(GetFrameTime());
|
||||
draw();
|
||||
draw_overlay();
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
void Sortiva::setup()
|
||||
{
|
||||
m_Steps->clear();
|
||||
m_List.list.clear();
|
||||
|
||||
uint16_t count = 5;
|
||||
|
||||
|
||||
for (int i = 1; i <= count; ++i) // 1,2,3,4,5
|
||||
{
|
||||
m_List.list.push_back(i);
|
||||
m_Steps->emplace_back();
|
||||
}
|
||||
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
|
||||
std::ranges::shuffle(m_List.list, rng); // 2,3,1,5,4
|
||||
|
||||
for (int i = 1; i <= count; ++i)
|
||||
{
|
||||
m_Steps->at(m_List.at(i - 1) - 1).value = i;
|
||||
}
|
||||
}
|
82
src/sortiva/sortiva.hpp
Normal file
82
src/sortiva/sortiva.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <collections.hpp>
|
||||
#include "../lua/FutureLua.hpp"
|
||||
#include <TickSystem.hpp>
|
||||
#include "../LuaSortList.hpp"
|
||||
|
||||
class Bubble_Sorter : Future<LuaSortList>
|
||||
{
|
||||
LuaSortList* list = nullptr;
|
||||
struct STATE
|
||||
{
|
||||
size_t n = 1;
|
||||
} state;
|
||||
public:
|
||||
Bubble_Sorter() = default;
|
||||
Bubble_Sorter(LuaSortList& l) : list(&l) {}
|
||||
|
||||
bool poll() override
|
||||
{
|
||||
size_t n = list->size();
|
||||
if (n <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
state.n = state.n + 1;
|
||||
|
||||
if (state.n > n)
|
||||
{
|
||||
state.n = 2;
|
||||
}
|
||||
|
||||
if (list->at(state.n - 2) > list->at(state.n - 1)) {
|
||||
list->swap(state.n - 2, state.n - 1);
|
||||
return false;
|
||||
}
|
||||
return list->sorted();
|
||||
}
|
||||
|
||||
LuaSortList& get() override
|
||||
{
|
||||
return *list;
|
||||
}
|
||||
|
||||
void set(LuaSortList& l)
|
||||
{
|
||||
list = &l;
|
||||
}
|
||||
};
|
||||
|
||||
class Sortiva final
|
||||
{
|
||||
public:
|
||||
Sortiva();
|
||||
~Sortiva();
|
||||
|
||||
void run();
|
||||
private:
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
bool m_Running = true;
|
||||
|
||||
void draw();
|
||||
void draw_overlay();
|
||||
void update(double);
|
||||
|
||||
void setup();
|
||||
|
||||
bool m_SortingFinished = true;
|
||||
TickSystem m_Ticker;
|
||||
Bubble_Sorter m_Sorter;
|
||||
LuaSortList m_List;
|
||||
|
||||
|
||||
// std::unique_ptr
|
||||
// -> tree
|
||||
// -> linked_list
|
||||
// -> uint16_t
|
||||
using val_step_diag = std::vector<linked_list<uint16_t>>;
|
||||
std::unique_ptr<val_step_diag> m_Steps;
|
||||
};
|
17
src/sva.hpp
17
src/sva.hpp
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
inline const char* ASCII_TITLE = R"(
|
||||
__
|
||||
(_ _ ___|_ o _
|
||||
__)(_) | |_ | \_/(_|
|
||||
|
||||
|
||||
|
||||
)";
|
||||
|
||||
inline void sva_console_init()
|
||||
{
|
||||
std::cout << ASCII_TITLE;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue