bla
This commit is contained in:
parent
898bcaf7b4
commit
d0783882b6
BIN
visualizer/.DS_Store
vendored
Normal file
BIN
visualizer/.DS_Store
vendored
Normal file
Binary file not shown.
137
visualizer/.clang-format
Executable file
137
visualizer/.clang-format
Executable file
@ -0,0 +1,137 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
...
|
||||
|
3
visualizer/.gitignore
vendored
Executable file
3
visualizer/.gitignore
vendored
Executable file
@ -0,0 +1,3 @@
|
||||
__pycache__
|
||||
build/
|
||||
.vscode/
|
12
visualizer/CMakeLists.txt
Executable file
12
visualizer/CMakeLists.txt
Executable file
@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(push_swap_visualizer
|
||||
LANGUAGES CXX
|
||||
VERSION 1.0
|
||||
)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
add_subdirectory(dependencies)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(tests)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/imgui.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/imgui.ini COPYONLY)
|
34
visualizer/README.md
Executable file
34
visualizer/README.md
Executable file
@ -0,0 +1,34 @@
|
||||
# Push Swap Visualizer
|
||||
This project is a visualizer for the **"PUSH_SWAP"** 42 School Project.
|
||||
|
||||
**Push Swap** is a program that takes as argument a space separated list of numbers and outputs a list of commands that can be used to sort them.
|
||||
|
||||
You can read the subject [here](https://github.com/Binary-Hackers/42_Subjects/blob/master/00_Projects/02_Algorithmic/push_swap.pdf).
|
||||
|
||||
## Usage
|
||||
- In the **Values** window
|
||||
- Choose the size of the push swap input with the slider [Optional]
|
||||
- **Shuffle** the input [Optional]
|
||||
- The space separated values should be filled automatically, you can also put your own values
|
||||
- Set the Push Swap program path (Absolute or relative path).
|
||||
- **Compute** the sort commands, it will display OK when done.
|
||||
- In the **Controls** window
|
||||
- **Load** the commands in the visualizer
|
||||
- **Start** the animation
|
||||
- Adjust the **Speed** as needed
|
||||
- **Pause** and go **Step** by step to see the details of your algorithm.
|
||||
- **Load** to restart the animation
|
||||
|
||||
## Install
|
||||
This project uses C++17, cmake, SFML and ImGui.
|
||||
- Install a C++ compiler (gcc, clang,...)
|
||||
- Install cmake
|
||||
- Move push_swap_visualizer inside push_swap
|
||||
- Inside push_swap_visualizer, mkdir :
|
||||
- 'build'
|
||||
- cd in the build folder and type :
|
||||
- 'cmake ..'
|
||||
- 'make'
|
||||
- run the visualizer with ./bin/visualizer
|
||||
|
||||
![](https://i.imgur.com/zqcsZfY.png)
|
31
visualizer/dependencies/CMakeLists.txt
Executable file
31
visualizer/dependencies/CMakeLists.txt
Executable file
@ -0,0 +1,31 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
sfml
|
||||
URL https://github.com/SFML/SFML/releases/download/2.5.1/SFML-2.5.1-sources.zip
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
imgui
|
||||
GIT_REPOSITORY https://github.com/ocornut/imgui
|
||||
GIT_TAG 35b1148efb839381b84de9290d9caf0b66ad7d03
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(imgui)
|
||||
|
||||
FetchContent_Declare(
|
||||
imgui-sfml
|
||||
GIT_REPOSITORY https://github.com/eliasdaler/imgui-sfml
|
||||
GIT_TAG 82dc2033e51b8323857c3ae1cf1f458b3a933c35
|
||||
)
|
||||
|
||||
add_subdirectory(imgui-sfml)
|
||||
add_subdirectory(sfml)
|
||||
|
||||
FetchContent_Declare(
|
||||
catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v2.13.7
|
||||
)
|
||||
|
||||
add_subdirectory(catch2)
|
4
visualizer/dependencies/catch2/CMakeLists.txt
Executable file
4
visualizer/dependencies/catch2/CMakeLists.txt
Executable file
@ -0,0 +1,4 @@
|
||||
message(STATUS "Fetching Catch2...")
|
||||
|
||||
FetchContent_MakeAvailable(catch2)
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib)
|
7
visualizer/dependencies/imgui-sfml/CMakeLists.txt
Executable file
7
visualizer/dependencies/imgui-sfml/CMakeLists.txt
Executable file
@ -0,0 +1,7 @@
|
||||
message(STATUS "Fetching ImGui-SFML...")
|
||||
|
||||
set(IMGUI_DIR ${imgui_SOURCE_DIR})
|
||||
set(IMGUI_SFML_FIND_SFML OFF)
|
||||
set(IMGUI_SFML_IMGUI_DEMO OFF)
|
||||
|
||||
FetchContent_MakeAvailable(imgui-sfml)
|
7
visualizer/dependencies/sfml/CMakeLists.txt
Executable file
7
visualizer/dependencies/sfml/CMakeLists.txt
Executable file
@ -0,0 +1,7 @@
|
||||
message(STATUS "Fetching SFML...")
|
||||
|
||||
# No need to build audio and network modules
|
||||
set(SFML_BUILD_AUDIO FALSE)
|
||||
set(SFML_BUILD_NETWORK FALSE)
|
||||
|
||||
FetchContent_MakeAvailable(sfml)
|
19
visualizer/imgui.ini
Executable file
19
visualizer/imgui.ini
Executable file
@ -0,0 +1,19 @@
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Controls]
|
||||
Pos=975,47
|
||||
Size=205,101
|
||||
Collapsed=0
|
||||
|
||||
[Window][Commands]
|
||||
Pos=1060,459
|
||||
Size=167,320
|
||||
Collapsed=0
|
||||
|
||||
[Window][Values]
|
||||
Pos=1212,140
|
||||
Size=182,207
|
||||
Collapsed=0
|
39
visualizer/include/gui.h
Executable file
39
visualizer/include/gui.h
Executable file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "pushswap.h"
|
||||
#include "queues.h"
|
||||
#include <SFML/Graphics/RectangleShape.hpp>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Gui {
|
||||
private:
|
||||
enum class STATE {Running, Reverse, Stopped};
|
||||
Queues queues;
|
||||
PushSwap pushswap;
|
||||
|
||||
std::vector<sf::RectangleShape> barsA;
|
||||
std::vector<sf::RectangleShape> barsB;
|
||||
int generateNumberSize;
|
||||
std::string numbers;
|
||||
int speed;
|
||||
STATE state;
|
||||
float scale;
|
||||
|
||||
void _updateControls();
|
||||
void _drawBars();
|
||||
void _animateQueue(sf::Clock &clock);
|
||||
std::list<int> _generateValues(const unsigned int size);
|
||||
void _updateBars();
|
||||
sf::Color _rgb(const double ratio);
|
||||
|
||||
public:
|
||||
sf::RenderWindow _window;
|
||||
|
||||
Gui();
|
||||
~Gui();
|
||||
|
||||
void loop();
|
||||
};
|
17
visualizer/include/pushswap.h
Executable file
17
visualizer/include/pushswap.h
Executable file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
class PushSwap {
|
||||
private:
|
||||
std::list<std::string> _split(const std::string &input, const char delimitor);
|
||||
|
||||
public:
|
||||
PushSwap();
|
||||
~PushSwap();
|
||||
void run(const std::string &numbers);
|
||||
|
||||
std::string path;
|
||||
std::list<std::string> commands;
|
||||
};
|
39
visualizer/include/queues.h
Executable file
39
visualizer/include/queues.h
Executable file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class Queues {
|
||||
enum COMMAND { NONE, SA, SB, SS, PA, PB, RA, RB, RR, RRA, RRB, RRR };
|
||||
std::map<const std::string, COMMAND> commandMap;
|
||||
|
||||
public:
|
||||
Queues();
|
||||
~Queues();
|
||||
|
||||
void step();
|
||||
void stepBack();
|
||||
void start(const std::list<int> &start);
|
||||
|
||||
std::list<std::string> commands;
|
||||
std::list<std::string> executedCommands;
|
||||
std::list<int> queueA;
|
||||
std::list<int> queueB;
|
||||
|
||||
private:
|
||||
void _executeCommand(const std::string &cmd);
|
||||
void _executeReverseCommand(const std::string &cmd);
|
||||
std::list<int> _normalize(const std::list<int> &numbers);
|
||||
void _sa();
|
||||
void _sb();
|
||||
void _ss();
|
||||
void _pa();
|
||||
void _pb();
|
||||
void _ra();
|
||||
void _rb();
|
||||
void _rr();
|
||||
void _rra();
|
||||
void _rrb();
|
||||
void _rrr();
|
||||
};
|
12
visualizer/include/utils.h
Executable file
12
visualizer/include/utils.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace Utils {
|
||||
std::list<std::string> SplitStringToString(const std::string &s,
|
||||
const char delimitor);
|
||||
std::list<int> SplitStringToInt(const std::string &s,
|
||||
const char delimitor);
|
||||
|
||||
} // namespace Utils
|
13
visualizer/src/CMakeLists.txt
Executable file
13
visualizer/src/CMakeLists.txt
Executable file
@ -0,0 +1,13 @@
|
||||
add_library(VisualizerLib STATIC utils.cpp queues.cpp pushswap.cpp gui.cpp)
|
||||
|
||||
target_link_libraries(VisualizerLib PUBLIC ImGui-SFML::ImGui-SFML)
|
||||
target_include_directories(VisualizerLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
|
||||
target_compile_features(VisualizerLib PRIVATE cxx_std_17)
|
||||
target_compile_options(VisualizerLib PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
|
||||
)
|
||||
|
||||
add_executable(visualizer main.cpp)
|
||||
target_compile_features(visualizer PRIVATE cxx_std_17)
|
||||
target_link_libraries(visualizer PRIVATE VisualizerLib)
|
236
visualizer/src/gui.cpp
Executable file
236
visualizer/src/gui.cpp
Executable file
@ -0,0 +1,236 @@
|
||||
#include "gui.h"
|
||||
#include "utils.h"
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/Window/Event.hpp>
|
||||
#include <imgui-SFML.h>
|
||||
#include <imgui.h>
|
||||
#include <misc/cpp/imgui_stdlib.h>
|
||||
#include <random>
|
||||
|
||||
Gui::Gui()
|
||||
: generateNumberSize{0}, speed{1}, state{STATE::Stopped}, scale{1.0f},
|
||||
_window{sf::VideoMode::getDesktopMode(), "Push Swap Visualizer"} {
|
||||
_window.setFramerateLimit(60);
|
||||
}
|
||||
Gui::~Gui() {}
|
||||
|
||||
std::list<int> Gui::_generateValues(const unsigned int size) {
|
||||
std::vector<int> values;
|
||||
for (unsigned int v = 1; v <= size; ++v) {
|
||||
values.push_back(v);
|
||||
}
|
||||
std::shuffle(values.begin(), values.end(),
|
||||
std::mt19937{std::random_device{}()});
|
||||
std::list<int> shuffledList;
|
||||
std::move(values.begin(), values.end(), back_inserter(shuffledList));
|
||||
return shuffledList;
|
||||
}
|
||||
|
||||
void Gui::_updateBars() {
|
||||
this->barsA.clear();
|
||||
this->barsB.clear();
|
||||
const sf::Vector2f windowSize = this->_window.getDefaultView().getSize();
|
||||
const uint64_t queuesSize{this->queues.queueA.size() +
|
||||
this->queues.queueB.size()};
|
||||
if (queuesSize == 0) {
|
||||
return;
|
||||
}
|
||||
const float barWidth = static_cast<float>(windowSize.y) / queuesSize;
|
||||
const float barUnit = static_cast<float>(windowSize.x) / (2 * queuesSize + 2);
|
||||
|
||||
const auto updateBar = [=](std::list<int> queue,
|
||||
std::vector<sf::RectangleShape> &bar,
|
||||
int deltaX = 0) {
|
||||
int index{0};
|
||||
for (const int val : queue) {
|
||||
bar.push_back(
|
||||
sf::RectangleShape(sf::Vector2f((1 + val) * barUnit, barWidth)));
|
||||
bar.back().setPosition(deltaX, index * barWidth);
|
||||
bar.back().setFillColor(this->_rgb(static_cast<float>(val) / queuesSize));
|
||||
index++;
|
||||
}
|
||||
};
|
||||
|
||||
updateBar(this->queues.queueA, this->barsA);
|
||||
updateBar(this->queues.queueB, this->barsB, windowSize.x / 2);
|
||||
}
|
||||
|
||||
void Gui::_updateControls() {
|
||||
ImGui::Begin("Controls");
|
||||
ImGui::SliderInt("Speed", &this->speed, 1, 500, "%i/s");
|
||||
|
||||
if (ImGui::Button("Start")) {
|
||||
this->state = STATE::Running;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reverse")) {
|
||||
this->state = STATE::Reverse;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Pause")) {
|
||||
this->state = STATE::Stopped;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Step")) {
|
||||
this->state = STATE::Stopped;
|
||||
this->queues.step();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Step Back")) {
|
||||
this->state = STATE::Stopped;
|
||||
this->queues.stepBack();
|
||||
}
|
||||
|
||||
ImGui::SliderFloat("Scale UI", &this->scale, 0.5f, 3.0f, "%.2f");
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Values");
|
||||
ImGui::Text("Values to generate");
|
||||
ImGui::InputInt("Count", &this->generateNumberSize);
|
||||
if (this->generateNumberSize < 0) {
|
||||
this->generateNumberSize = 0;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Shuffle")) {
|
||||
unsigned int size = static_cast<unsigned int>(this->generateNumberSize);
|
||||
std::list<int> valueInts = this->_generateValues(size);
|
||||
std::string values;
|
||||
for (const int value : valueInts) {
|
||||
values += std::to_string(value) + ' ';
|
||||
}
|
||||
this->numbers = values;
|
||||
}
|
||||
|
||||
ImGui::Text("Space separated values");
|
||||
ImGui::InputText("Values", &this->numbers);
|
||||
|
||||
ImGui::Text("push_swap file path");
|
||||
ImGui::InputText("", &this->pushswap.path);
|
||||
if (ImGui::Button("Compute")) {
|
||||
this->pushswap.run(this->numbers);
|
||||
this->state = STATE::Stopped;
|
||||
this->queues.start(Utils::SplitStringToInt(this->numbers, ' '));
|
||||
this->queues.commands = this->pushswap.commands;
|
||||
this->queues.executedCommands.clear();
|
||||
}
|
||||
|
||||
std::string status{"..."};
|
||||
if (!this->pushswap.commands.empty()) {
|
||||
status = "OK";
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", status.c_str());
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Commands");
|
||||
ImGui::Text("Count: %zu", this->pushswap.commands.size());
|
||||
ImGui::BeginChild("Scrolling");
|
||||
for (const auto &cmd : this->queues.commands) {
|
||||
ImGui::Text("%s", cmd.c_str());
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void Gui::_drawBars() {
|
||||
for (const auto &shape : this->barsA) {
|
||||
this->_window.draw(shape);
|
||||
}
|
||||
for (const auto &shape : this->barsB) {
|
||||
this->_window.draw(shape);
|
||||
}
|
||||
}
|
||||
|
||||
void Gui::_animateQueue(sf::Clock &clock) {
|
||||
float delta = clock.getElapsedTime().asSeconds();
|
||||
if (delta >= (1.0 / this->speed)) {
|
||||
clock.restart();
|
||||
}
|
||||
switch (this->state) {
|
||||
case STATE::Running: {
|
||||
int steps = static_cast<int>(delta * this->speed);
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
this->queues.step();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE::Reverse: {
|
||||
int steps = static_cast<int>(delta * this->speed);
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
this->queues.stepBack();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE::Stopped:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Gui::loop() {
|
||||
ImGui::SFML::Init(_window);
|
||||
|
||||
sf::Clock deltaClock;
|
||||
sf::Clock stepClock;
|
||||
while (_window.isOpen()) {
|
||||
sf::Event event;
|
||||
while (_window.pollEvent(event)) {
|
||||
ImGui::SFML::ProcessEvent(event);
|
||||
|
||||
if (event.type == sf::Event::Closed) {
|
||||
_window.close();
|
||||
}
|
||||
}
|
||||
ImGui::GetIO().FontGlobalScale = this->scale;
|
||||
this->_updateBars();
|
||||
ImGui::SFML::Update(this->_window, deltaClock.restart());
|
||||
|
||||
this->_updateControls();
|
||||
|
||||
this->_animateQueue(stepClock);
|
||||
|
||||
_window.clear();
|
||||
|
||||
this->_drawBars();
|
||||
|
||||
ImGui::SFML::Render(_window);
|
||||
_window.display();
|
||||
}
|
||||
ImGui::SFML::Shutdown();
|
||||
}
|
||||
|
||||
sf::Color Gui::_rgb(const double ratio) {
|
||||
int normalized = static_cast<int>(ratio * 256 * 4);
|
||||
int region = normalized / 256;
|
||||
int x = normalized % 256;
|
||||
|
||||
sf::Color color;
|
||||
color.a = 255;
|
||||
switch (region) {
|
||||
case 0:
|
||||
color.r = 0;
|
||||
color.g = x;
|
||||
color.b = 255;
|
||||
break;
|
||||
case 1:
|
||||
color.r = 0;
|
||||
color.g = 255;
|
||||
color.b = 255 - x;
|
||||
break;
|
||||
case 2:
|
||||
color.r = x;
|
||||
color.g = 255;
|
||||
color.b = 0;
|
||||
break;
|
||||
case 3:
|
||||
color.r = 255;
|
||||
color.g = 255 - x;
|
||||
color.b = 0;
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
}
|
7
visualizer/src/main.cpp
Executable file
7
visualizer/src/main.cpp
Executable file
@ -0,0 +1,7 @@
|
||||
#include "gui.h"
|
||||
|
||||
int main() {
|
||||
Gui gui;
|
||||
gui.loop();
|
||||
return 0;
|
||||
}
|
27
visualizer/src/pushswap.cpp
Executable file
27
visualizer/src/pushswap.cpp
Executable file
@ -0,0 +1,27 @@
|
||||
#include "pushswap.h"
|
||||
#include "utils.h"
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
PushSwap::PushSwap() : path{"./push_swap"} {}
|
||||
PushSwap::~PushSwap() {}
|
||||
|
||||
void PushSwap::run(const std::string &numbers) {
|
||||
this->commands.clear();
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
std::string command = this->path + " " + numbers;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"),
|
||||
pclose);
|
||||
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
this->commands = Utils::SplitStringToString(result, '\n');
|
||||
}
|
221
visualizer/src/queues.cpp
Executable file
221
visualizer/src/queues.cpp
Executable file
@ -0,0 +1,221 @@
|
||||
#include "queues.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
Queues::Queues()
|
||||
: commandMap{
|
||||
{"sa", COMMAND::SA}, {"sb", COMMAND::SB}, {"ss", COMMAND::SS},
|
||||
{"pa", COMMAND::PA}, {"pb", COMMAND::PB}, {"ra", COMMAND::RA},
|
||||
{"rb", COMMAND::RB}, {"rr", COMMAND::RR}, {"rra", COMMAND::RRA},
|
||||
{"rrb", COMMAND::RRB}, {"rrr", COMMAND::RRR},
|
||||
} {}
|
||||
Queues::~Queues() {}
|
||||
|
||||
void Queues::step() {
|
||||
if (this->commands.empty()) {
|
||||
return;
|
||||
}
|
||||
this->_executeCommand(this->commands.front());
|
||||
this->executedCommands.push_front(this->commands.front());
|
||||
this->commands.pop_front();
|
||||
}
|
||||
|
||||
void Queues::stepBack() {
|
||||
if (this->executedCommands.empty()) {
|
||||
return;
|
||||
}
|
||||
this->_executeReverseCommand(this->executedCommands.front());
|
||||
this->commands.push_front(this->executedCommands.front());
|
||||
this->executedCommands.pop_front();
|
||||
}
|
||||
|
||||
std::list<int> Queues::_normalize(const std::list<int> &numbers) {
|
||||
std::list<int> normalized{numbers};
|
||||
std::vector<int> ordered(numbers.size());
|
||||
std::copy(numbers.begin(), numbers.end(), ordered.begin());
|
||||
std::sort(ordered.begin(), ordered.end());
|
||||
for (int &number : normalized) {
|
||||
const auto order = std::find(ordered.begin(), ordered.end(), number);
|
||||
number = order - ordered.begin();
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
void Queues::start(const std::list<int> &start) {
|
||||
this->queueA = this->_normalize(start);
|
||||
this->queueB.clear();
|
||||
}
|
||||
|
||||
void Queues::_executeCommand(const std::string &cmd) {
|
||||
COMMAND command{COMMAND::NONE};
|
||||
try {
|
||||
command = this->commandMap[cmd];
|
||||
} catch (...) {
|
||||
}
|
||||
switch (command) {
|
||||
case COMMAND::SA:
|
||||
this->_sa();
|
||||
break;
|
||||
case COMMAND::SB:
|
||||
this->_sb();
|
||||
break;
|
||||
case COMMAND::SS:
|
||||
this->_ss();
|
||||
break;
|
||||
case COMMAND::PA:
|
||||
this->_pa();
|
||||
break;
|
||||
case COMMAND::PB:
|
||||
this->_pb();
|
||||
break;
|
||||
case COMMAND::RA:
|
||||
this->_ra();
|
||||
break;
|
||||
case COMMAND::RB:
|
||||
this->_rb();
|
||||
break;
|
||||
case COMMAND::RR:
|
||||
this->_rr();
|
||||
break;
|
||||
case COMMAND::RRA:
|
||||
this->_rra();
|
||||
break;
|
||||
case COMMAND::RRB:
|
||||
this->_rrb();
|
||||
break;
|
||||
case COMMAND::RRR:
|
||||
this->_rrr();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Queues::_executeReverseCommand(const std::string &cmd) {
|
||||
COMMAND command{COMMAND::NONE};
|
||||
try {
|
||||
command = this->commandMap[cmd];
|
||||
} catch (...) {
|
||||
}
|
||||
switch (command) {
|
||||
case COMMAND::SA:
|
||||
this->_sa();
|
||||
break;
|
||||
case COMMAND::SB:
|
||||
this->_sb();
|
||||
break;
|
||||
case COMMAND::SS:
|
||||
this->_ss();
|
||||
break;
|
||||
case COMMAND::PA:
|
||||
this->_pb();
|
||||
break;
|
||||
case COMMAND::PB:
|
||||
this->_pa();
|
||||
break;
|
||||
case COMMAND::RA:
|
||||
this->_rra();
|
||||
break;
|
||||
case COMMAND::RB:
|
||||
this->_rrb();
|
||||
break;
|
||||
case COMMAND::RR:
|
||||
this->_rrr();
|
||||
break;
|
||||
case COMMAND::RRA:
|
||||
this->_ra();
|
||||
break;
|
||||
case COMMAND::RRB:
|
||||
this->_rb();
|
||||
break;
|
||||
case COMMAND::RRR:
|
||||
this->_rr();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Queues::_sa() {
|
||||
if (this->queueA.size() < 2) {
|
||||
return;
|
||||
}
|
||||
std::swap(*this->queueA.begin(), *(++this->queueA.begin()));
|
||||
}
|
||||
|
||||
void Queues::_sb() {
|
||||
if (this->queueB.size() < 2) {
|
||||
return;
|
||||
}
|
||||
std::swap(*this->queueB.begin(), *(++this->queueB.begin()));
|
||||
}
|
||||
|
||||
void Queues::_ss() {
|
||||
this->_sa();
|
||||
this->_sb();
|
||||
}
|
||||
|
||||
void Queues::_pa() {
|
||||
if (this->queueB.empty()) {
|
||||
return;
|
||||
}
|
||||
int firstElement = this->queueB.front();
|
||||
this->queueB.pop_front();
|
||||
this->queueA.push_front(firstElement);
|
||||
}
|
||||
|
||||
void Queues::_pb() {
|
||||
if (this->queueA.empty()) {
|
||||
return;
|
||||
}
|
||||
int firstElement = this->queueA.front();
|
||||
this->queueA.pop_front();
|
||||
this->queueB.push_front(firstElement);
|
||||
}
|
||||
|
||||
void Queues::_ra() {
|
||||
if (this->queueA.size() < 2) {
|
||||
return;
|
||||
}
|
||||
int firstElement = this->queueA.front();
|
||||
this->queueA.pop_front();
|
||||
this->queueA.push_back(firstElement);
|
||||
}
|
||||
|
||||
void Queues::_rb() {
|
||||
if (this->queueB.size() < 2) {
|
||||
return;
|
||||
}
|
||||
int firstElement = this->queueB.front();
|
||||
this->queueB.pop_front();
|
||||
this->queueB.push_back(firstElement);
|
||||
}
|
||||
|
||||
void Queues::_rr() {
|
||||
this->_ra();
|
||||
this->_rb();
|
||||
}
|
||||
|
||||
void Queues::_rra() {
|
||||
if (this->queueA.size() < 2) {
|
||||
return;
|
||||
}
|
||||
int lastElement = this->queueA.back();
|
||||
this->queueA.pop_back();
|
||||
this->queueA.push_front(lastElement);
|
||||
}
|
||||
|
||||
void Queues::_rrb() {
|
||||
if (this->queueB.size() < 2) {
|
||||
return;
|
||||
}
|
||||
int lastElement = this->queueB.back();
|
||||
this->queueB.pop_back();
|
||||
this->queueB.push_front(lastElement);
|
||||
}
|
||||
|
||||
void Queues::_rrr() {
|
||||
this->_rra();
|
||||
this->_rrb();
|
||||
}
|
27
visualizer/src/utils.cpp
Executable file
27
visualizer/src/utils.cpp
Executable file
@ -0,0 +1,27 @@
|
||||
#include "utils.h"
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace Utils {
|
||||
std::list<std::string> SplitStringToString(const std::string &s,
|
||||
const char delimitor) {
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
std::list<std::string> elems;
|
||||
while (std::getline(ss, item, delimitor)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::list<int> SplitStringToInt(const std::string &s, const char delimitor) {
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
std::list<int> elems;
|
||||
while (std::getline(ss, item, delimitor)) {
|
||||
elems.push_back(std::stoi(item));
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
} // namespace Utils
|
4
visualizer/tests/CMakeLists.txt
Executable file
4
visualizer/tests/CMakeLists.txt
Executable file
@ -0,0 +1,4 @@
|
||||
|
||||
add_executable(tests test_queues.cpp test_pushswap.cpp)
|
||||
target_link_libraries(tests PRIVATE Catch2::Catch2 VisualizerLib)
|
||||
target_include_directories(tests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
10
visualizer/tests/test_pushswap.cpp
Executable file
10
visualizer/tests/test_pushswap.cpp
Executable file
@ -0,0 +1,10 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include "pushswap.h"
|
||||
|
||||
TEST_CASE("run", "[PushSwap]") {
|
||||
PushSwap ps;
|
||||
ps.path = "../push_swap";
|
||||
ps.run("2 1 3");
|
||||
REQUIRE_FALSE(ps.commands.empty());
|
||||
REQUIRE(ps.commands.front() == "sa");
|
||||
}
|
84
visualizer/tests/test_queues.cpp
Executable file
84
visualizer/tests/test_queues.cpp
Executable file
@ -0,0 +1,84 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
#include "queues.h"
|
||||
|
||||
TEST_CASE("normalize", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.start({2, 10, 4});
|
||||
auto it = queues.queueA.begin();
|
||||
REQUIRE(*it == 0);
|
||||
REQUIRE(*(++it) == 2);
|
||||
REQUIRE(*(++it) == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("sa", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueA = {1, 2, 3, 4};
|
||||
queues.commands = {"sa"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueA.front() == 2);
|
||||
REQUIRE(*(++queues.queueA.begin()) == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("sb", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueB = {1, 2, 3, 4};
|
||||
queues.commands = {"sb"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueB.front() == 2);
|
||||
REQUIRE(*(++queues.queueB.begin()) == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("pa", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueB = {1, 2, 3, 4};
|
||||
queues.commands = {"pa"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueB.front() == 2);
|
||||
REQUIRE(queues.queueA.front() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("pb", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueA = {1, 2, 3, 4};
|
||||
queues.commands = {"pb"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueA.front() == 2);
|
||||
REQUIRE(queues.queueB.front() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("ra", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueA = {1, 2, 3, 4};
|
||||
queues.commands = {"ra"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueA.front() == 2);
|
||||
REQUIRE(queues.queueA.back() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("rb", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueB = {1, 2, 3, 4};
|
||||
queues.commands = {"rb"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueB.front() == 2);
|
||||
REQUIRE(queues.queueB.back() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("rra", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueA = {1, 2, 3, 4};
|
||||
queues.commands = {"rra"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueA.front() == 4);
|
||||
REQUIRE(queues.queueA.back() == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("rrb", "[Queues]") {
|
||||
Queues queues;
|
||||
queues.queueB = {1, 2, 3, 4};
|
||||
queues.commands = {"rrb"};
|
||||
queues.step();
|
||||
REQUIRE(queues.queueB.front() == 4);
|
||||
REQUIRE(queues.queueB.back() == 3);
|
||||
}
|
Loading…
Reference in New Issue
Block a user