From a4460f6d9453bbd7e584937686449cef3e19f052 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Mon, 20 Aug 2018 20:34:57 -0400 Subject: Initial commit --- src/graphcoloring/levels/colorloader.cpp | 142 ++++++++++++ src/graphcoloring/levels/colorloader.hpp | 54 +++++ src/graphcoloring/levels/globalloader.cpp | 45 ++++ src/graphcoloring/levels/globalloader.hpp | 40 ++++ src/graphcoloring/levels/graphloader.cpp | 178 +++++++++++++++ src/graphcoloring/levels/graphloader.hpp | 57 +++++ src/graphcoloring/levels/paths/path.cpp | 207 ++++++++++++++++++ src/graphcoloring/levels/paths/path.hpp | 70 ++++++ src/graphcoloring/levels/pointcalculator.cpp | 48 ++++ src/graphcoloring/levels/pointcalculator.hpp | 45 ++++ src/graphcoloring/levels/rules/boundrule.cpp | 135 ++++++++++++ src/graphcoloring/levels/rules/boundrule.hpp | 55 +++++ src/graphcoloring/levels/rules/edgerule.cpp | 82 +++++++ src/graphcoloring/levels/rules/edgerule.hpp | 51 +++++ src/graphcoloring/levels/rules/rule.hpp | 37 ++++ src/graphcoloring/levels/rules/ruleloader.cpp | 92 ++++++++ src/graphcoloring/levels/rules/ruleloader.hpp | 53 +++++ src/graphcoloring/levels/rules/rules.cpp | 72 ++++++ src/graphcoloring/levels/rules/rules.hpp | 42 ++++ src/graphcoloring/levels/value.cpp | 304 ++++++++++++++++++++++++++ src/graphcoloring/levels/value.hpp | 80 +++++++ src/graphcoloring/levels/valueloader.cpp | 96 ++++++++ src/graphcoloring/levels/valueloader.hpp | 46 ++++ 23 files changed, 2031 insertions(+) create mode 100644 src/graphcoloring/levels/colorloader.cpp create mode 100644 src/graphcoloring/levels/colorloader.hpp create mode 100644 src/graphcoloring/levels/globalloader.cpp create mode 100644 src/graphcoloring/levels/globalloader.hpp create mode 100644 src/graphcoloring/levels/graphloader.cpp create mode 100644 src/graphcoloring/levels/graphloader.hpp create mode 100644 src/graphcoloring/levels/paths/path.cpp create mode 100644 src/graphcoloring/levels/paths/path.hpp create mode 100644 src/graphcoloring/levels/pointcalculator.cpp create mode 100644 src/graphcoloring/levels/pointcalculator.hpp create mode 100644 src/graphcoloring/levels/rules/boundrule.cpp create mode 100644 src/graphcoloring/levels/rules/boundrule.hpp create mode 100644 src/graphcoloring/levels/rules/edgerule.cpp create mode 100644 src/graphcoloring/levels/rules/edgerule.hpp create mode 100644 src/graphcoloring/levels/rules/rule.hpp create mode 100644 src/graphcoloring/levels/rules/ruleloader.cpp create mode 100644 src/graphcoloring/levels/rules/ruleloader.hpp create mode 100644 src/graphcoloring/levels/rules/rules.cpp create mode 100644 src/graphcoloring/levels/rules/rules.hpp create mode 100644 src/graphcoloring/levels/value.cpp create mode 100644 src/graphcoloring/levels/value.hpp create mode 100644 src/graphcoloring/levels/valueloader.cpp create mode 100644 src/graphcoloring/levels/valueloader.hpp (limited to 'src/graphcoloring/levels') diff --git a/src/graphcoloring/levels/colorloader.cpp b/src/graphcoloring/levels/colorloader.cpp new file mode 100644 index 0000000..a580333 --- /dev/null +++ b/src/graphcoloring/levels/colorloader.cpp @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "colorloader.hpp" + +#include "utils/errors.hpp" +#include "../level.hpp" +#include "../graphcoloring.hpp" + +namespace graphcoloring { + +ColorLoader::ColorLoader() +{ +} + +void ColorLoader::LoadDocument(const pugi::xml_document& document) +{ + Level::colors.clear(); + pugi::xml_node colors_node = document.child("colors"); + for (pugi::xml_node color_node : colors_node.children("color")) + { + std::string name = color_node.attribute("name").value(); + gui::Color color = + gui::colors::FromAttribute(color_node.attribute("color")); + int vertex_points = color_node.attribute("vertex-points").as_int(0); + int edge_points = color_node.attribute("edge-points").as_int(0); + color_names[name] = color; + vertex_color_points[color] = vertex_points; + edge_color_points[color] = edge_points; + Level::colors.push_back(color); + } +} + +gui::Color ColorLoader::GetColorByName(std::string name) const +{ + if (color_names.count(name) == 0) + utils::errors::Die("Could not find color: " + name); + return color_names.at(name); +} + +gui::Color ColorLoader::GetColorFromAttribute(pugi::xml_attribute attr) const +{ + if (attr.empty()) + return Level::colors[0]; + else + return GetColorByName(attr.value()); +} + +std::string ColorLoader::GetColorName(gui::Color color) const +{ + for (std::pair color_name : color_names) + if (color_name.second == color) + return color_name.first; + utils::errors::Die("Could not find color."); + return ""; +} + +int ColorLoader::GetVertexPoints(gui::Color color) const +{ + if (vertex_color_points.count(color) == 0) + utils::errors::Die("Could not find color."); + return vertex_color_points.at(color); +} + +int ColorLoader::GetEdgePoints(gui::Color color) const +{ + if (edge_color_points.count(color) == 0) + utils::errors::Die("Could not find color."); + return edge_color_points.at(color); +} + +void ColorLoader::RenderColorPoints(gui::Window* window) const +{ + window->SetDrawColor(GraphColoring::BACKGROUND_COLOR); + window->Clear(); + int x = 10, y = 10; + const int w = COLOR_POINTS_COLUMN_WIDTH, h = Vertex::VERTEX_RADIUS * 2; + for (gui::Color color : Level::colors) + { + if (edge_color_points.at(color) == 0) continue; + RenderEdgeColorPoints(window, color, x, y); + y += h + 10; + if (y > window->GetHeight()-h-10) + { + y = 10; + x += w + 10; + } + } + for (gui::Color color : Level::colors) + { + if (vertex_color_points.at(color) == 0) continue; + RenderVertexColorPoints(window, color, x, y); + y += h + 10; + if (y > window->GetHeight()-h-10) + { + y = 10; + x += w + 10; + } + } + +} + +void ColorLoader::RenderEdgeColorPoints(gui::Window* window, gui::Color color, + int x, int y) const +{ + const int w = COLOR_POINTS_COLUMN_WIDTH, h = Vertex::VERTEX_RADIUS*2; + window->SetDrawColor(rules::RenderColor(color)); + window->DrawLine(x, y+h/2, x+w/4, y+h/2); + window->SetTextSize(48); + window->DrawText(std::to_string(GetEdgePoints(color)), + gui::Position(x+w, y), gui::Alignment::RIGHT, gui::Alignment::TOP); +} + +void ColorLoader::RenderVertexColorPoints(gui::Window* window, gui::Color color, + int x, int y) const +{ + const int w = COLOR_POINTS_COLUMN_WIDTH, r = Vertex::VERTEX_RADIUS; + window->SetDrawColor(rules::RenderColor(color)); + window->DrawCircle(x+r, y+r, r, false); + window->SetTextSize(48); + window->DrawText(std::to_string(GetVertexPoints(color)), + gui::Position(x+w, y+r), gui::Alignment::RIGHT, gui::Alignment::CENTER); +} + + + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/colorloader.hpp b/src/graphcoloring/levels/colorloader.hpp new file mode 100644 index 0000000..c5f52cc --- /dev/null +++ b/src/graphcoloring/levels/colorloader.hpp @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_COLORLOADER_H_ +#define GRAPHCOLORING_LEVELS_COLORLOADER_H_ + +#include +#include + +#include "gui/window.hpp" +#include "pugi/pugixml.hpp" + +namespace graphcoloring { + +class ColorLoader { +public: + ColorLoader(); + virtual ~ColorLoader(){} + void LoadDocument(const pugi::xml_document& document); + gui::Color GetColorByName(std::string name) const; + gui::Color GetColorFromAttribute(pugi::xml_attribute attr) const; + std::string GetColorName(gui::Color color) const; + int GetVertexPoints(gui::Color color) const; + int GetEdgePoints(gui::Color color) const; + void RenderColorPoints(gui::Window* window) const; + std::map color_names; + std::map vertex_color_points; + std::map edge_color_points; +private: + static constexpr int COLOR_POINTS_COLUMN_WIDTH = 200; + void RenderVertexColorPoints(gui::Window* window, gui::Color color, + int x, int y) const; + void RenderEdgeColorPoints(gui::Window* window, gui::Color color, + int x, int y) const; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_COLORLOADER_H_ diff --git a/src/graphcoloring/levels/globalloader.cpp b/src/graphcoloring/levels/globalloader.cpp new file mode 100644 index 0000000..05b8cda --- /dev/null +++ b/src/graphcoloring/levels/globalloader.cpp @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "globalloader.hpp" + +namespace graphcoloring { + +GlobalLoader::GlobalLoader() +{ +} + +void GlobalLoader::LoadDocument(const pugi::xml_document& document) +{ + vertex_protections = + document.child("global-vertex-protections").attribute("protect").value(); + edge_protections = + document.child("global-edge-protections").attribute("protect").value(); +} + +bool GlobalLoader::IsVertexProtected(char protection) const +{ + return vertex_protections.find(protection) != std::string::npos; +} + +bool GlobalLoader::IsEdgeProtected(char protection) const +{ + return edge_protections.find(protection) != std::string::npos; +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/globalloader.hpp b/src/graphcoloring/levels/globalloader.hpp new file mode 100644 index 0000000..7a0b739 --- /dev/null +++ b/src/graphcoloring/levels/globalloader.hpp @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_GLOBALLOADER_H_ +#define GRAPHCOLORING_LEVELS_GLOBALLOADER_H_ + +#include "pugi/pugixml.hpp" + +namespace graphcoloring { + +class GlobalLoader { +public: + GlobalLoader(); + virtual ~GlobalLoader() {} + void LoadDocument(const pugi::xml_document& document); + bool IsVertexProtected(char protection) const; + bool IsEdgeProtected(char protection) const; +private: + std::string vertex_protections; + std::string edge_protections; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_GLOBALLOADER_H_ diff --git a/src/graphcoloring/levels/graphloader.cpp b/src/graphcoloring/levels/graphloader.cpp new file mode 100644 index 0000000..9b8b4b4 --- /dev/null +++ b/src/graphcoloring/levels/graphloader.cpp @@ -0,0 +1,178 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "graphloader.hpp" + +#include + +#include "utils/errors.hpp" +#include "../level.hpp" +#include "../graphcoloring.hpp" + +namespace graphcoloring { + +GraphLoader::GraphLoader(const ColorLoader& color_loader_, + const GlobalLoader& global_loader_) + : color_loader(color_loader_), global_loader(global_loader_) +{} + +void GraphLoader::LoadDocument(const pugi::xml_document& document, Graph& graph) +{ + pugi::xml_node graph_node = document.child("graph"); + for (pugi::xml_node vertex_node : graph_node.children("vertex")) + ReadVertex(vertex_node, graph); + for (pugi::xml_node edge_node : graph_node.children("edge")) + ReadEdge(edge_node, graph); +} + +bool GraphLoader::IsVertexProtected(std::string protections, char protection) + const +{ + bool is_protected = protections.find(protection) != std::string::npos; + if (global_loader.IsVertexProtected(protection)) + is_protected = true; + return is_protected; +} +bool GraphLoader::IsEdgeProtected(std::string protections, char protection) + const +{ + bool is_protected = protections.find(protection) != std::string::npos; + if (global_loader.IsEdgeProtected(protection)) + is_protected = true; + return is_protected; +} + +void GraphLoader::ReadVertex(pugi::xml_node vertex_node, Graph& graph) +{ + int x = vertex_node.attribute("x").as_int(); + int y = vertex_node.attribute("y").as_int(); + + int v_id = graph.AddVertex(x, y); + Vertex& v = graph.GetVertexByID(v_id); + + if (!vertex_node.attribute("origin").empty()) + { + v.is_delete_protected = true; + graph.AddOrigin(v_id); + } + + + + if (!vertex_node.attribute("id").empty()) + { + vertex_ids[vertex_node.attribute("id").value()] = v.id; + } + + gui::Color color + = color_loader.GetColorFromAttribute(vertex_node.attribute("color")); + v.ChangeColor(color); + // NOTE: This next line does handle the case where there is no protect + // specified; pugixml will default to "". + std::string protections = vertex_node.attribute("protect").value(); + v.is_color_protected = IsVertexProtected(protections, PROTECT_COLOR); + v.is_delete_protected = IsVertexProtected(protections, PROTECT_DELETE); + v.is_edge_protected = IsVertexProtected(protections, PROTECT_EDGE); +} + +void GraphLoader::ReadEdge(pugi::xml_node edge_node, Graph& graph) +{ + std::string v1_name = edge_node.attribute("v1").value(); + std::string v2_name = edge_node.attribute("v2").value(); + + int v1 = GetVertexByName(v1_name); + int v2 = GetVertexByName(v2_name); + if (v1 == -1) + utils::errors::Die("There is no vertex named " + v1_name); + if (v2 == -1) + utils::errors::Die("There is no vertex named " + v2_name); + + int e_id = graph.AddEdge(v1, v2); + Edge& e = graph.GetEdgeByID(e_id); + if (!edge_node.attribute("id").empty()) + { + edge_ids[edge_node.attribute("id").value()] = e.id; + } + gui::Color color + = color_loader.GetColorFromAttribute(edge_node.attribute("color")); + e.ChangeColor(color); + + std::string protections = edge_node.attribute("protect").value(); + e.is_color_protected = IsEdgeProtected(protections, PROTECT_COLOR); + e.is_delete_protected = IsEdgeProtected(protections, PROTECT_DELETE); +} + +void GraphLoader::WriteVertex(const Vertex& vertex, pugi::xml_node& node) const +{ + node.set_name("vertex"); + node.append_attribute("x") = vertex.x; + node.append_attribute("y") = vertex.y; + node.append_attribute("id") = vertex.id; + node.append_attribute("color") = color_loader.GetColorName(vertex.Color()) + .c_str(); + std::stringstream protections; + if (vertex.is_color_protected) protections << PROTECT_COLOR; + if (vertex.is_delete_protected) protections << PROTECT_DELETE; + if (vertex.is_edge_protected) protections << PROTECT_EDGE; + node.append_attribute("protect") = protections.str().c_str(); +} + +void GraphLoader::WriteEdge(const Edge& edge, pugi::xml_node& node) const +{ + node.set_name("edge"); + node.append_attribute("v1") = edge.from.id; + node.append_attribute("v2") = edge.to.id; + node.append_attribute("id") = edge.id; + node.append_attribute("color") = color_loader.GetColorName(edge.Color()) + .c_str(); + std::stringstream protections; + if (edge.is_color_protected) protections << PROTECT_COLOR; + if (edge.is_delete_protected) protections << PROTECT_DELETE; + node.append_attribute("protect") = protections.str().c_str(); +} + +void GraphLoader::WriteGraph(const Graph& graph, pugi::xml_node& node) const +{ + for (const Vertex* v : graph.vertices) + { + pugi::xml_node vertex_node = node.append_child("vertex"); + WriteVertex(*v, vertex_node); + } + for (const Edge* e : graph.edges) + { + pugi::xml_node edge_node = node.append_child("edge"); + WriteEdge(*e, edge_node); + } +} + +int GraphLoader::GetVertexByName(const std::string& name) const +{ + if (vertex_ids.count(name)) + return vertex_ids.at(name); + else + return -1; +} + +int GraphLoader::GetEdgeByName(const std::string& name) const +{ + if (edge_ids.count(name)) + return edge_ids.at(name); + else + return -1; +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/graphloader.hpp b/src/graphcoloring/levels/graphloader.hpp new file mode 100644 index 0000000..b17f7e8 --- /dev/null +++ b/src/graphcoloring/levels/graphloader.hpp @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_GRAPHLOADER_H_ +#define GRAPHCOLORING_LEVELS_GRAPHLOADER_H_ + +#include + +#include "../graphs/graph.hpp" +#include "pugi/pugixml.hpp" +#include "colorloader.hpp" +#include "globalloader.hpp" + +namespace graphcoloring { + +class GraphLoader { +public: + GraphLoader(const ColorLoader& color_loader, + const GlobalLoader& global_loader); + virtual ~GraphLoader() {} + // Load document into graph + void LoadDocument(const pugi::xml_document& document, Graph& graph); + // Returns id of vertex, or -1 if there is no vertex with that name. + int GetVertexByName(const std::string& name) const; + int GetEdgeByName(const std::string& name) const; + void WriteGraph(const Graph& graph, pugi::xml_node& node) const; + std::map vertex_ids; + std::map edge_ids; +private: + bool IsVertexProtected(std::string protections, char protection) const; + bool IsEdgeProtected(std::string protections, char protection) const; + void ReadVertex(pugi::xml_node vertex_node, Graph& graph); + void ReadEdge(pugi::xml_node edge_node, Graph& graph); + void WriteVertex(const Vertex& vertex, pugi::xml_node& node) const; + void WriteEdge(const Edge& edge, pugi::xml_node& node) const; + const ColorLoader& color_loader; + const GlobalLoader& global_loader; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_GRAPHLOADER_H_ diff --git a/src/graphcoloring/levels/paths/path.cpp b/src/graphcoloring/levels/paths/path.cpp new file mode 100644 index 0000000..6528b18 --- /dev/null +++ b/src/graphcoloring/levels/paths/path.cpp @@ -0,0 +1,207 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "path.hpp" + +#include +#include + +namespace graphcoloring { + +constexpr gui::Color Path::ANY_COLOR; + +Path::Path(gui::Window* window_, + Graph& graph_, const RuleLoader& rule_loader_, + const ColorLoader& color_loader_) + : window(window_), graph(graph_), rule_loader(rule_loader_), + color_loader(color_loader_) +{ + window->SetMouseupCallback([this] (gui::Window*,int,int) { + RightClick(); + }, GDK_BUTTON_SECONDARY); + window->SetKeyupCallback([this] (gui::Window*) { + ResetPath(); + }, GDK_KEY_q); +} + +void Path::LoadFromNode(pugi::xml_node node) +{ + std::string name = node.name(); + + if (name == "cycle") + type = Type::CYCLE; + else + type = Type::PATH; + + points_starting_value = node.attribute("points").as_int(0); + + for (pugi::xml_node point_node : node.children()) + { + std::string name = point_node.name(); + if (name != "edge") continue; + std::string color_str = point_node.attribute("color").value(); + gui::Color color; + if (color_str == "any") + color = ANY_COLOR; + else + color = + color_loader.GetColorFromAttribute( + point_node.attribute("color")); + color_operations[color] = LoadOperation(point_node); + } +} + +void Path::LoadFromDocument(const pugi::xml_document& document) +{ + for (pugi::xml_node node : document.children()) + { + std::string name = node.name(); + if (name != "cycle" && name != "path") continue; + LoadFromNode(node); + break; + } +} + +Path::operation_t Path::LoadOperation(pugi::xml_node node) +{ + int val = node.attribute("val").as_int(0); + std::map operations = { + {"+", [val] (int a) { return a + val; }}, + {"-", [val] (int a) { return a - val; }}, + {"*", [val] (int a) { return a * val; }}, + {"/", [val] (int a) { return a / val; }}, + {"%", [val] (int a) { return a % val; }} + }; + std::string op = node.attribute("op").value(); + return operations[op]; +} + +void Path::RightClick() +{ + if (!IsPath()) return; + if (!rule_loader.IsValid(graph)) return; + int vertex_id = graph.GetHoveringVertex(); + if (vertex_id == -1) return; + graph.Lock(); + if (last_vertex == -1) + { + last_vertex = vertex_id; + if (first_vertex == -1) + first_vertex = vertex_id; + return; + } + if (last_vertex == vertex_id) // Remove end of path + { + if (path.size() == 0) + { + ResetPath(); + return; + } + int edge_id = path.at(path.size()-1); + path.pop_back(); + last_vertex = + graph.GetEdgeByIDConst(edge_id).OtherEndpoint(last_vertex); + return; + } + if (!graph.HasEdge(last_vertex, vertex_id)) + { + return; + } + int edge_id = graph.GetEdgeByEndpointsConst(last_vertex, vertex_id).id; + if (std::find(path.begin(), path.end(), edge_id) != path.end()) // Duplicate edge + return; + path.push_back(edge_id); + last_vertex = vertex_id; +} + +void Path::ResetPath() +{ + if (!IsPath()) return; + graph.Unlock(); + path = std::vector(); + is_making_path = false; + first_vertex = -1; + last_vertex = -1; +} + +std::vector Path::GetPath() const +{ + return path; +} + +std::set Path::PathEdgeSet() const +{ + return std::set(path.begin(), path.end()); + +} + +std::set Path::PathVertexSet() const +{ + std::set vertices; + if (last_vertex != -1) + vertices.insert(last_vertex); + for (int e : path) + { + const Edge& edge = graph.GetEdgeByIDConst(e); + vertices.insert(edge.from.id); + vertices.insert(edge.to.id); + } + return vertices; +} + +int Path::LastVertex() const +{ + return last_vertex; +} + +bool Path::IsMakingPath() const +{ + return is_making_path; +} + +bool Path::IsPath() const +{ + return type != Type::NO_PATH; +} + +int Path::Points() const +{ + if (!IsPath()) return 0; + if (type == Type::CYCLE) + { + if (path.size() < 2) + return 0; + if (first_vertex != last_vertex) + return 0; + } + int points = points_starting_value; + for (int e : path) + { + const Edge& edge = graph.GetEdgeByIDConst(e); + if (color_operations.count(edge.Color()) + && color_operations.at(edge.Color())) + points = color_operations.at(edge.Color())(points); + + if (color_operations.count(ANY_COLOR) + && color_operations.at(ANY_COLOR)) + points = color_operations.at(ANY_COLOR)(points); + } + return points; +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/paths/path.hpp b/src/graphcoloring/levels/paths/path.hpp new file mode 100644 index 0000000..294b1a2 --- /dev/null +++ b/src/graphcoloring/levels/paths/path.hpp @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_PATHS_PATH_H_ +#define GRAPHCOLORING_LEVELS_PATHS_PATH_H_ + +#include "gui/window.hpp" +#include "graphcoloring/levels/rules/ruleloader.hpp" + +namespace graphcoloring { + +class Path { +public: + Path(gui::Window* window, + Graph& graph, const RuleLoader& rule_loader, + const ColorLoader& color_loader); + virtual ~Path() {} + void LoadFromDocument(const pugi::xml_document& document); + void ResetPath(); + bool IsPath() const; // Is there a path in the document? + std::vector GetPath() const; + std::set PathEdgeSet() const; + std::set PathVertexSet() const; + int LastVertex() const; // -1 if no last vertex + bool IsMakingPath() const; + int Points() const; +private: + enum class Type + { + NO_PATH, // There is no path in the document. + CYCLE, + PATH + }; + typedef std::function operation_t; + static constexpr gui::Color ANY_COLOR = 0; + void LoadFromNode(pugi::xml_node node); + void RightClick(); + operation_t LoadOperation(pugi::xml_node node); + gui::Window* window; + Graph& graph; + const RuleLoader& rule_loader; + const ColorLoader& color_loader; + Type type = Type::NO_PATH; + bool is_making_path = false; + int first_vertex = -1; + int last_vertex = -1; + std::vector path; + int points_starting_value = 0; + std::map color_operations; + +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_PATHS_PATH_H_ diff --git a/src/graphcoloring/levels/pointcalculator.cpp b/src/graphcoloring/levels/pointcalculator.cpp new file mode 100644 index 0000000..09f761e --- /dev/null +++ b/src/graphcoloring/levels/pointcalculator.cpp @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "pointcalculator.hpp" + +namespace graphcoloring { + +PointCalculator::PointCalculator(const ValueLoader& value_loader_, + const RuleLoader& rule_loader_, const ColorLoader& color_loader_, + const Path& path_) + : value_loader(value_loader_), rule_loader(rule_loader_), + color_loader(color_loader_), path(path_) +{} + +int PointCalculator::Points(const Graph& graph, bool check_if_invalid) const +{ + if (check_if_invalid) + { + bool is_valid = rule_loader.IsValid(graph); + if (!is_valid) return 0; + } + int points = value_loader.Points(graph); + for (const Vertex* v : graph.vertices) + points += color_loader.GetVertexPoints(v->Color()); + for (const Edge* e : graph.edges) + points += color_loader.GetEdgePoints(e->Color()); + + points += path.Points(); + + return points; +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/pointcalculator.hpp b/src/graphcoloring/levels/pointcalculator.hpp new file mode 100644 index 0000000..5baee6c --- /dev/null +++ b/src/graphcoloring/levels/pointcalculator.hpp @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_POINTCALCULATOR_H_ +#define GRAPHCOLORING_LEVELS_POINTCALCULATOR_H_ + +#include "valueloader.hpp" +#include "colorloader.hpp" +#include "rules/ruleloader.hpp" +#include "paths/path.hpp" + +namespace graphcoloring { + +class PointCalculator { +public: + PointCalculator(const ValueLoader& value_loader, + const RuleLoader& rule_loader, const ColorLoader& color_loader, + const Path& path); + int Points(const Graph& graph, bool check_if_invalid = true) const; + virtual ~PointCalculator() {} +private: + const ValueLoader& value_loader; + const RuleLoader& rule_loader; + const ColorLoader& color_loader; + const Path& path; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_POINTCALCULATOR_H_ 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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 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 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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 . +//////////////////////////////////////////////////////////////////////////////// + + +#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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 . +//////////////////////////////////////////////////////////////////////////////// + +#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(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(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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 edge_rules; + std::vector maximum_rules; + bool connected_rule = false; // true if the graph should be connected + std::vector> 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 . +//////////////////////////////////////////////////////////////////////////////// + +#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 . +//////////////////////////////////////////////////////////////////////////////// + + +#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_ */ diff --git a/src/graphcoloring/levels/value.cpp b/src/graphcoloring/levels/value.cpp new file mode 100644 index 0000000..f84d019 --- /dev/null +++ b/src/graphcoloring/levels/value.cpp @@ -0,0 +1,304 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "value.hpp" + +#include +#include + +#include "utils/errors.hpp" + +namespace graphcoloring { + +std::map Value::operation_table; + +Value::Value() : type(Type::NULL_TYPE) {} + +Value::Value(int val_) +{ + val = val_; + type = Type::VALUE; +} + +Value::Value(std::vector list_) +{ + list = list_; + type = Type::LIST; +} + +Value::Value(const std::string& string) +{ + FromString(string); +} + +void Value::FromString(const std::string& string) +{ + const std::map type_map = + { + {"", Type::NULL_TYPE}, + {"V", Type::NUMBER_OF_VERTICES}, + {"E", Type::NUMBER_OF_EDGES}, + {"vertices", Type::VERTICES}, + {"edges", Type::EDGES} + }; + if (type_map.count(string)) + { + type = type_map.at(string); + return; + } + try + { + val = std::stoi(string); + type = Type::VALUE; + } + catch (std::invalid_argument&) + { + // NOTE: Does not check if variable exists! This means that errors + // will only be caught when the variable is evaluated, but it allows + // out-of-order declaration. + type = Type::VARIABLE; + variable_name = string; + } +} + + +Value::Value(pugi::xml_node node) +{ + std::string name = node.name(); + if (name == "op") + { + std::string v1 = node.attribute("val1").value(); + std::string v2 = node.attribute("val2").value(); + std::string op = node.attribute("op").value(); + type = Type::OPERATION; + val1 = std::shared_ptr(new Value(v1)); + val2 = std::shared_ptr(new Value(v2)); + ReadOperation(op); + } + else if (name == "var") + { + FromString(node.attribute("val").value()); + } + else if (name == "map" || name == "fold") + { + if (name == "map") + type = Type::MAP; + else + type = Type::FOLD; + std::string op = node.attribute("op").value(); + std::string v = node.attribute("val").value(); + std::string start = node.attribute("start").value(); + if (v == "") + utils::errors::Die("No argument passed to " + name + "."); + ReadOperation(op); + val1 = std::shared_ptr(new Value(v)); + fold_start = std::shared_ptr(new Value(start)); + } + else if (name == "zip") + { + type = Type::ZIP; + std::string op = node.attribute("op").value(); + std::string v1 = node.attribute("val1").value(); + std::string v2 = node.attribute("val2").value(); + if (v1 == "" || v2 == "") + utils::errors::Die("Empty argument passed to zip."); + ReadOperation(op); + val1 = std::shared_ptr(new Value(v1)); + val2 = std::shared_ptr(new Value(v2)); + } + else + { + utils::errors::Die("Unknown tag: " + name); + } +} + +Value::operation_t Value::SimpleOperation(std::function op) +{ + return [op](const Graph&, int a, int b) { return op(a, b); }; +} + +Value::operation_t Value::SimpleBoolOperation(std::function op) +{ + return [op](const Graph&, int a, int b) { return op(a, b) ? 1 : 0; }; +} + +Value::operation_t Value::SimpleLogicOperation(std::functionop) +{ + return [op](const Graph&, int a, int b) { + return op(a != 0, b != 0) ? 1 : 0; + }; +} + +void Value::InitializeOperationTable() +{ + operation_table = { + {"min", SimpleOperation([](int a, int b)->int{return std::min(a,b);})}, + {"max", SimpleOperation([](int a, int b)->int{return std::max(a,b);})}, + {"+", SimpleOperation(std::plus())}, + {"-", SimpleOperation(std::minus())}, + {"*", SimpleOperation(std::multiplies())}, + {"/", SimpleOperation(std::divides())}, + {"%", SimpleOperation(std::modulus())}, + {"=", SimpleBoolOperation(std::equal_to())}, + {"!=", SimpleBoolOperation(std::not_equal_to())}, + {"<", SimpleBoolOperation(std::less())}, + {">", SimpleBoolOperation(std::greater())}, + {"<=", SimpleBoolOperation(std::less_equal())}, + {">=", SimpleBoolOperation(std::greater_equal())}, + {"and", SimpleLogicOperation(std::logical_and())}, + {"or", SimpleLogicOperation(std::logical_or())}, + {"not", SimpleLogicOperation([](bool a, bool b)->bool{ + return !a; // Ignore second argument. + })}, + {"v1", [](const Graph& graph, int e, int)->int { + return graph.GetEdgeByIDConst(e).from.id; + }}, + {"v2", [](const Graph& graph, int e, int)->int { + return graph.GetEdgeByIDConst(e).to.id; + }}, + {"connected", [](const Graph& graph, int v1, int v2)->int { + if (!graph.HasVertexWithID(v1) || !graph.HasVertexWithID(v2)) + return 0; + return graph.HasEdge(v1, v2) ? 1 : 0; + }}, + {"degree", [](const Graph& graph, int v, int)->int { + return graph.Degree(v); + }}, + {"vertex-color", [](const Graph& graph, int v_id, int)->int { + const Vertex& v = graph.GetVertexByIDConst(v_id); + return (int)v.Color(); + }}, + {"edge-color", [](const Graph& graph, int e_id, int)->int { + const Edge& e = graph.GetEdgeByIDConst(e_id); + return (int)e.Color(); + }} + }; +} + +void Value::ReadOperation(std::string op) +{ + if (operation_table.size() == 0) + InitializeOperationTable(); + if (operation_table.count(op)) + { + operation = operation_table[op]; + } + else + { + utils::errors::Die("Invalid operation: " + op); + } +} + +std::vector Value::EvalListOperation(const Graph& graph, + std::function lookup_variable) const +{ + switch (type) + { + case Type::VARIABLE: + return lookup_variable(variable_name) + .EvalListOperation(graph, lookup_variable); + case Type::VERTICES: + { + std::vector list; + for (const Vertex* v : graph.vertices) + { + list.push_back(v->id); + } + return list; + } + case Type::EDGES: + { + std::vector list; + for (const Edge* e : graph.edges) + { + list.push_back(e->id); + } + return list; + } + case Type::LIST: + { + std::vector out; + for (Value v : list) + out.push_back(v.Eval(graph, lookup_variable)); + return out; + } + case Type::MAP: + { + std::vector in = val1->EvalListOperation(graph, lookup_variable); + std::vector out; + for (int v : in) + out.push_back(operation(graph, v, 0)); + return out; + } + case Type::ZIP: + { + std::vector in1= val1->EvalListOperation(graph, lookup_variable); + std::vector in2= val2->EvalListOperation(graph, lookup_variable); + std::vector out; + for (int i = 0; i < (int)std::min(in1.size(),in2.size()); i++) + out.push_back(operation(graph, in1[i], in2[i])); + return out; + } + default: break; + } + std::stringstream s; + s << "Invalid list operation: " << (int)type << "."; + utils::errors::Die(s.str()); + return std::vector(); +} + +int Value::Eval(const Graph& graph, + std::function lookup_variable) const +{ + switch (type) + { + case Type::NULL_TYPE: + return 0; + case Type::VALUE: + return val; + case Type::VARIABLE: + return lookup_variable(variable_name).Eval(graph, lookup_variable); + case Type::NUMBER_OF_VERTICES: + return graph.V(); + case Type::NUMBER_OF_EDGES: + return graph.E(); + case Type::OPERATION: + assert(operation); + return operation(graph, + val1->Eval(graph, lookup_variable), + val2->Eval(graph, lookup_variable)); + case Type::FOLD: + { + assert(operation); + int x = fold_start->Eval(graph, lookup_variable); + for (const Value& v : val1->EvalListOperation(graph, lookup_variable)) + { + x = operation(graph, x, v.Eval(graph, lookup_variable)); + } + return x; + } + + default: break; + } + std::stringstream s; + s << "Invalid operation: " << (int)type << "."; + utils::errors::Die(s.str()); + return -1; +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/value.hpp b/src/graphcoloring/levels/value.hpp new file mode 100644 index 0000000..789540e --- /dev/null +++ b/src/graphcoloring/levels/value.hpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_VALUE_H_ +#define GRAPHCOLORING_LEVELS_VALUE_H_ + + +#include "pugi/pugixml.hpp" +#include "../graphs/graph.hpp" + +namespace graphcoloring { + +class Value { +public: + typedef std::function operation_t; + Value(); + Value(std::vector list); + Value(int val); + Value(const std::string& string); + Value(pugi::xml_node node); + virtual ~Value() {} + int Eval(const Graph& graph, + std::function lookup_variable) const; + static void AddNodeToVariables(pugi::xml_node node); +private: + void FromString(const std::string& string); + void ReadOperation(std::string op); + static operation_t SimpleOperation(std::function op); // For operations which don't look at the graph. + // Bool operations return bools. + static operation_t SimpleBoolOperation(std::function op); + // Logical operations take bools and return bools. + static operation_t SimpleLogicOperation(std::function op); + static void InitializeOperationTable(); + std::vector EvalListOperation(const Graph& graph, // Handles anything that returns a list. + std::function lookup_variable) const; + operation_t operation; + static std::map operation_table; + std::shared_ptr fold_start; + std::shared_ptr val1; + std::shared_ptr val2; + std::string variable_name; + int val = 0; + std::vector list; + enum class Type + { + NULL_TYPE, + VALUE, // This value represents a constant number + LIST, + VARIABLE, + NUMBER_OF_VERTICES, + NUMBER_OF_EDGES, + VERTICES, + EDGES, + OPERATION, + LIST_OPERATION, + MAP, + ZIP, + FOLD + }; + Type type; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_VALUE_H_ diff --git a/src/graphcoloring/levels/valueloader.cpp b/src/graphcoloring/levels/valueloader.cpp new file mode 100644 index 0000000..527ce99 --- /dev/null +++ b/src/graphcoloring/levels/valueloader.cpp @@ -0,0 +1,96 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#include "valueloader.hpp" + +#include "../level.hpp" +#include "utils/errors.hpp" + +namespace graphcoloring { + +ValueLoader::ValueLoader() : objective_points(-1) {} + +void ValueLoader::AddNode(pugi::xml_node node) +{ + variables[node.attribute("id").value()] = Value(node); +} + +void ValueLoader::LoadGraph(const GraphLoader& graph_loader) +{ + for (const std::pair& v_id : graph_loader.vertex_ids) + variables[v_id.first] = v_id.second; + for (const std::pair& e_id : graph_loader.edge_ids) + variables[e_id.first] = e_id.second; +} + + +void ValueLoader::LoadColors(const ColorLoader& color_loader) +{ + for (std::pair color : color_loader.color_names) + { + variables[color.first] = (int)color.second; + } +} + +void ValueLoader::LoadDocument(const pugi::xml_document& document) +{ + for (pugi::xml_node node : document.child("values").children()) + { + std::string name = node.name(); + if (name == "comment") continue; + if (name == "include") + { + pugi::xml_document doc; + std::string filename = node.attribute("file").value(); + std::string path = "assets/levels/" + filename + ".xml"; + doc.load_file(path.c_str()); + LoadDocument(doc); + } + else + { + AddNode(node); + } + } +} + + +int ValueLoader::VariableValue(const Graph& graph, + const std::string& name) const +{ + if (variables.count(name) == 0) + utils::errors::Die("Variable not found: " + name); + std::function lookup_variable + = [this] (std::string name)->Value { + if (variables.count(name) == 0) + utils::errors::Die("Variable not found: " + name); + return variables.at(name); + }; + return variables.at(name).Eval(graph, lookup_variable); +} + +int ValueLoader::Points(const Graph& graph) const +{ + return VariableValue(graph, "points"); +} + +int ValueLoader::ObjectivePoints(const Graph& graph) const +{ + return VariableValue(graph, "objective"); +} + +} // namespace graphcoloring diff --git a/src/graphcoloring/levels/valueloader.hpp b/src/graphcoloring/levels/valueloader.hpp new file mode 100644 index 0000000..0035864 --- /dev/null +++ b/src/graphcoloring/levels/valueloader.hpp @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_LEVELS_VALUELOADER_H_ +#define GRAPHCOLORING_LEVELS_VALUELOADER_H_ + +#include "value.hpp" + +#include "graphloader.hpp" + +namespace graphcoloring { + +class ValueLoader { +public: + ValueLoader(); + virtual ~ValueLoader() {} + void LoadDocument(const pugi::xml_document& document); + void LoadGraph(const GraphLoader& graph_loader); // Loads edge & vertex IDs. + void LoadColors(const ColorLoader& color_loader); // Loads color names. + int VariableValue(const Graph& graph, const std::string& name) const; + int Points(const Graph& graph) const; + int ObjectivePoints(const Graph& graph) const; +private: + void AddNode(pugi::xml_node node); + std::map variables; + int objective_points; +}; + +} // namespace graphcoloring + +#endif // GRAPHCOLORING_LEVELS_VALUELOADER_H_ -- cgit v1.2.3