Skip to content

Instantly share code, notes, and snippets.

@Sam-Belliveau
Last active April 2, 2019 14:31
Show Gist options
  • Select an option

  • Save Sam-Belliveau/0f9ffd8eb4cf064355a394c18f8da738 to your computer and use it in GitHub Desktop.

Select an option

Save Sam-Belliveau/0f9ffd8eb4cf064355a394c18f8da738 to your computer and use it in GitHub Desktop.
Sorting Algorithm Visualizer
#ifndef SAMS_SUPER_COOL_SORT_ALGORITHM_VISUALIZER_2019
#define SAMS_SUPER_COOL_SORT_ALGORITHM_VISUALIZER_2019 1
#include <cstdint> // 64 bit ints
#include <algorithm> // misc tools
#include <random> // shuffling
#include <vector> // vector
// Timing
#include <chrono>
#include <thread>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Color.hpp>
class Visualizer
{
public: // Int Type Used
using IntType = std::size_t;
public: // Element Type Class
// This has special instructions to
// draw the array when items are moved
class ElementType
{
private: // Members
Visualizer* visualizer;
IntType value, timeSinceAssigned;
private: // Private Rendering Functions
void drawArray() const
{
// Don't Redraw if it is an external variable
if(this >= visualizer->begin()
&& this < visualizer->end())
visualizer->drawArray();
}
void compared() const { visualizer->incComps(); }
void assigned()
{
timeSinceAssigned = 0;
visualizer->incAssigns();
drawArray();
}
public: // Public Methods used in visualizer
ElementType() : value{0}, visualizer{nullptr} {}
ElementType(IntType val, Visualizer* vis)
: value{val}, visualizer{vis}, timeSinceAssigned{0} {};
void setVisualizer(Visualizer* vis) { visualizer = vis; }
IntType getTimeSinceAssigned() { return timeSinceAssigned++; }
IntType getValue() const { return value; }
public: // Public Methods used in sorting
ElementType(const ElementType& other)
: value{other.value}, visualizer{other.visualizer}
{ assigned(); }
ElementType& operator=(const ElementType& other)
{
value = other.value;
visualizer = other.visualizer;
assigned();
return *this;
}
// Support for casting into integers
operator IntType() { return value; }
ElementType& operator=(const IntType other)
{
value = other;
assigned();
return *this;
}
friend bool operator< (const ElementType& a, const ElementType& b)
{ a.compared(); return a.value < b.value; }
friend bool operator> (const ElementType& a, const ElementType& b) { return b < a; }
friend bool operator<=(const ElementType& a, const ElementType& b) { return !(a > b); }
friend bool operator>=(const ElementType& a, const ElementType& b) { return !(a < b); }
friend bool operator==(const ElementType& a, const ElementType& b) { return a.value == b.value; }
friend bool operator!=(const ElementType& a, const ElementType& b) { return !(a == b); }
};
private: // Internal Usage
// Used To Wait Certain Amounts
using Clock = std::chrono::steady_clock;
using DurationType = std::chrono::duration<IntType, std::milli>;
using TimePoint = std::chrono::time_point<Clock>;
// Used To Scale Bars to their Size
constexpr static IntType WindowSize = 512;
float ScaleToWindowSize(float in)
{ return (in * float(WindowSize)) / float(testArray.size()); }
public:
Visualizer() : Visualizer(0) {}
Visualizer(IntType size)
{
sf::ContextSettings settings;
settings.antialiasingLevel = 16;
window.create(
sf::VideoMode(WindowSize, WindowSize),
"Sorting Visualizer",
sf::Style::Default,
settings
);
comps = 0; assigns = 0;
setWaitMS(0); setSize(size);
}
~Visualizer()
{
while (window.isOpen())
{
checkSFMLEvents();
drawArray();
}
}
void checkSFMLEvents()
{
sf::Event event;
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
}
// Draws Bar Graph
void drawArray()
{
if(window.isOpen())
{
checkSFMLEvents();
if(!setup)
{
TimePoint currentTime = Clock::now();
window.clear(sf::Color::Black);
for(IntType i = 0; i < testArray.size(); ++i)
{
sf::RectangleShape bar(
sf::Vector2f(
ScaleToWindowSize(1),
ScaleToWindowSize(testArray[i].getValue())
)
);
bar.setPosition(
ScaleToWindowSize(i),
ScaleToWindowSize(testArray.size() - testArray[i].getValue())
);
// Make Bar More Red If Just Moved
IntType assigned = testArray[i].getTimeSinceAssigned() * 12;
assigned = std::min(assigned, IntType(255));
bar.setFillColor(sf::Color(255, assigned, assigned));
window.draw(bar);
}
window.display();
// Waits certain amount of time,
// taking rendering into account
std::this_thread::sleep_until(currentTime + waitMS);
}
}
}
public: // Different Setups For The Array
void sorted()
{
setup = true;
for(IntType i = 0; i < testArray.size(); ++i)
{ testArray[i] = ElementType(i, this); }
comps = 0;
assigns = 0;
setup = false;
}
void reversed()
{
setup = true;
for(IntType i = 0; i < testArray.size(); ++i)
{ testArray[i] = ElementType(testArray.size() - i - 1, this); }
comps = 0;
assigns = 0;
setup = false;
}
void randomize(IntType seed = 0x3243F6A8885A308D)
{
sorted();
setup = true;
std::mt19937_64 random(seed);
std::shuffle(testArray.begin(), testArray.end(), random);
comps = 0;
assigns = 0;
setup = false;
}
void almostsorted(IntType seed = 0x3243F6A8885A308D, IntType swapDis = 8, IntType prob = 32)
{
sorted();
setup = true;
std::mt19937_64 random(seed);
std::uniform_int_distribution<IntType> dist(0, size()/prob);
for(IntType i = swapDis; i < size(); ++i)
{
if(dist(random) == 0)
{ std::swap(testArray[i], testArray[i-swapDis]); }
}
comps = 0;
assigns = 0;
setup = false;
}
void setSize(IntType size)
{
testArray.resize(size);
randomize();
}
void setWaitMS(IntType t) { waitMS = DurationType(t); }
IntType getWaitMS() { return waitMS.count(); }
public: // Element Type uses this to create tally
void incComps() { ++comps; }
void incAssigns() { ++assigns; }
public: // Sorting Interfaces
ElementType& operator[](IntType i) { return testArray[i]; }
const ElementType& operator[](IntType i) const { return testArray[i]; }
ElementType* begin() { return &*testArray.begin(); }
const ElementType* begin() const { return &*testArray.cbegin(); }
const ElementType* cbegin() const { return &*testArray.cbegin(); }
ElementType* end() { return &*testArray.end(); }
const ElementType* end() const { return &*testArray.cend(); }
const ElementType* cend() const { return &*testArray.cend(); }
IntType size() const { return testArray.size(); }
IntType getComparisons() const { return comps; }
IntType getAssignments() const { return assigns; }
// Checks to see if array is sorted
bool isSorted() const
{
for(IntType i = 1; i < testArray.size(); ++i)
if(testArray[i].getValue() < testArray[i-1].getValue())
return false;
return true;
}
private:
sf::RenderWindow window; // Used to render things
bool setup; // Used as toggle to modify array without drawing
IntType comps, assigns; // Counts comparisons and assignments
DurationType waitMS;
using VectorType = std::vector<ElementType>;
VectorType testArray;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment