summaryrefslogtreecommitdiff
path: root/src/graphcoloring/levels/rules
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2018-08-20 20:34:57 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2018-08-20 20:34:57 -0400
commita4460f6d9453bbd7e584937686449cef3e19f052 (patch)
tree037c208f1e20302ed048c0952ef8e3418add9c86 /src/graphcoloring/levels/rules
Initial commit0.0.0
Diffstat (limited to 'src/graphcoloring/levels/rules')
-rw-r--r--src/graphcoloring/levels/rules/boundrule.cpp135
-rw-r--r--src/graphcoloring/levels/rules/boundrule.hpp55
-rw-r--r--src/graphcoloring/levels/rules/edgerule.cpp82
-rw-r--r--src/graphcoloring/levels/rules/edgerule.hpp51
-rw-r--r--src/graphcoloring/levels/rules/rule.hpp37
-rw-r--r--src/graphcoloring/levels/rules/ruleloader.cpp92
-rw-r--r--src/graphcoloring/levels/rules/ruleloader.hpp53
-rw-r--r--src/graphcoloring/levels/rules/rules.cpp72
-rw-r--r--src/graphcoloring/levels/rules/rules.hpp42
9 files changed, 619 insertions, 0 deletions
diff --git a/src/graphcoloring/levels/rules/boundrule.cpp b/src/graphcoloring/levels/rules/boundrule.cpp
new file mode 100644
index 0000000..0aef4af
--- /dev/null
+++ b/src/graphcoloring/levels/rules/boundrule.cpp
@@ -0,0 +1,135 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#include "boundrule.hpp"
+
+#include "graphcoloring/level.hpp"
+#include "utils/errors.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+BoundRule::BoundRule(gui::Color color_, int bound_, bool bound_type_,
+ bool rule_type_)
+ : color(color_), bound(bound_), bound_type(bound_type_),
+ rule_type(rule_type_)
+{}
+
+
+BoundRule::BoundRule(pugi::xml_node node, const ColorLoader& color_loader)
+{
+ LoadFromNode(node, color_loader);
+}
+
+void BoundRule::LoadFromNode(pugi::xml_node node,
+ const ColorLoader& color_loader)
+{
+ std::string name(node.name());
+ if (name.substr(name.length()-7) == std::string("minimum"))
+ bound_type = MINIMUM;
+ else
+ bound_type = MAXIMUM;
+
+ if (name.substr(0,name.length()-8) == std::string("vertex"))
+ rule_type = VERTEX_RULE;
+ else
+ rule_type = EDGE_RULE;
+ color = ColorFromAttribute(node.attribute("color"), color_loader);
+ bound = node.attribute(bound_type == MINIMUM ? "min" : "max").as_int(0);
+}
+
+bool BoundRule::CheckAllCounts(const Graph& graph) const
+{
+ std::map<gui::Color, int> counts;
+ for (gui::Color color : Level::colors)
+ counts[color] = 0;
+ if (rule_type == VERTEX_RULE)
+ {
+ for (const Vertex* v : graph.vertices)
+ {
+ if (counts.count(v->Color()))
+ counts[v->Color()]++;
+ }
+ }
+ else
+ {
+ for (const Edge* e : graph.edges)
+ {
+ if (counts.count(e->Color()))
+ counts[e->Color()]++;
+ else
+ counts[e->Color()] = 1;
+ }
+ }
+ for (std::pair<gui::Color, int> count : counts)
+ {
+ if (bound_type == MINIMUM && count.second < bound)
+ return false;
+ if (bound_type == MAXIMUM && count.second > bound)
+ return false;
+ }
+ return true;
+}
+
+bool BoundRule::ObeysRule(const Graph& graph) const
+{
+ if (color == SAME_COLOR) // For same, check if any color is out of bounds.
+ return CheckAllCounts(graph);
+
+ int count = 0;
+ if (rule_type == VERTEX_RULE)
+ {
+ for (const Vertex* v : graph.vertices)
+ if (IsSameColor(v->Color(), color))
+ count++;
+ }
+ else
+ {
+ for (const Edge* e : graph.edges)
+ if (IsSameColor(e->Color(), color))
+ count++;
+ }
+ return bound_type == MINIMUM ? (count >= bound) : (count <= bound);
+}
+
+int BoundRule::Render(gui::Window* window, int x, int y, int width) const
+{
+ int r = Vertex::VERTEX_RADIUS;
+ window->SetDrawColor(RenderColor(color));
+ if (rule_type == VERTEX_RULE)
+ {
+ window->DrawCircle(x+r, y+r, r, false);
+ }
+ else
+ {
+ window->DrawLine(x, y+r, x+width/4, y+r);
+ }
+ window->SetTextSize(r*2);
+ window->DrawText(std::to_string(bound), gui::Position(x+width, y+r),
+ gui::Alignment::RIGHT, gui::Alignment::CENTER);
+ window->DrawText(bound_type == MAXIMUM ? ">" : "<",
+ gui::Position(x+width/2, y+r),
+ gui::Alignment::CENTER, gui::Alignment::CENTER);
+ window->SetDrawColor(0xFF0000FF);
+ window->DrawLine(x+3*width/8, y, x+5*width/8, y+2*r);
+ return r*2;
+}
+
+
+} // namespace rules
+} // namespace graphcoloring
diff --git a/src/graphcoloring/levels/rules/boundrule.hpp b/src/graphcoloring/levels/rules/boundrule.hpp
new file mode 100644
index 0000000..a1c5e09
--- /dev/null
+++ b/src/graphcoloring/levels/rules/boundrule.hpp
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GRAPHCOLORING_LEVELS_RULES_BOUNDRULE_H_
+#define GRAPHCOLORING_LEVELS_RULES_BOUNDRULE_H_
+
+#include "graphcoloring/graphs/graph.hpp"
+
+#include "rules.hpp"
+#include "rule.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+class BoundRule : public Rule {
+public:
+ BoundRule(gui::Color color = ANY_COLOR,
+ int bound = 0, bool bound_type = MAXIMUM,
+ bool rule_type = VERTEX_RULE);
+ BoundRule(pugi::xml_node node, const ColorLoader& color_loader);
+ void LoadFromNode(pugi::xml_node node, const ColorLoader& color_loader);
+ virtual ~BoundRule() {}
+ bool ObeysRule(const Graph& graph) const;
+ int Render(gui::Window* window, int x, int y, int width) const;
+private:
+ bool CheckAllCounts(const Graph& graph) const;
+ static constexpr bool EDGE_RULE = false;
+ static constexpr bool VERTEX_RULE = true;
+ static constexpr bool MINIMUM = false;
+ static constexpr bool MAXIMUM = true;
+ gui::Color color;
+ int bound;
+ bool bound_type;
+ bool rule_type;
+};
+
+} // namespace rules
+} // namespace graphcoloring
+
+#endif // GRAPHCOLORING_LEVELS_RULES_BOUNDRULE_H_
diff --git a/src/graphcoloring/levels/rules/edgerule.cpp b/src/graphcoloring/levels/rules/edgerule.cpp
new file mode 100644
index 0000000..e2a3a74
--- /dev/null
+++ b/src/graphcoloring/levels/rules/edgerule.cpp
@@ -0,0 +1,82 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#include "edgerule.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+EdgeRule::EdgeRule(gui::Color vcolor1, gui::Color vcolor2, gui::Color ecolor)
+ : vertex_color1(vcolor1), vertex_color2(vcolor2), edge_color(ecolor)
+{}
+
+EdgeRule::EdgeRule(pugi::xml_node node, const ColorLoader& color_loader)
+{
+ LoadFromNode(node, color_loader);
+}
+
+void EdgeRule::LoadFromNode(pugi::xml_node node,const ColorLoader& color_loader)
+{
+ vertex_color1 = ColorFromAttribute(node.attribute("v1"), color_loader);
+ vertex_color2 = ColorFromAttribute(node.attribute("v2"), color_loader);
+ edge_color = ColorFromAttribute(node.attribute("edge"), color_loader);
+}
+
+bool EdgeRule::ObeysRule(const Edge& edge) const
+{
+ ResetSameColor();
+ if (!IsSameColor(edge.Color(), edge_color)) return true;
+
+ gui::Color v1 = edge.from.Color();
+ gui::Color v2 = edge.to.Color();
+ bool obeys
+ = !((IsSameColor(v1,vertex_color1) && IsSameColor(v2,vertex_color2))
+ || (IsSameColor(v2,vertex_color1) && IsSameColor(v1,vertex_color2)));
+ ResetSameColor();
+ return obeys;
+}
+
+bool EdgeRule::ObeysRule(const Graph& graph) const
+{
+ for (const Edge* e : graph.edges)
+ if (!ObeysRule(*e))
+ return false;
+ return true;
+}
+
+int EdgeRule::Render(gui::Window* window, int x, int y, int width) const
+{
+ int r = Vertex::VERTEX_RADIUS;
+ // First vertex
+ window->SetDrawColor(RenderColor(vertex_color1));
+ window->DrawCircle(x+r, y+r, r, false);
+ // Edge
+ window->SetDrawColor(RenderColor(edge_color));
+ window->DrawLine(x+2*r, y+r, x+width-2*r, y+r);
+ // Second vertex
+ window->SetDrawColor(RenderColor(vertex_color2));
+ window->DrawCircle(x+width-r, y+r, r, false);
+ // Red line
+ window->SetDrawColor(0xFF0000FF);
+ window->DrawLine(x+width/2-r/2, y+r/2, x+width/2+r/2, y+3*r/2);
+ return r*2;
+
+}
+
+} // namespace rules
+} // namespace graphcoloring
diff --git a/src/graphcoloring/levels/rules/edgerule.hpp b/src/graphcoloring/levels/rules/edgerule.hpp
new file mode 100644
index 0000000..187baf7
--- /dev/null
+++ b/src/graphcoloring/levels/rules/edgerule.hpp
@@ -0,0 +1,51 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef GRAPHCOLORING_LEVELS_RULES_EDGERULE_H_
+#define GRAPHCOLORING_LEVELS_RULES_EDGERULE_H_
+
+#include "graphcoloring/graphs/graph.hpp"
+#include "rules.hpp"
+#include "rule.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+class EdgeRule : public Rule {
+public:
+ EdgeRule(gui::Color vertex_color1 = ANY_COLOR,
+ gui::Color vertex_color2 = ANY_COLOR,
+ gui::Color edge_color = ANY_COLOR);
+ EdgeRule(pugi::xml_node node, const ColorLoader& color_loader);
+ void LoadFromNode(pugi::xml_node node, const ColorLoader& color_loader);
+ bool ObeysRule(const Graph& graph) const;
+ int Render(gui::Window* window, int x, int y, int width) const;
+ virtual ~EdgeRule() {}
+private:
+ bool ObeysRule(const Edge& edge) const;
+ gui::Color vertex_color1;
+ gui::Color vertex_color2;
+ gui::Color edge_color;
+
+};
+
+} // namespace rules
+} // namespace graphcoloring
+
+#endif // GRAPHCOLORING_LEVELS_RULES_EDGERULE_H_
diff --git a/src/graphcoloring/levels/rules/rule.hpp b/src/graphcoloring/levels/rules/rule.hpp
new file mode 100644
index 0000000..5856fc0
--- /dev/null
+++ b/src/graphcoloring/levels/rules/rule.hpp
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GRAPHCOLORING_LEVELS_RULES_RULE_H_
+#define GRAPHCOLORING_LEVELS_RULES_RULE_H_
+
+#include "graphcoloring/graphs/graph.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+class Rule {
+public:
+ virtual ~Rule() {}
+ virtual bool ObeysRule(const Graph& graph) const = 0;
+ virtual int Render(gui::Window* window, int x, int y, int width) const = 0; // Returns height
+};
+
+} // namespace rules
+} // namespace graphcoloring
+
+#endif /* GRAPHCOLORING_LEVELS_RULES_RULE_H_ */
diff --git a/src/graphcoloring/levels/rules/ruleloader.cpp b/src/graphcoloring/levels/rules/ruleloader.cpp
new file mode 100644
index 0000000..e741594
--- /dev/null
+++ b/src/graphcoloring/levels/rules/ruleloader.cpp
@@ -0,0 +1,92 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#include "ruleloader.hpp"
+
+#include "graphcoloring/graphcoloring.hpp"
+
+namespace graphcoloring {
+
+RuleLoader::RuleLoader() {}
+
+void RuleLoader::LoadDocument(const pugi::xml_document& document,
+ const ColorLoader& color_loader)
+{
+ for (pugi::xml_node rule_node : document.child("rules").children())
+ {
+ std::string name = rule_node.name();
+ if (name == "connected")
+ connected_rule = true;
+ // These node methods will check the name of the node.
+ LoadEdgeRule(rule_node, color_loader);
+ LoadMaximumRule(rule_node, color_loader);
+
+ }
+}
+
+void RuleLoader::LoadEdgeRule(pugi::xml_node node,
+ const ColorLoader& color_loader)
+{
+ std::string name = node.name();
+ if (name != "edge-rule") return;
+ rules::EdgeRule rule(node, color_loader);
+ edge_rules.push_back(rule);
+ all_rules.push_back(std::make_unique<rules::EdgeRule>(rule));
+}
+
+void RuleLoader::LoadMaximumRule(pugi::xml_node node,
+ const ColorLoader& color_loader)
+{
+ std::string name = node.name();
+ if (name != "vertex-maximum" && name != "edge-maximum"
+ && name != "vertex-minimum" && name != "edge-minimum")
+ return;
+ rules::BoundRule rule(node, color_loader);
+ maximum_rules.push_back(rule);
+ all_rules.push_back(std::make_unique<rules::BoundRule>(rule));
+}
+
+
+bool RuleLoader::IsValid(const Graph& graph) const
+{
+ for (auto& rule : all_rules)
+ if (!rule->ObeysRule(graph))
+ return false;
+ if (connected_rule && !graph.IsConnected())
+ return false;
+ return true;
+}
+
+void RuleLoader::RenderRules(gui::Window* window) const
+{
+ window->SetDrawColor(GraphColoring::BACKGROUND_COLOR);
+ window->Clear();
+ int x = 10, y = 10;
+ for (auto& rule : all_rules)
+ {
+ if (y >= window->GetHeight()-2*Vertex::VERTEX_RADIUS-10)
+ {
+ y = 10;
+ x += 50 + RULE_COLUMN_WIDTH;
+ }
+ int height = rule->Render(window, x, y, RULE_COLUMN_WIDTH);
+ y += height + 10;
+ }
+}
+
+} // namespace graphcoloring
diff --git a/src/graphcoloring/levels/rules/ruleloader.hpp b/src/graphcoloring/levels/rules/ruleloader.hpp
new file mode 100644
index 0000000..8089cb5
--- /dev/null
+++ b/src/graphcoloring/levels/rules/ruleloader.hpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GRAPHCOLORING_LEVELS_RULELOADER_H_
+#define GRAPHCOLORING_LEVELS_RULELOADER_H_
+
+#include "pugi/pugixml.hpp"
+
+#include "graphcoloring/levels/colorloader.hpp"
+#include "graphcoloring/graphs/graph.hpp"
+#include "boundrule.hpp"
+#include "edgerule.hpp"
+
+namespace graphcoloring {
+
+class RuleLoader {
+public:
+ static constexpr gui::Color ANY_COLOR = 0x00000000;
+ RuleLoader();
+ virtual ~RuleLoader() {}
+ void LoadDocument(const pugi::xml_document& document,
+ const ColorLoader& color_loader);
+ bool IsValid(const Graph& graph) const; // O(Rules * Edges)
+ void RenderRules(gui::Window* window) const;
+private:
+ void LoadEdgeRule(pugi::xml_node node, const ColorLoader& color_loader);
+ void LoadMaximumRule(pugi::xml_node node, const ColorLoader& color_loader);
+ static constexpr int RULE_COLUMN_WIDTH = 200;
+ std::vector<rules::EdgeRule> edge_rules;
+ std::vector<rules::BoundRule> maximum_rules;
+ bool connected_rule = false; // true if the graph should be connected
+ std::vector<std::unique_ptr<rules::Rule>> all_rules;
+
+};
+
+} // namespace graphcoloring
+
+#endif // GRAPHCOLORING_LEVELS_RULELOADER_H_
diff --git a/src/graphcoloring/levels/rules/rules.cpp b/src/graphcoloring/levels/rules/rules.cpp
new file mode 100644
index 0000000..2b9537f
--- /dev/null
+++ b/src/graphcoloring/levels/rules/rules.cpp
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+#include "rules.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+static gui::Color same_color = ANY_COLOR;
+
+void ResetSameColor() { same_color = ANY_COLOR; }
+
+bool IsSameColor(gui::Color color1, gui::Color color2)
+{
+ if (color1 == ANY_COLOR || color2 == ANY_COLOR)
+ return true;
+
+ if (same_color == ANY_COLOR)
+ {
+ if (color1 == SAME_COLOR && color2 != SAME_COLOR)
+ {
+ same_color = color2;
+ return true;
+ }
+ if (color2 == SAME_COLOR && color1 != SAME_COLOR)
+ {
+ same_color = color1;
+ return true;
+ }
+ }
+ if (color1 == SAME_COLOR && color2 == same_color)
+ return true;
+ if (color2 == SAME_COLOR && color1 == same_color)
+ return true;
+
+ return color1 == color2;
+}
+
+gui::Color RenderColor(gui::Color color)
+{
+ if (color == ANY_COLOR)
+ return gui::colors::WHITE;
+ if (color == SAME_COLOR)
+ return 0x666666FF;
+ return color;
+}
+
+gui::Color ColorFromAttribute(pugi::xml_attribute attr,
+ const ColorLoader& color_loader)
+{
+ if (attr.empty()) return ANY_COLOR;
+ if (std::string(attr.value()) == "same") return SAME_COLOR;
+ return attr.empty() ? ANY_COLOR : color_loader.GetColorFromAttribute(attr);
+}
+
+} // namespace rules
+} // namespace graphcoloring
diff --git a/src/graphcoloring/levels/rules/rules.hpp b/src/graphcoloring/levels/rules/rules.hpp
new file mode 100644
index 0000000..2e6d83c
--- /dev/null
+++ b/src/graphcoloring/levels/rules/rules.hpp
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Leo Tenenbaum
+// This file is part of GraphColoring.
+//
+// GraphColoring is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GraphColoring is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GraphColoring. If not, see <https://www.gnu.org/licenses/>.
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef GRAPHCOLORING_LEVELS_RULES_RULES_H_
+#define GRAPHCOLORING_LEVELS_RULES_RULES_H_
+
+#include "pugi/pugixml.hpp"
+#include "../colorloader.hpp"
+
+namespace graphcoloring {
+namespace rules {
+
+constexpr gui::Color ANY_COLOR = 0;
+constexpr gui::Color SAME_COLOR = 1; // Refers to patterns like same-red-same, which can mean blue-red-blue, red-red-red, etc.
+extern void ResetSameColor(); // Forget about "same" color
+extern bool IsSameColor(gui::Color color1, gui::Color color2);
+extern gui::Color RenderColor(gui::Color color); // Turns ANY_COLOR into white.
+extern gui::Color ColorFromAttribute(pugi::xml_attribute attr,
+ const ColorLoader& color_loader); // ANY_COLOR if attribute is empty.
+
+} // namespace rules
+} // namespace graphcoloring
+
+
+
+#endif /* SRC_GRAPHCOLORING_LEVELS_RULES_RULES_HPP_ */