From 35f0e2076ef2e1401f26ddee7c4ade762fe17ba9 Mon Sep 17 00:00:00 2001 From: Caleb Biggs <calebjbiggs@gmail.com> Date: Mon, 9 Dec 2024 14:51:03 -0800 Subject: [PATCH] Final touches for submission --- README.md | 9 ++++ build/src/controller.cpp | 88 +++++++++++++++++++++++++++++++------ build/src/controller.hpp | 6 +-- build/src/edge_widget.cpp | 1 + build/src/graph.cpp | 74 +++++++++++++++++++------------ build/src/graph.hpp | 25 ++++------- build/src/main.cpp | 33 ++------------ build/src/selected_pane.cpp | 1 - 8 files changed, 145 insertions(+), 92 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c885cc5 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +Requires Qt 5 +This was only tested on Debian 12 using the g++ compiler and qmake + +To build: +run `qmake` in this directory to generate a Makefile +run `make` to compile + +To run: +Either run `make run` or `./math453` \ No newline at end of file diff --git a/build/src/controller.cpp b/build/src/controller.cpp index dc14615..0cfe05b 100644 --- a/build/src/controller.cpp +++ b/build/src/controller.cpp @@ -1,6 +1,16 @@ #include "controller.hpp" +/** + * For most of this project I took care to simplify my code once I got + * it working, avoided repeating code, and tried to make all of my + * functions be short and easy to understand. Then I added a bunch of + * features that I put no further work into once they were functional + * because the deadline was approaching. Most of those features are + * contained in this constructor, which is very bloated and probably + * difficult to read. The program as a whole is also mostly lacking + * in comments, hopefully the function names are descriptive enough. + */ controller::controller(QWidget* window): QWidget(window){ auto new_node_button = new QPushButton("New Node", this); new_node_button->setGeometry(0, 0, 200, 60); @@ -11,18 +21,65 @@ controller::controller(QWidget* window): QWidget(window){ //TODO: Create some sort of "Mass actions" class to house these - auto debug_print_button = new QPushButton("Debug: Print Graph", this); - debug_print_button->setGeometry(0, 620, 200, 60); - QPushButton::connect(debug_print_button, &QPushButton::clicked, this, &controller::debug_print_graph); - - auto clear_edges_button = new QPushButton("Remove All Edges", this); - clear_edges_button->setGeometry(0, 680, 200, 60); + QLabel* mass_actions = new QLabel("Mass Actions", this); + mass_actions->move(5, 445); + mass_actions->setAlignment(Qt::AlignLeft); + mass_actions->setAlignment(Qt::AlignVCenter); + mass_actions->setFixedSize(200, 25); + + auto clear_edges_button = new QPushButton("Clear Edges", this); + clear_edges_button->setGeometry(5, 470, 92, 25); QPushButton::connect(clear_edges_button, &QPushButton::clicked, this, &controller::rem_all_edges); - auto rem_all_nodes_button = new QPushButton("Remove All Nodes", this); - rem_all_nodes_button->setGeometry(0, 740, 200, 60); + auto rem_all_nodes_button = new QPushButton("Clear Nodes", this); + rem_all_nodes_button->setGeometry(102, 470, 93, 25); QPushButton::connect(rem_all_nodes_button, &QPushButton::clicked, this, &controller::rem_all_nodes); + auto show_degree = new QPushButton("Degrees", this); + show_degree->setGeometry(5, 500, 92, 25); + QPushButton::connect(show_degree, &QPushButton::clicked, this, [&](){ + for(auto &[k, v] : nodes){ + v->setText(QString::fromStdString(to_string(matrix.get_edges(k).size()))); + } + }); + + auto show_index = new QPushButton("Indices", this); + show_index->setGeometry(102, 500, 93, 25); + QPushButton::connect(show_index, &QPushButton::clicked, this, [&](){ + for(auto &[k, v] : nodes){ + v->setText(QString::fromStdString(to_string(k))); + } + }); + + auto min_coloring = new QPushButton("Min Coloring", this); + min_coloring->setGeometry(5, 530, 92, 25); + QPushButton::connect(min_coloring, &QPushButton::clicked, this, [&](){ + vector<tuple<const char*,const string>> colors = { + {"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}}; + auto coloring = matrix.minimal_coloring(6); + if(!coloring) return; + for(auto &[k, v] : *coloring) nodes[k]->color(get<1>(colors[v])); + }); + + k_value = new QLineEdit(this); + k_value->move(102, 530); + k_value->setFixedSize(22, 25); + k_value->setPlaceholderText("K"); + + auto k_coloring = new QPushButton("Color", this); + k_coloring->setGeometry(129, 530, 66, 25); //102 + QPushButton::connect(k_coloring, &QPushButton::clicked, this, [&](){ + vector<tuple<const char*,const string>> colors = { + {"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}}; + uint32_t k = 3; + try{ k = stol(k_value->text().toStdString()); + } catch(...){ return; } + if(k > 6) return; + auto coloring = matrix.k_color(k); + if(!coloring) return; + for(auto &[k, v] : *coloring) nodes[k]->color(get<1>(colors[v])); + }); + //TODO: Make a "graph search" class for these QLabel* graph_search = new QLabel("Graph Search", this); @@ -81,12 +138,15 @@ controller::controller(QWidget* window): QWidget(window){ }); - //Testing button - auto test_button = new QPushButton("Test Button", this); - test_button->setGeometry(0, 560, 200, 60); - QPushButton::connect(test_button, &QPushButton::clicked, this, [&](){ - - }); + //Debug buttons + auto test_button = new QPushButton("Debug: Test New Feature", this); + test_button->setGeometry(0, 680, 200, 60); + QPushButton::connect(test_button, &QPushButton::clicked, this, [&](){}); + + auto debug_print_button = new QPushButton("Debug: Print Graph", this); + debug_print_button->setGeometry(0, 740, 200, 60); + QPushButton::connect(debug_print_button, &QPushButton::clicked, this, &controller::debug_print_graph); + area = new graph_area(800, 800, this); area->move(200, 0); diff --git a/build/src/controller.hpp b/build/src/controller.hpp index f2bc59c..c150782 100644 --- a/build/src/controller.hpp +++ b/build/src/controller.hpp @@ -12,10 +12,9 @@ #include <QString> #include <QLineEdit> -#include <bits/stdc++.h> //TODO: Replace with correct imports +#include "graph.hpp" using namespace std; -#include "graph.hpp" enum Mode { REM_NODE, ADD_EDGE, REM_EDGE }; @@ -35,9 +34,10 @@ class controller: public QWidget { graph_area* area; adj_matrix matrix; Mode mode = REM_NODE; - //TODO: Put these in their own QWidget class + //TODO: Put these in their own QWidget class(es) QLineEdit* search_start; QLineEdit* search_end; + QLineEdit* k_value; public: controller(QWidget* window); diff --git a/build/src/edge_widget.cpp b/build/src/edge_widget.cpp index 41e4bf5..9b4f6b1 100644 --- a/build/src/edge_widget.cpp +++ b/build/src/edge_widget.cpp @@ -1,3 +1,4 @@ +#include <cmath> #include "controller.hpp" diff --git a/build/src/graph.cpp b/build/src/graph.cpp index 4fb6ecc..03c70fd 100644 --- a/build/src/graph.cpp +++ b/build/src/graph.cpp @@ -1,3 +1,9 @@ +#include <queue> +#include <stack> +#include <iterator> +#include <random> +#include <cmath> +#include <algorithm> #include "graph.hpp" @@ -91,6 +97,44 @@ bool adj_matrix::is_adjacent(uint32_t head, uint32_t tail){ } +bool adj_matrix::check_coloring(unordered_map<uint32_t,uint32_t> coloring){ + for(auto &[node, color] : coloring){ + for(auto adj : get_adj(node)){ + if(coloring[adj] == color) return false; + } + } + return true; +} + + +unordered_map<uint32_t,uint32_t>* adj_matrix::k_color(uint32_t k){ + auto output = new unordered_map<uint32_t,uint32_t>; + vector<uint32_t> keys; + for(auto &[k, v] : matrix) { + keys.push_back(k); + (*output)[k] = 0; + } + for(uint64_t i = 0; i < pow(k, matrix.size()); i++){ + bool carry = true; + for(uint32_t j = 0; j < keys.size() && carry; j++){ + (*output)[keys[j]] = ((*output)[keys[j]]+1)%k; + if(!((*output)[keys[j]])) carry = false; + } + if(check_coloring(*output)) return output; + } + return NULL; +} + + +unordered_map<uint32_t,uint32_t>* adj_matrix::minimal_coloring(uint32_t max){ + for(uint32_t i = 2; i <= max; i++){ + auto output = k_color(i); + if(output) return output; + } + return NULL; +} + + void adj_matrix::print_node(uint32_t node){} @@ -196,32 +240,4 @@ vector<uint32_t> Graph::IDS(uint32_t s, uint32_t e){ vector<uint32_t> path; for(int i = 1; path.size() == 0; path = DFS(s, e, i++)); return path; -} - - -/****************\ -| Grid Functions | -\****************/ - - -uint32_t Grid::get_x(uint32_t node){ return node/height; } -uint32_t Grid::get_y(uint32_t node){ return node%height; } -uint32_t Grid::get_node(uint32_t x, uint32_t y){ return (x*height)+y; } - - -Grid::Grid(uint32_t x, uint32_t y){ width = x; height = y; } - -vector<uint32_t> Grid::get_adj(uint32_t node){ - set<uint32_t> output; - uint32_t node_x = get_x(node); - uint32_t node_y = get_y(node); - - output.insert(get_node(node_x, (node_y+1)%height)); - output.insert(get_node(node_x, (node_y-1+height)%height)); - output.insert(get_node((node_x+1)%width, node_y)); - output.insert(get_node((node_x-1+width)%width, node_y)); - - return vector<uint32_t>(output.begin(), output.end()); -} - -void Grid::print_node(uint32_t node){ cout << "(" << get_x(node) << ", " << get_y(node) << ")"; } \ No newline at end of file +} \ No newline at end of file diff --git a/build/src/graph.hpp b/build/src/graph.hpp index 591ec4d..61a0737 100644 --- a/build/src/graph.hpp +++ b/build/src/graph.hpp @@ -1,5 +1,10 @@ #pragma once -#include <bits/stdc++.h> +#include <iostream> +#include <cstdint> +#include <vector> +#include <unordered_map> +#include <unordered_set> + using namespace std; @@ -18,21 +23,6 @@ public: }; -class Grid : public Graph{ -private: - uint32_t width, height; - uint32_t get_x(uint32_t node); - uint32_t get_y(uint32_t node); - uint32_t get_node(uint32_t x, uint32_t y); - - -public: - Grid(uint32_t x, uint32_t y); - virtual vector<uint32_t> get_adj(uint32_t node); - virtual void print_node(uint32_t node); -}; - - //Directed/Undirected //Weighted/Unweighted // enum graph_type { }; @@ -57,5 +47,8 @@ class adj_matrix : public Graph { uint32_t get_edge(uint32_t head, uint32_t tail); unordered_set<uint32_t> get_edges(uint32_t node_index); unordered_multiset<uint32_t> get_weights(uint32_t edge_index); + bool check_coloring(unordered_map<uint32_t,uint32_t> coloring); + unordered_map<uint32_t,uint32_t>* k_color(uint32_t k); + unordered_map<uint32_t,uint32_t>* minimal_coloring(uint32_t max); void print(); }; \ No newline at end of file diff --git a/build/src/main.cpp b/build/src/main.cpp index f996dcb..83e51ee 100644 --- a/build/src/main.cpp +++ b/build/src/main.cpp @@ -1,6 +1,9 @@ #include "controller.hpp" +//TODO: Move main into controller.cpp +//See controller.cpp for the core functionality of the program and +//graph.cpp and graph.hpp for the underlying graph structure int main(int argc, char* argv[]){ QApplication app(argc, argv); QWidget window; @@ -12,33 +15,5 @@ int main(int argc, char* argv[]){ window.show(); return app.exec(); - - - // Grid g(5, 5); - // vector<uint32_t> temp = g.BFS(0, 12); - // // for(int i = 0; i < 4; i++) cout << temp[i] << endl; - // cout << "start: "; - // g.print_node(0); - // cout << endl << "end: "; - // g.print_node(12); - // cout << endl; - // for(auto i : temp){ - // g.print_node(i); - // cout << endl; - // } - - // auto temp = g.IDS(0, 12); - // cout << "start: "; - // g.print_node(0); - // cout << endl << "end: "; - // g.print_node(12); - // cout << endl; - // for(auto i : temp){ - // g.print_node(i); - // cout << endl; - // } - return 0; -} - -// #include "main.moc" \ No newline at end of file +} \ No newline at end of file diff --git a/build/src/selected_pane.cpp b/build/src/selected_pane.cpp index 64336bf..08ec2e8 100644 --- a/build/src/selected_pane.cpp +++ b/build/src/selected_pane.cpp @@ -12,7 +12,6 @@ controller::selected_pane::selected_pane(controller* parent) : QWidget(parent){ sel_label->setFixedSize(200, 25); - //TODO: Soften colors auto colors = new vector<tuple<const char*,const string>>({ {"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}}); -- GitLab