abg

Animated background for X11
git clone git://git.laack.co/abg.git
Log | Files | Refs | README | LICENSE

commit f4610d5adb3d3472f9c21d68f131561f516c0880
parent 004a4ea4ddfaac30a4a426d4a6d8bba0e92ddde7
Author: Andrew Laack <andrew@laack.co>
Date:   Wed, 16 Sep 2026 10:41:54 -0500

Reformatted, refactoring makefile.

Diffstat:
A.clang-format | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MMakefile | 10++++++++--
Msrc/background.cpp | 77+++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/edge.cpp | 15++++++++-------
Msrc/graph.cpp | 192++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/main.cpp | 146++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/prim.cpp | 75+++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/utils.cpp | 19++++++++++---------
Msrc/vertex.cpp | 20+++++++++++---------
Mtests/algo_test.cpp | 319+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtests/graph_test.cpp | 170+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtests/snapshot_shared.cpp | 91++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mtests/snapshot_test.cpp | 25+++++++++++++------------
Mtests/snapshot_update.cpp | 27++++++++++++++-------------
14 files changed, 959 insertions(+), 585 deletions(-)

diff --git a/.clang-format b/.clang-format @@ -0,0 +1,358 @@ +--- +Language: Cpp +AlignAfterOpenBracket: true +AccessModifierOffset: -1 +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + AlignPPAndNotPP: true + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowBreakBeforeQtProperty: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AttributeMacros: + - __capability + - absl_nonnull + - absl_nullable + - absl_nullability_unknown +BinPackArguments: true +BinPackLongBracedList: true +BinPackParameters: BinPack +BitFieldColonSpacing: Both +BracedInitializerIndentWidth: -1 +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterOpenBracketBracedList: false +BreakAfterOpenBracketFunction: false +BreakAfterOpenBracketIf: false +BreakAfterOpenBracketLoop: false +BreakAfterOpenBracketSwitch: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeCloseBracketBracedList: false +BreakBeforeCloseBracketFunction: false +BreakBeforeCloseBracketIf: false +BreakBeforeCloseBracketLoop: false +BreakBeforeCloseBracketSwitch: false +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTemplateCloser: false +BreakBeforeTernaryOperators: true +BreakBinaryOperations: Never +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: Yes +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: AlignFirstComment +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +EnumTrailingComma: Leave +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<ext/.*\.h>' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigitsInsert: 0 + BinaryMaxDigitsRemove: 0 + Decimal: 0 + DecimalMinDigitsInsert: 0 + DecimalMaxDigitsRemove: 0 + Hex: 0 + HexMinDigitsInsert: 0 + HexMaxDigitsRemove: 0 + BinaryMinDigits: 0 + DecimalMinDigits: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +NumericLiteralCase: + ExponentLetter: Leave + HexDigit: Leave + Prefix: Leave + Suffix: Leave +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +OneLineFormatOffRegex: '' +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: Always +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: + Enabled: true + IgnoreCase: false + IgnoreExtension: false +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterOperatorKeyword: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterNot: false + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBraces: Never +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/Makefile b/Makefile @@ -8,8 +8,14 @@ install: build clean: rm abg.out +# other +fmt: + clang-format -i src/*.cpp + clang-format -i tests/*.cpp +format: fmt + # snapshot update -update-snapshot: +snapshot-update: ${TCOMMAND_P} tests/snapshot_update.cpp ${TCOMMAND_S} -o snapshot_update ./snapshot_update rm snapshot_update @@ -28,4 +34,4 @@ algo-test: ./algo_tests rm algo_tests -test: snapshot-test graph-test algo-test +test: format snapshot-test graph-test algo-test diff --git a/src/background.cpp b/src/background.cpp @@ -1,60 +1,61 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> +#include <unistd.h> + #include <cstddef> #include <cstdint> #include <stdexcept> #include <string> -#include <unistd.h> #include <vector> std::vector<uint32_t> getScreenSize() { - Display *dpy; - Screen *screen; - dpy = XOpenDisplay(NULL); - int count = ScreenCount(dpy); - if (count == 0) { - throw std::runtime_error{"Unable to find screens."}; - } - screen = ScreenOfDisplay(dpy, 0); - std::vector<uint32_t> res{(uint32_t)screen->width, (uint32_t)screen->height}; - return res; + Display* dpy; + Screen* screen; + dpy = XOpenDisplay(NULL); + int count = ScreenCount(dpy); + if (count == 0) { + throw std::runtime_error{"Unable to find screens."}; + } + screen = ScreenOfDisplay(dpy, 0); + std::vector<uint32_t> res{(uint32_t)screen->width, + (uint32_t)screen->height}; + return res; } void sendToBg(std::string name) { - Display *d = XOpenDisplay(nullptr); - Window root = DefaultRootWindow(d), r, p, *kids; - uint32_t n; + Display* d = XOpenDisplay(nullptr); + Window root = DefaultRootWindow(d), r, p, *kids; + uint32_t n; - XQueryTree(d, root, &r, &p, &kids, &n); - for (unsigned i = 0; i < n; i++) { + XQueryTree(d, root, &r, &p, &kids, &n); + for (unsigned i = 0; i < n; i++) { + char* wn = nullptr; + XFetchName(d, kids[i], &wn); - char *wn = nullptr; - XFetchName(d, kids[i], &wn); + if (wn == nullptr) { + continue; + } - if (wn == nullptr) { - continue; - } - - bool hit = name == wn; - XFree(wn); + bool hit = name == wn; + XFree(wn); - if (!hit) { - continue; - } + if (!hit) { + continue; + } - XSetWindowAttributes a; + XSetWindowAttributes a; - a.override_redirect = True; - XChangeWindowAttributes(d, kids[i], CWOverrideRedirect, &a); + a.override_redirect = True; + XChangeWindowAttributes(d, kids[i], CWOverrideRedirect, &a); - // have to do unmap / map to make it bg for all tags - XUnmapWindow(d, kids[i]); - XMapWindow(d, kids[i]); + // have to do unmap / map to make it bg for all tags + XUnmapWindow(d, kids[i]); + XMapWindow(d, kids[i]); - XLowerWindow(d, kids[i]); - break; - } + XLowerWindow(d, kids[i]); + break; + } - XFree(kids); - XCloseDisplay(d); + XFree(kids); + XCloseDisplay(d); } diff --git a/src/edge.cpp b/src/edge.cpp @@ -1,4 +1,5 @@ #include "../include/edge.hpp" + #include <cstddef> #include <string> @@ -7,15 +8,15 @@ Edge::Edge(std::size_t v1, std::size_t v2, double length2, : v1Index(v1), v2Index(v2), length2(length2), identifier(identifier) {} std::string Edge::toString() const noexcept { - return "(v1: " + std::to_string(this->v1Index) + - ", v2: " + std::to_string(this->v2Index) + - +", traversed: " + std::to_string(this->traversed) + ")"; + return "(v1: " + std::to_string(this->v1Index) + + ", v2: " + std::to_string(this->v2Index) + + +", traversed: " + std::to_string(this->traversed) + ")"; } -bool Edge::operator<(const Edge &other) const { - return length2 < other.length2; +bool Edge::operator<(const Edge& other) const { + return length2 < other.length2; } -bool Edge::operator>(const Edge &other) const { - return length2 > other.length2; +bool Edge::operator>(const Edge& other) const { + return length2 > other.length2; } diff --git a/src/graph.cpp b/src/graph.cpp @@ -1,141 +1,141 @@ #include "../include/graph.hpp" -#include "../include/constants.hpp" -#include "../include/utils.hpp" -#include "../include/vertex.hpp" + +#include <raylib.h> + #include <cstddef> #include <cstdint> -#include <raylib.h> #include <stdexcept> +#include "../include/constants.hpp" +#include "../include/utils.hpp" +#include "../include/vertex.hpp" + Graph::Graph(std::size_t edgeCount, std::size_t vertCount, uint32_t xMax, uint32_t yMax) { - - if (edgeCount > 0 && vertCount <= 1) { - throw std::invalid_argument("This graph does not support self-loops."); - } - if (xMax <= 0 || yMax <= 0) { - throw std::invalid_argument("xMax and yMax must be > 0."); - } - - for (std::size_t i = 0; i < vertCount; ++i) { - Vector2 rnd = randomPosition(xMax, yMax); - Vertex v{rnd, VERTEX_RENDER_SIZE}; - this->vertices.push_back(v); - } - for (std::size_t i = 0; i < edgeCount; ++i) { - std::size_t idx1 = 0; - std::size_t idx2 = 0; - // no self-edges - while (idx1 == idx2) { - idx1 = std::rand() % vertCount; - idx2 = std::rand() % vertCount; + if (edgeCount > 0 && vertCount <= 1) { + throw std::invalid_argument("This graph does not support self-loops."); + } + if (xMax <= 0 || yMax <= 0) { + throw std::invalid_argument("xMax and yMax must be > 0."); } - Edge e{idx1, idx2, - distanceSquared(vertices[idx1].position, vertices[idx2].position), - i}; - this->edges[idx1].push_back(e); - this->edges[idx2].push_back(e); - } + for (std::size_t i = 0; i < vertCount; ++i) { + Vector2 rnd = randomPosition(xMax, yMax); + Vertex v{rnd, VERTEX_RENDER_SIZE}; + this->vertices.push_back(v); + } + for (std::size_t i = 0; i < edgeCount; ++i) { + std::size_t idx1 = 0; + std::size_t idx2 = 0; + // no self-edges + while (idx1 == idx2) { + idx1 = std::rand() % vertCount; + idx2 = std::rand() % vertCount; + } + + Edge e{ + idx1, idx2, + distanceSquared(vertices[idx1].position, vertices[idx2].position), + i}; + this->edges[idx1].push_back(e); + this->edges[idx2].push_back(e); + } } std::string Graph::toString() noexcept { + std::string result = "edges: {"; - std::string result = "edges: {"; - - for (auto pair : this->edges) { - auto key = pair.first; - for (auto edge : edges[key]) { - result += edge.toString(); + for (auto pair : this->edges) { + auto key = pair.first; + for (auto edge : edges[key]) { + result += edge.toString(); + } } - } - result += "}"; + result += "}"; - result += "\nvertices: {"; + result += "\nvertices: {"; - for (auto vertex : this->vertices) { - result += vertex.toString(); - } + for (auto vertex : this->vertices) { + result += vertex.toString(); + } - result += "}"; - return result; + result += "}"; + return result; } void Graph::render() noexcept { + // yes, this will double draw because we track 0 -> 1 and 1 -> 0 + + std::vector<Edge> visited{}; + for (auto pair : this->edges) { + auto edges = this->edges[pair.first]; + for (auto edge : edges) { + std::size_t idx1 = edge.v1Index; + std::size_t idx2 = edge.v2Index; + auto v1 = vertices[idx1].position; + auto v2 = vertices[idx2].position; + if (edge.traversed) { + visited.push_back(edge); + } else { + DrawLineEx(v1, v2, EDGE_REDNER_SIZE, DARKERGRAY); + } + } + } - // yes, this will double draw because we track 0 -> 1 and 1 -> 0 - - std::vector<Edge> visited{}; - for (auto pair : this->edges) { - auto edges = this->edges[pair.first]; - for (auto edge : edges) { - std::size_t idx1 = edge.v1Index; - std::size_t idx2 = edge.v2Index; - auto v1 = vertices[idx1].position; - auto v2 = vertices[idx2].position; - if (edge.traversed) { - visited.push_back(edge); - } else { - DrawLineEx(v1, v2, EDGE_REDNER_SIZE, DARKERGRAY); - } + for (auto vertex : this->vertices) { + vertex.render(); + } + + // ensure we draw visited over unvisited for better looks + for (auto edge : visited) { + std::size_t idx1 = edge.v1Index; + std::size_t idx2 = edge.v2Index; + auto v1 = vertices[idx1].position; + auto v2 = vertices[idx2].position; + DrawLineEx(v1, v2, EDGE_REDNER_SIZE, WHITE); } - } - - for (auto vertex : this->vertices) { - vertex.render(); - } - - // ensure we draw visited over unvisited for better looks - for (auto edge : visited) { - std::size_t idx1 = edge.v1Index; - std::size_t idx2 = edge.v2Index; - auto v1 = vertices[idx1].position; - auto v2 = vertices[idx2].position; - DrawLineEx(v1, v2, EDGE_REDNER_SIZE, WHITE); - } } void Graph::traverseVertexIdx(std::size_t idx) { - this->vertices[idx].visited = true; + this->vertices[idx].visited = true; } std::vector<Edge> Graph::getEdgesOfVertexIdx(std::size_t idx) { - return this->edges[idx]; + return this->edges[idx]; } void Graph::setEdgeTraversed(Edge e) { + std::size_t source = e.v1Index; + std::size_t destination = e.v2Index; - std::size_t source = e.v1Index; - std::size_t destination = e.v2Index; - - if (source == destination) { - return; - } + if (source == destination) { + return; + } - auto &cEdges = edges[source]; + auto& cEdges = edges[source]; - for (auto &edge : cEdges) { - if (edge.v2Index == destination || edge.v1Index == destination) { - edge.traversed = true; + for (auto& edge : cEdges) { + if (edge.v2Index == destination || edge.v1Index == destination) { + edge.traversed = true; + } } - } - auto &oEdges = edges[destination]; + auto& oEdges = edges[destination]; - for (auto &edge : oEdges) { - if (edge.v2Index == source || edge.v1Index == source) { - edge.traversed = true; + for (auto& edge : oEdges) { + if (edge.v2Index == source || edge.v1Index == source) { + edge.traversed = true; + } } - } } Vertex Graph::getVertex(std::size_t idx) { - // idx can't be negative bc size_t - if (idx >= vertices.size()) { - throw std::invalid_argument("idx out of bounds for vertex list"); - } - return vertices[idx]; + // idx can't be negative bc size_t + if (idx >= vertices.size()) { + throw std::invalid_argument("idx out of bounds for vertex list"); + } + return vertices[idx]; } std::size_t Graph::getVertexCount() const noexcept { return vertices.size(); } diff --git a/src/main.cpp b/src/main.cpp @@ -1,90 +1,92 @@ -#include "../include/background.hpp" -#include "../include/constants.hpp" -#include "../include/graph.hpp" -#include "../include/prim.hpp" -#include "../vendor/argparse.hpp" +#include <raylib.h> +#include <unistd.h> + #include <cstdint> #include <cstdlib> #include <ctime> #include <iostream> #include <queue> -#include <raylib.h> -#include <unistd.h> #include <unordered_set> -int main(int argc, char **argv) { - - srand(clock()); - - // reverse semver - // software does get completed at some point, and for me that's at 1.0.0. - - argparse::ArgumentParser program("abg", "10.0.0"); - - program.add_argument("--vertices") - .help("number of vertices in the graph") - .default_value(DEFAULT_VERTEX_COUNT) - .scan<'i', std::size_t>(); - - program.add_argument("--sleep", "-s") - .help("amount of time to sleep between traversals") - .default_value(DEFAULT_SLEEP_TIME) - .scan<'g', float>(); - - // edges != total number of unique edges where uniqueness is defined by - // vertices this is because we allow multiple edges between two vertices - // (though they aren't rendered differently) we don't allow self-edges though. - - program.add_argument("--edges", "-e") - .help("number of edges in the graph") - .default_value(DEFAULT_EDGE_COUNT) - .scan<'i', std::size_t>(); - - try { - program.parse_args(argc, argv); - } catch (const std::exception &err) { - std::cerr << err.what() << std::endl; - std::cerr << program; - std::exit(1); - } +#include "../include/background.hpp" +#include "../include/constants.hpp" +#include "../include/graph.hpp" +#include "../include/prim.hpp" +#include "../vendor/argparse.hpp" - std::size_t vertexCount = program.get<std::size_t>("--vertices"); - std::size_t edgeCount = program.get<std::size_t>("--edges"); - float sleepTime = program.get<float>("--sleep"); +int main(int argc, char** argv) { + srand(clock()); - SetTraceLogLevel(LOG_ERROR); + // reverse semver + // software does get completed at some point, and for me that's at 1.0.0. - auto ss = getScreenSize(); + argparse::ArgumentParser program("abg", "10.0.0"); - uint32_t xMax = ss[0]; - uint32_t yMax = ss[1]; + program.add_argument("--vertices") + .help("number of vertices in the graph") + .default_value(DEFAULT_VERTEX_COUNT) + .scan<'i', std::size_t>(); - // would be nice to do this all in background.cpp, but raylib and x11 can't - // both be imported by the same file because of some dependency chain thing - // with Font. + program.add_argument("--sleep", "-s") + .help("amount of time to sleep between traversals") + .default_value(DEFAULT_SLEEP_TIME) + .scan<'g', float>(); - InitWindow(xMax, yMax, "abg"); - sendToBg("abg"); + // edges != total number of unique edges where uniqueness is defined by + // vertices this is because we allow multiple edges between two vertices + // (though they aren't rendered differently) we don't allow self-edges + // though. - while (!WindowShouldClose()) { + program.add_argument("--edges", "-e") + .help("number of edges in the graph") + .default_value(DEFAULT_EDGE_COUNT) + .scan<'i', std::size_t>(); - Graph g = Graph(edgeCount, vertexCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - for (auto edge : edges) { - toVisit.push(edge); + try { + program.parse_args(argc, argv); + } catch (const std::exception& err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); } - g.traverseVertexIdx(0); - visitedIndices.insert(0); - - while (!WindowShouldClose() && toVisit.size() != 0) { - BeginDrawing(); - ClearBackground(BLACK); - g.render(); - EndDrawing(); - usleep((int)(sleepTime * 1000000)); - oneStepPrim(toVisit, visitedIndices, g); + + std::size_t vertexCount = program.get<std::size_t>("--vertices"); + std::size_t edgeCount = program.get<std::size_t>("--edges"); + float sleepTime = program.get<float>("--sleep"); + + SetTraceLogLevel(LOG_ERROR); + + auto ss = getScreenSize(); + + uint32_t xMax = ss[0]; + uint32_t yMax = ss[1]; + + // would be nice to do this all in background.cpp, but raylib and x11 can't + // both be imported by the same file because of some dependency chain thing + // with Font. + + InitWindow(xMax, yMax, "abg"); + sendToBg("abg"); + + while (!WindowShouldClose()) { + Graph g = Graph(edgeCount, vertexCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> + toVisit{}; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + for (auto edge : edges) { + toVisit.push(edge); + } + g.traverseVertexIdx(0); + visitedIndices.insert(0); + + while (!WindowShouldClose() && toVisit.size() != 0) { + BeginDrawing(); + ClearBackground(BLACK); + g.render(); + EndDrawing(); + usleep((int)(sleepTime * 1000000)); + oneStepPrim(toVisit, visitedIndices, g); + } } - } } diff --git a/src/prim.cpp b/src/prim.cpp @@ -1,52 +1,55 @@ #include "../include/prim.hpp" -#include "../include/graph.hpp" -#include <cstdlib> -#include <queue> + #include <raylib.h> #include <unistd.h> + +#include <cstdlib> +#include <queue> #include <unordered_set> +#include "../include/graph.hpp" + void explore( std::size_t cIdx, - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> &toVisit, - Edge &current, Graph &g, std::unordered_set<std::size_t> &visitedIndices) { + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>>& toVisit, + Edge& current, Graph& g, std::unordered_set<std::size_t>& visitedIndices) { + visitedIndices.insert(cIdx); + g.traverseVertexIdx(cIdx); - visitedIndices.insert(cIdx); - g.traverseVertexIdx(cIdx); + g.setEdgeTraversed(current); - g.setEdgeTraversed(current); - - std::vector<Edge> edges = g.getEdgesOfVertexIdx(cIdx); - for (auto edge : edges) { - toVisit.push(edge); - } + std::vector<Edge> edges = g.getEdgesOfVertexIdx(cIdx); + for (auto edge : edges) { + toVisit.push(edge); + } } void oneStepPrim( - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> &toVisit, - std::unordered_set<std::size_t> &visitedIndices, Graph &g) { - bool found = false; - if (toVisit.size() == 0) { - return; - } - while (found == false) { + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>>& toVisit, + std::unordered_set<std::size_t>& visitedIndices, Graph& g) { + bool found = false; if (toVisit.size() == 0) { - return; + return; } - - found = true; - auto current = toVisit.top(); - toVisit.pop(); - - if (visitedIndices.find(current.v2Index) == visitedIndices.end()) { - auto cIdx = current.v2Index; - explore(cIdx, toVisit, current, g, visitedIndices); - - } else if (visitedIndices.find(current.v1Index) == visitedIndices.end()) { - auto cIdx = current.v1Index; - explore(cIdx, toVisit, current, g, visitedIndices); - } else { - found = false; + while (found == false) { + if (toVisit.size() == 0) { + return; + } + + found = true; + auto current = toVisit.top(); + toVisit.pop(); + + if (visitedIndices.find(current.v2Index) == visitedIndices.end()) { + auto cIdx = current.v2Index; + explore(cIdx, toVisit, current, g, visitedIndices); + + } else if (visitedIndices.find(current.v1Index) == + visitedIndices.end()) { + auto cIdx = current.v1Index; + explore(cIdx, toVisit, current, g, visitedIndices); + } else { + found = false; + } } - } } diff --git a/src/utils.cpp b/src/utils.cpp @@ -1,4 +1,5 @@ #include "../include/utils.hpp" + #include <cassert> #include <cstdint> #include <cstdlib> @@ -7,16 +8,16 @@ float square(float x) { return x * x; } // call srand before invocation as this is a pure function. Vector2 randomPosition(uint32_t xMax, uint32_t yMax) { - uint32_t r1 = rand() % xMax; - uint32_t r2 = rand() % yMax; - Vector2 v{(float)r1, (float)r2}; - return v; + uint32_t r1 = rand() % xMax; + uint32_t r2 = rand() % yMax; + Vector2 v{(float)r1, (float)r2}; + return v; } float distanceSquared(Vector2 v1, Vector2 v2) { - float xSquare = square(v1.x - v2.x); - float ySquare = square(v1.y - v2.y); - float result = xSquare + ySquare; - assert(result >= 0); - return result; + float xSquare = square(v1.x - v2.x); + float ySquare = square(v1.y - v2.y); + float result = xSquare + ySquare; + assert(result >= 0); + return result; } diff --git a/src/vertex.cpp b/src/vertex.cpp @@ -1,21 +1,23 @@ #include "../include/vertex.hpp" + #include <raylib.h> + #include <string> Vertex::Vertex(Vector2 position, float drawSize) : position(position), drawSize(drawSize) {} std::string Vertex::toString() { - std::string result = "(x: " + std::to_string(this->position.x) + - ", y: " + std::to_string(this->position.y) + - ", visited: " + std::to_string(this->visited) + ")"; - return result; + std::string result = "(x: " + std::to_string(this->position.x) + + ", y: " + std::to_string(this->position.y) + + ", visited: " + std::to_string(this->visited) + ")"; + return result; } void Vertex::render() { - if (visited) { - DrawCircle(position.x, position.y, drawSize, WHITE); - } else { - DrawCircle(position.x, position.y, drawSize, DARKGRAY); - } + if (visited) { + DrawCircle(position.x, position.y, drawSize, WHITE); + } else { + DrawCircle(position.x, position.y, drawSize, DARKGRAY); + } } diff --git a/tests/algo_test.cpp b/tests/algo_test.cpp @@ -1,205 +1,204 @@ -#include "../include/prim.hpp" - #include <catch2/catch_test_macros.hpp> #include <cstddef> -TEST_CASE("Small Prim algorithm", "[small prim algo]") { - std::size_t edgeCount = 1; - std::size_t vertCount = 2; - - float xMax = 5120; - float yMax = 1440; - - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - - for (auto edge : edges) { - toVisit.push(edge); - } - - g.traverseVertexIdx(0); - visitedIndices.insert(0); - - while (toVisit.size() != 0) { - oneStepPrim(toVisit, visitedIndices, g); - } - // this will be true bc 2 vertices 1 edge... - // our graph may have multi-edges. - REQUIRE(visitedIndices.size() == 2); -} +#include "../include/prim.hpp" -bool isConnected(Graph g) { +TEST_CASE("Small Prim algorithm", "[small prim algo]") { + std::size_t edgeCount = 1; + std::size_t vertCount = 2; - std::unordered_set<std::size_t> verticesFound{0}; + float xMax = 5120; + float yMax = 1440; - std::vector<std::size_t> current{}; + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - while (true) { - for (auto key : verticesFound) { - auto edges = g.getEdgesOfVertexIdx(key); - for (auto edge : edges) { - current.push_back(edge.v1Index); - current.push_back(edge.v2Index); - } - } - std::size_t len = verticesFound.size(); - for (auto idx : current) { - verticesFound.insert(idx); - } - if (len == verticesFound.size()) { - break; + for (auto edge : edges) { + toVisit.push(edge); } - } - - return verticesFound.size() == g.getVertexCount(); -} - -TEST_CASE("Large Prim algorithm", "[Large prim algo]") { - std::size_t edgeCount = 3000; - std::size_t vertCount = 1000; - - float xMax = 5120; - float yMax = 1440; - - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - do { - g = Graph(edgeCount, vertCount, xMax, yMax); - } while (!isConnected(g)); - - g.traverseVertexIdx(0); - visitedIndices.insert(0); - - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - - for (auto edge : edges) { - toVisit.push(edge); - } - - while (toVisit.size() != 0) { - oneStepPrim(toVisit, visitedIndices, g); - } + g.traverseVertexIdx(0); + visitedIndices.insert(0); - REQUIRE(visitedIndices.size() == vertCount); + while (toVisit.size() != 0) { + oneStepPrim(toVisit, visitedIndices, g); + } + // this will be true bc 2 vertices 1 edge... + // our graph may have multi-edges. + REQUIRE(visitedIndices.size() == 2); } -TEST_CASE("Medium Prim algorithm", "[Medium prim algo]") { - std::size_t edgeCount = 70; - std::size_t vertCount = 51; - - float xMax = 5120; - float yMax = 1440; - - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - - do { - g = Graph(edgeCount, vertCount, xMax, yMax); - } while (!isConnected(g)); - - g.traverseVertexIdx(0); - visitedIndices.insert(0); - - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); +bool isConnected(Graph g) { + std::unordered_set<std::size_t> verticesFound{0}; - for (auto edge : edges) { - toVisit.push(edge); - } + std::vector<std::size_t> current{}; - while (toVisit.size() != 0) { - oneStepPrim(toVisit, visitedIndices, g); - } + while (true) { + for (auto key : verticesFound) { + auto edges = g.getEdgesOfVertexIdx(key); + for (auto edge : edges) { + current.push_back(edge.v1Index); + current.push_back(edge.v2Index); + } + } + std::size_t len = verticesFound.size(); + for (auto idx : current) { + verticesFound.insert(idx); + } + if (len == verticesFound.size()) { + break; + } + } - REQUIRE(visitedIndices.size() == vertCount); + return verticesFound.size() == g.getVertexCount(); } -TEST_CASE("Staircase Prim algorithm", "[Staircase prim algo]") { - for (int i = 2; i < 30; ++i) { - for (int x = i - 1; x < 60; ++x) { - std::size_t edgeCount = x; - std::size_t vertCount = i; +TEST_CASE("Large Prim algorithm", "[Large prim algo]") { + std::size_t edgeCount = 3000; + std::size_t vertCount = 1000; - float xMax = 5120; - float yMax = 1440; + float xMax = 5120; + float yMax = 1440; - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> - toVisit{}; + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - do { + do { g = Graph(edgeCount, vertCount, xMax, yMax); - } while (!isConnected(g)); + } while (!isConnected(g)); + + g.traverseVertexIdx(0); + visitedIndices.insert(0); - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - for (auto edge : edges) { + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + + for (auto edge : edges) { toVisit.push(edge); - } - g.traverseVertexIdx(0); - visitedIndices.insert(0); + } - while (toVisit.size() != 0) { + while (toVisit.size() != 0) { oneStepPrim(toVisit, visitedIndices, g); - } - - REQUIRE(visitedIndices.size() == vertCount); } - } + + REQUIRE(visitedIndices.size() == vertCount); } -TEST_CASE("Small Prim Test", "[Small full validation]") { - for (int i = 0; i < 100; ++i) { - std::size_t edgeCount = 10; - std::size_t vertCount = 5; +TEST_CASE("Medium Prim algorithm", "[Medium prim algo]") { + std::size_t edgeCount = 70; + std::size_t vertCount = 51; float xMax = 5120; float yMax = 1440; Graph g = Graph(edgeCount, vertCount, xMax, yMax); - do { - g = Graph(edgeCount, vertCount, xMax, yMax); - } while (!isConnected(g)); - std::unordered_set<std::size_t> visitedIndices{}; std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - for (auto edge : g.getEdgesOfVertexIdx(0)) - toVisit.push(edge); + do { + g = Graph(edgeCount, vertCount, xMax, yMax); + } while (!isConnected(g)); + g.traverseVertexIdx(0); visitedIndices.insert(0); - std::unordered_set<std::size_t> vBefore = visitedIndices; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - bool havePrior = false; - Edge prior = toVisit.top(); - std::unordered_set<std::size_t> visibleAtPrior; + for (auto edge : edges) { + toVisit.push(edge); + } while (toVisit.size() != 0) { - auto current = toVisit.top(); - if (havePrior) { - bool wasPresent = visibleAtPrior.count(current.v1Index) > 0 || - visibleAtPrior.count(current.v2Index) > 0; - // anytime we use the same source node two steps in a row, the second - // weight must be smaller. - if (wasPresent) { - REQUIRE(current.length2 >= prior.length2); - } - } - - prior = current; - visibleAtPrior = visitedIndices; - havePrior = true; - oneStepPrim(toVisit, visitedIndices, g); - bool valid = vBefore.size() + 1 == visitedIndices.size() || - vBefore.size() == vertCount; - REQUIRE(valid); - vBefore = visitedIndices; + oneStepPrim(toVisit, visitedIndices, g); } + REQUIRE(visitedIndices.size() == vertCount); - } +} + +TEST_CASE("Staircase Prim algorithm", "[Staircase prim algo]") { + for (int i = 2; i < 30; ++i) { + for (int x = i - 1; x < 60; ++x) { + std::size_t edgeCount = x; + std::size_t vertCount = i; + + float xMax = 5120; + float yMax = 1440; + + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> + toVisit{}; + + do { + g = Graph(edgeCount, vertCount, xMax, yMax); + } while (!isConnected(g)); + + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + for (auto edge : edges) { + toVisit.push(edge); + } + g.traverseVertexIdx(0); + visitedIndices.insert(0); + + while (toVisit.size() != 0) { + oneStepPrim(toVisit, visitedIndices, g); + } + + REQUIRE(visitedIndices.size() == vertCount); + } + } +} + +TEST_CASE("Small Prim Test", "[Small full validation]") { + for (int i = 0; i < 100; ++i) { + std::size_t edgeCount = 10; + std::size_t vertCount = 5; + + float xMax = 5120; + float yMax = 1440; + + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + do { + g = Graph(edgeCount, vertCount, xMax, yMax); + } while (!isConnected(g)); + + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> + toVisit{}; + + for (auto edge : g.getEdgesOfVertexIdx(0)) toVisit.push(edge); + g.traverseVertexIdx(0); + visitedIndices.insert(0); + + std::unordered_set<std::size_t> vBefore = visitedIndices; + + bool havePrior = false; + Edge prior = toVisit.top(); + std::unordered_set<std::size_t> visibleAtPrior; + + while (toVisit.size() != 0) { + auto current = toVisit.top(); + if (havePrior) { + bool wasPresent = visibleAtPrior.count(current.v1Index) > 0 || + visibleAtPrior.count(current.v2Index) > 0; + // anytime we use the same source node two steps in a row, the + // second weight must be smaller. + if (wasPresent) { + REQUIRE(current.length2 >= prior.length2); + } + } + + prior = current; + visibleAtPrior = visitedIndices; + havePrior = true; + oneStepPrim(toVisit, visitedIndices, g); + bool valid = vBefore.size() + 1 == visitedIndices.size() || + vBefore.size() == vertCount; + REQUIRE(valid); + vBefore = visitedIndices; + } + REQUIRE(visitedIndices.size() == vertCount); + } } diff --git a/tests/graph_test.cpp b/tests/graph_test.cpp @@ -5,119 +5,117 @@ #include <unordered_set> TEST_CASE("Graph traversal invariants", "[graph traversal]") { - int vertCount = 10; - int edgeCount = 10; - float xMax = 10; - float yMax = 10; - auto g = Graph(edgeCount, vertCount, xMax, yMax); - for (int i = 0; i < vertCount; ++i) { - g.traverseVertexIdx(i); - } - for (int i = 0; i < vertCount; ++i) { - REQUIRE(g.getVertex(i).visited); - } - - bool error = false; - - try { - g.getVertex(vertCount + 1); - } catch (std::invalid_argument& e) { - error = true; - } - - REQUIRE(error); + int vertCount = 10; + int edgeCount = 10; + float xMax = 10; + float yMax = 10; + auto g = Graph(edgeCount, vertCount, xMax, yMax); + for (int i = 0; i < vertCount; ++i) { + g.traverseVertexIdx(i); + } + for (int i = 0; i < vertCount; ++i) { + REQUIRE(g.getVertex(i).visited); + } + + bool error = false; + + try { + g.getVertex(vertCount + 1); + } catch (std::invalid_argument& e) { + error = true; + } + + REQUIRE(error); } void createGraph(int vertCount, int edgeCount) { - auto g = Graph(edgeCount, vertCount, 10, 10); + auto g = Graph(edgeCount, vertCount, 10, 10); } TEST_CASE("Graph gracefully handles stupid fucking inputs", "[graph bad inputs]") { - int vertCount = 0; - int edgeCount = 0; // some trivial and stupid graph + int vertCount = 0; + int edgeCount = 0; // some trivial and stupid graph - bool error = false; + bool error = false; - try { - createGraph(vertCount, edgeCount); - } catch (std::invalid_argument& e) { - error = true; - } - REQUIRE(!error); + try { + createGraph(vertCount, edgeCount); + } catch (std::invalid_argument& e) { + error = true; + } + REQUIRE(!error); - vertCount = 0; - edgeCount = 1; // bad + vertCount = 0; + edgeCount = 1; // bad - error = false; - try { - createGraph(vertCount, edgeCount); - } catch (std::invalid_argument& e) { - error = true; - } + error = false; + try { + createGraph(vertCount, edgeCount); + } catch (std::invalid_argument& e) { + error = true; + } - REQUIRE(error); + REQUIRE(error); } TEST_CASE("Graph respects max x and max y values", "[graph max values]") { - int vertCount = 10; - int edgeCount = 10; - - for (int z = 2; z < 100; ++z) { - - float xMax = 0; - float yMax = 0; - - while (xMax == 0 || yMax == 0) { - xMax = rand() % z; - yMax = rand() % z; + int vertCount = 10; + int edgeCount = 10; + + for (int z = 2; z < 100; ++z) { + float xMax = 0; + float yMax = 0; + + while (xMax == 0 || yMax == 0) { + xMax = rand() % z; + yMax = rand() % z; + } + + auto g = Graph(edgeCount, vertCount, xMax, yMax); + + for (int i = 0; i < vertCount; ++i) { + REQUIRE(g.getVertex(i).position.x <= xMax); + } + for (int i = 0; i < vertCount; ++i) { + REQUIRE(g.getVertex(i).position.y <= yMax); + } } - - auto g = Graph(edgeCount, vertCount, xMax, yMax); + auto g = Graph(edgeCount, vertCount, UINT32_MAX, UINT32_MAX); for (int i = 0; i < vertCount; ++i) { - REQUIRE(g.getVertex(i).position.x <= xMax); + REQUIRE(g.getVertex(i).position.x <= UINT32_MAX); } for (int i = 0; i < vertCount; ++i) { - REQUIRE(g.getVertex(i).position.y <= yMax); + REQUIRE(g.getVertex(i).position.y <= UINT32_MAX); } - } - auto g = Graph(edgeCount, vertCount, UINT32_MAX, UINT32_MAX); - - for (int i = 0; i < vertCount; ++i) { - REQUIRE(g.getVertex(i).position.x <= UINT32_MAX); - } - for (int i = 0; i < vertCount; ++i) { - REQUIRE(g.getVertex(i).position.y <= UINT32_MAX); - } } std::size_t countEdges(Graph g) { - std::size_t vertexCount = g.getVertexCount(); - std::unordered_set<std::size_t> unique{}; - - for (std::size_t i = 0; i < vertexCount; ++i) { - auto edges = g.getEdgesOfVertexIdx(i); - for (auto edge : edges) { - unique.insert(edge.identifier); + std::size_t vertexCount = g.getVertexCount(); + std::unordered_set<std::size_t> unique{}; + + for (std::size_t i = 0; i < vertexCount; ++i) { + auto edges = g.getEdgesOfVertexIdx(i); + for (auto edge : edges) { + unique.insert(edge.identifier); + } } - } - return unique.size(); + return unique.size(); } TEST_CASE("Graph vertex and edge counts", "[graph counts]") { - - for (int i = 2; i < 100; ++i) { - for (int x = 1; x < 10; ++x) { - std::size_t vertCount = i; - std::size_t edgeCount = x; - float xMax = 10; - float yMax = 10; - - auto g = Graph(edgeCount, vertCount, xMax, yMax); - - REQUIRE(g.getVertexCount() == vertCount); - REQUIRE(countEdges(g) == edgeCount); + for (int i = 2; i < 100; ++i) { + for (int x = 1; x < 10; ++x) { + std::size_t vertCount = i; + std::size_t edgeCount = x; + float xMax = 10; + float yMax = 10; + + auto g = Graph(edgeCount, vertCount, xMax, yMax); + + REQUIRE(g.getVertexCount() == vertCount); + REQUIRE(countEdges(g) == edgeCount); + } } - } } diff --git a/tests/snapshot_shared.cpp b/tests/snapshot_shared.cpp @@ -1,69 +1,70 @@ -#include "../include/graph.hpp" -#include "../include/prim.hpp" #include <catch2/catch_test_macros.hpp> #include <queue> #include <unordered_set> +#include "../include/graph.hpp" +#include "../include/prim.hpp" + Graph basicGraphSerialization() { - srand(42); - int vertCount = 10; - int edgeCount = 10; - float xMax = 10; - float yMax = 10; - auto g = Graph(edgeCount, vertCount, xMax, yMax); - return g; + srand(42); + int vertCount = 10; + int edgeCount = 10; + float xMax = 10; + float yMax = 10; + auto g = Graph(edgeCount, vertCount, xMax, yMax); + return g; } Graph fullTraversalSerialization() { - srand(42); - std::size_t edgeCount = 1; - std::size_t vertCount = 2; + srand(42); + std::size_t edgeCount = 1; + std::size_t vertCount = 2; - float xMax = 5120; - float yMax = 1440; + float xMax = 5120; + float yMax = 1440; - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - for (auto edge : edges) { - toVisit.push(edge); - } + for (auto edge : edges) { + toVisit.push(edge); + } - g.traverseVertexIdx(0); - visitedIndices.insert(0); + g.traverseVertexIdx(0); + visitedIndices.insert(0); - while (toVisit.size() != 0) { - oneStepPrim(toVisit, visitedIndices, g); - } + while (toVisit.size() != 0) { + oneStepPrim(toVisit, visitedIndices, g); + } - return g; + return g; } Graph fullTraversalLargerSerialization() { - srand(42); - std::size_t edgeCount = 25; - std::size_t vertCount = 15; + srand(42); + std::size_t edgeCount = 25; + std::size_t vertCount = 15; - float xMax = 5120; - float yMax = 1440; + float xMax = 5120; + float yMax = 1440; - Graph g = Graph(edgeCount, vertCount, xMax, yMax); - std::unordered_set<std::size_t> visitedIndices{}; - std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; - std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + Graph g = Graph(edgeCount, vertCount, xMax, yMax); + std::unordered_set<std::size_t> visitedIndices{}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit{}; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); - for (auto edge : edges) { - toVisit.push(edge); - } + for (auto edge : edges) { + toVisit.push(edge); + } - g.traverseVertexIdx(0); - visitedIndices.insert(0); + g.traverseVertexIdx(0); + visitedIndices.insert(0); - while (toVisit.size() != 0) { - oneStepPrim(toVisit, visitedIndices, g); - } + while (toVisit.size() != 0) { + oneStepPrim(toVisit, visitedIndices, g); + } - return g; + return g; } diff --git a/tests/snapshot_test.cpp b/tests/snapshot_test.cpp @@ -1,31 +1,32 @@ -#include "../include/graph.hpp" -#include "snapshot_shared.cpp" #include <catch2/catch_test_macros.hpp> #include <fstream> #include <iostream> #include <sstream> +#include "../include/graph.hpp" +#include "snapshot_shared.cpp" + std::string readFileToString(std::string filename) { - auto in = std::ifstream("tests/snapshot/" + filename + ".out"); - std::ostringstream sstr; - sstr << in.rdbuf(); - return sstr.str(); + auto in = std::ifstream("tests/snapshot/" + filename + ".out"); + std::ostringstream sstr; + sstr << in.rdbuf(); + return sstr.str(); } TEST_CASE("Basic graph serialization snapshot", "[basic graph serialization snapshot]") { - Graph g = basicGraphSerialization(); - REQUIRE(readFileToString("basicGraph") == g.toString()); + Graph g = basicGraphSerialization(); + REQUIRE(readFileToString("basicGraph") == g.toString()); } TEST_CASE("Traversed graph serialization snapshot", "[traversed graph serialization snapshot]") { - Graph g = fullTraversalSerialization(); - REQUIRE(readFileToString("traversedGraph") == g.toString()); + Graph g = fullTraversalSerialization(); + REQUIRE(readFileToString("traversedGraph") == g.toString()); } TEST_CASE("Traversed graph serialization snapshot larger", "[traversed graph serialization snapshot larger]") { - Graph g = fullTraversalLargerSerialization(); - REQUIRE(readFileToString("traversedLargerGraph") == g.toString()); + Graph g = fullTraversalLargerSerialization(); + REQUIRE(readFileToString("traversedLargerGraph") == g.toString()); } diff --git a/tests/snapshot_update.cpp b/tests/snapshot_update.cpp @@ -1,21 +1,22 @@ -#include "../include/graph.hpp" -#include "snapshot_shared.cpp" #include <filesystem> #include <fstream> +#include "../include/graph.hpp" +#include "snapshot_shared.cpp" + void snapshotGraph(std::string testName, Graph g) { - std::filesystem::path path{"tests/snapshot"}; - path /= testName + ".out"; - std::filesystem::create_directories(path.parent_path()); - std::ofstream ofs(path); - ofs << g.toString(); + std::filesystem::path path{"tests/snapshot"}; + path /= testName + ".out"; + std::filesystem::create_directories(path.parent_path()); + std::ofstream ofs(path); + ofs << g.toString(); } int main() { - Graph g1 = basicGraphSerialization(); - snapshotGraph("basicGraph", g1); - Graph g2 = fullTraversalSerialization(); - snapshotGraph("traversedGraph", g2); - Graph g3 = fullTraversalLargerSerialization(); - snapshotGraph("traversedLargerGraph", g3); + Graph g1 = basicGraphSerialization(); + snapshotGraph("basicGraph", g1); + Graph g2 = fullTraversalSerialization(); + snapshotGraph("traversedGraph", g2); + Graph g3 = fullTraversalLargerSerialization(); + snapshotGraph("traversedLargerGraph", g3); }