* 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:
n0ffie 2025-01-11 04:18:48 +01:00 committed by GitHub
parent 96e6514337
commit a89b27d456
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 1665 additions and 1228 deletions

33
src/LuaSortList.hpp Normal file
View 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;
}
};

View file

@ -1 +0,0 @@
#include "Renderer.h"

View file

@ -1,7 +0,0 @@
#pragma once
class Renderer
{
public:
};

View file

@ -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;
}

View file

@ -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);
};

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -1,2 +0,0 @@
#define RAYGUI_IMPLEMENTATION
#include <raylibs/raygui.h>

View file

@ -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
}

View file

@ -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
View 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
View 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
View 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;
};

View file

@ -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;
}

View file

@ -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;
}
};

View file

@ -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

View 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);
//--------------------------------------------------------------------------------
}

View 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();
};

View 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
);
}
}

View 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();
}
}

View 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
View 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
View 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;
};

View file

@ -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;
}