This commit is contained in:
Danny Jonker 2023-03-24 16:19:05 +01:00
parent 898bcaf7b4
commit d0783882b6
23 changed files with 990 additions and 0 deletions

BIN
visualizer/.DS_Store vendored Normal file

Binary file not shown.

137
visualizer/.clang-format Executable file
View 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
View File

@ -0,0 +1,3 @@
__pycache__
build/
.vscode/

12
visualizer/CMakeLists.txt Executable file
View 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
View 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)

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

View File

@ -0,0 +1,4 @@
message(STATUS "Fetching Catch2...")
FetchContent_MakeAvailable(catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib)

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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,7 @@
#include "gui.h"
int main() {
Gui gui;
gui.loop();
return 0;
}

27
visualizer/src/pushswap.cpp Executable file
View 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
View 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
View 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

View 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")

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

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