working version
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 24 Feb 2019 04:27:09 +0000 (22:27 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 24 Feb 2019 04:27:09 +0000 (22:27 -0600)
lua/graph.lua
main.lua
modules/graph_algorithms.c
modules/graph_standard.c

index 7806791835476a4aca8e7d3272b37643821125e2..1e406f4f75593c77209426f434d11bca354157a5 100644 (file)
@@ -25,6 +25,8 @@ function Graph:addNode(x, y)
 end
 
 function Graph:deleteNode(nodeID)
+       if nodeID == nil then return end
+
        assert(type(nodeID) == "number")
        local g = self.graph
 
index a4496037a0751f9c8623b926d062cfc5c7ff8e9c..fb84bafead6f61ef2fdabd238a030570294d3cb5 100644 (file)
--- a/main.lua
+++ b/main.lua
@@ -6,8 +6,11 @@ local graph = nil
 local regions = nil
 local graph_region = nil
 
+local GRAPH_FONT, SIDEBAR_FONT
+
 function love.load()
        GRAPH_FONT = love.graphics.setNewFont(16)
+       SIDEBAR_FONT = love.graphics.setNewFont(24)
 
        graph = Graph:new()
 
@@ -31,6 +34,7 @@ function love.load()
                -- other properties
                selectedNode = nil;
                postDrawFunction = nil;
+               clickNodeFunction = nil;
                isMouseDown = false;
 
                update = function(self) end;
@@ -55,10 +59,15 @@ function love.load()
                                local d = (x - nx) * (x - nx) + (y - ny) * (y - ny)
 
                                if d <= 20 * 20 then
-                                       self.selectedNode = node.id
+                                       if self.clickNodeFunction == nil then
+                                               self.selectedNode = node.id
+                                       else
+                                               self.clickNodeFunction(node)
+                                       end
                                end
                        end
                end;
+
                mouseup = function(self, x, y)
                        self.isMouseDown = false
                end;
@@ -68,8 +77,9 @@ function love.load()
                                graph:setNodePos(self.selectedNode, x, y)
                        end
                end;
-               mouseenter = function(self)
-               end;
+
+               mouseenter = function(self) end;
+
                mouseleave = function(self)
                        self.isMouseDown = false
                end;
@@ -77,6 +87,91 @@ function love.load()
 
        regions:add(graph_region)
 
+       regions:add {
+               priority = 1;
+               rect = { 0, 0, 200, 600 };
+
+               buttons = {
+                       {
+                               text = "Add node",
+                               click = function()
+                                       graph:addNode(300, 300)
+                               end;
+                       };
+                       {
+                               text = "Delete node",
+                               click = function()
+                                       graph:deleteNode(graph_region.selectedNode)
+                               end;
+                       };
+                       {
+                               text = "Add arc",
+                               click = function()
+                                       local curr = graph_region.selectedNode
+                                       if curr == nil then return end
+
+                                       graph_region.clickNodeFunction = function(node)
+                                               graph:addArc(curr, node.id, 1)
+                                               graph_region.clickNodeFunction = nil
+                                       end
+                               end;
+                       };
+                       {
+                               text = "Add edge",
+                               click = function()
+                                       local curr = graph_region.selectedNode
+                                       if curr == nil then return end
+
+                                       graph_region.clickNodeFunction = function(node)
+                                               graph:addEdge(curr, node.id, 1)
+                                               graph_region.clickNodeFunction = nil
+                                       end
+                               end;
+                       };
+                       {
+                               text = "Run Dijkstras",
+                               click = function()
+                                       if graph_region.selectedNode ~= nil then
+                                               createDijskstraStepper(graph_region.selectedNode)
+                                       end
+                               end;
+                       };
+               };
+               mousePos = -1;
+
+               update = function(self) end;
+
+               draw = function(self)
+                       love.graphics.setFont(SIDEBAR_FONT)
+                       for i, button in ipairs(self.buttons) do
+                               if self.mousePos >= (i - 1) * 60 + 10 and self.mousePos <= i * 60 + 10 then
+                                       love.graphics.setColor(.4, .4, .4)
+                               else
+                                       love.graphics.setColor(.2, .2, .2)
+                               end
+                               love.graphics.rectangle("fill", 10, (i - 1) * 60 + 10, 180, 40)
+
+                               love.graphics.setColor(1, 1, 1)
+                               love.graphics.printf(button.text, 0, (i - 1) * 60 + 15, 200, "center")  
+                       end
+               end;
+
+               mousedown = function(self, x, y)
+                       for i, button in ipairs(self.buttons) do
+                               if y >= (i - 1) * 60 + 10 and y <= i * 60 + 10 then
+                                       button.click()
+                               end
+                       end
+               end;
+               mouseup = function(self, x, y) end;
+               mousemove = function(self, x, y, dx, dy)
+                       self.mousePos = y
+               end;
+               mouseenter = function(self) end;
+               mouseleave = function(self)
+                       self.mousePos = -1
+               end;
+       }
 
        -- regions:add {
        --      priority = 0;
@@ -92,11 +187,17 @@ function love.load()
        -- }
 end
 
-function createDijskstraStepper()
+local dijkstrasOpen = false
+function createDijskstraStepper(start)
+       if dijkstrasOpen then return end
+
+       dijkstrasOpen = true
        local step = -1
 
+       local isDone = false
        function updateDijkstras()
-               local dj = graph:dijkstras(0, step)
+               local dj, done = graph:dijkstras(start, step)
+               isDone = done
                graph_region.postDrawFunction = function(reg)
                        drawDijkstras(graph, dj)
                end
@@ -120,15 +221,19 @@ function createDijskstraStepper()
                mousedown = function(self, x, y)
                        if x >= 265 and x <= 295 then
                                step = step - 1
+                               isDone = false
                                if step < -1 then step = -1 end
                        elseif x >= 305 and x <= 335 then
-                               step = step + 1
+                               if not isDone then
+                                       step = step + 1
+                               end
                        end
 
                        updateDijkstras()
                        if x >= 550 then
                                regions:remove(reg_id)
                                graph_region.postDrawFunction = nil
+                               dijkstrasOpen = false
                        end
                end;
                mouseup = function(self, x, y) end;
@@ -158,41 +263,48 @@ end
 
 -- DRAWING FUNCTIONS
 
+function drawEdge(x1, y1, x2, y2, directed, weight, color)
+       love.graphics.setColor(color)
+
+       love.graphics.line(x1, y1, x2, y2)
+
+       local cx = math.lerp(x1, x2, 0.5)
+       local cy = math.lerp(y1, y2, 0.5)
+       local arrowSize = 22
+
+       if directed == 2 then
+               local alpha = math.atan2(x2 - x1, y2 - y1)
+
+               local triangle = {
+                       cx + arrowSize * math.sin(alpha + 0 * math.pi / 3), cy + arrowSize * math.cos(alpha + 0 * math.pi / 3),
+                       cx + arrowSize * math.sin(alpha + 2 * math.pi / 3), cy + arrowSize * math.cos(alpha + 2 * math.pi / 3),
+                       cx + arrowSize * math.sin(alpha + 4 * math.pi / 3), cy + arrowSize * math.cos(alpha + 4 * math.pi / 3)
+               }
+
+               love.graphics.polygon("fill", triangle)
+       elseif directed == 1 then
+               love.graphics.rectangle("fill", cx - arrowSize * .6, cy - arrowSize * .6, arrowSize * 1.2, arrowSize * 1.2)
+       end
+
+       love.graphics.setColor(1, 1, 1)
+       love.graphics.printf(tostring(weight), cx - 20, cy - 10, 40, "center")
+end
+
 local NODE_INNER_RADIUS = 17
 local NODE_OUTER_RADIUS = 20
 function drawGraph(graph, selectedNode)
        local nodes = graph:getNodes()
        local edges = graph:getEdges()
 
+       love.graphics.setFont(GRAPH_FONT)
        love.graphics.setLineWidth(4)
        for _, edge in pairs(edges) do
-               love.graphics.setColor(0, 0, 0)
                local x1 = nodes[edge.from_node].x
                local y1 = nodes[edge.from_node].y
                local x2 = nodes[edge.to_node].x
                local y2 = nodes[edge.to_node].y
 
-               love.graphics.line(x1, y1, x2, y2)
-
-               local cx = math.lerp(x1, x2, 0.5)
-               local cy = math.lerp(y1, y2, 0.5)
-               local arrowSize = 22
-
-               if edge.directed then
-                       local alpha = math.atan2(x2 - x1, y2 - y1)
-
-                       local triangle = {
-                               cx + arrowSize * math.sin(alpha + 0 * math.pi / 3), cy + arrowSize * math.cos(alpha + 0 * math.pi / 3),
-                               cx + arrowSize * math.sin(alpha + 2 * math.pi / 3), cy + arrowSize * math.cos(alpha + 2 * math.pi / 3),
-                               cx + arrowSize * math.sin(alpha + 4 * math.pi / 3), cy + arrowSize * math.cos(alpha + 4 * math.pi / 3)
-                       }
-
-                       love.graphics.polygon("fill", triangle)
-               else
-                       love.graphics.rectangle("fill", cx - arrowSize * .6, cy - arrowSize * .6, arrowSize * 1.2, arrowSize * 1.2)
-               end
-               love.graphics.setColor(1, 1, 1)
-               love.graphics.printf(tostring(edge.weight), cx - 20, cy - 10, 40, "center")
+               drawEdge(x1, y1, x2, y2, (edge.directed and 2 or 1), edge.weight, {0, 0, 0})
        end
 
        for _, node in pairs(nodes) do
@@ -210,10 +322,17 @@ end
 function drawDijkstras(graph, dijkstras)
        love.graphics.setFont(GRAPH_FONT)
 
+       if dijkstras.from >= 0 and dijkstras.to >= 0 then
+               local x1, y1 = graph:getNodePos(dijkstras.from)
+               local x2, y2 = graph:getNodePos(dijkstras.to)
+
+               drawEdge(x1, y1, x2, y2, 0, dijkstras.weight, {1, 0, 0})
+       end
+
        for _, node in ipairs(dijkstras) do
                if node.distance >= 0 then
                        local x, y = graph:getNodePos(node.id)
-                       love.graphics.setColor(0, 1, 0)
+                       love.graphics.setColor(1, 0, 0)
                        love.graphics.circle("fill", x, y, NODE_INNER_RADIUS)
 
                        love.graphics.setColor(0, 0, 0)
index fc5aa7e0595eba69486a7d8aa433c5fd483bb498..c4fae9ff176be97c7b9fc012f4bc713f3f38d495 100644 (file)
@@ -61,8 +61,9 @@ int dijkstras(lua_State *L)
                insert_dj(shortest_distance, distance_walker->node_id, -1);
                distance_walker = distance_walker->next;
        }
-       int last_from;
-       int last_to;
+       int last_from = -1;
+       int last_to = -1;
+       int last_weight;
 
        while (connected_nodes != NULL && current_iterations <= iterations)
        {
@@ -89,6 +90,7 @@ int dijkstras(lua_State *L)
                                                shortest_distance_tmp = distance_to_current_node + edge_walker->weight;
                                                from = current_node->node_id;
                                                to = edge_walker->to_id;
+                                               last_weight = edge_walker->weight;
                                        }
                                }
                                edge_walker = edge_walker->next_edge;
@@ -142,8 +144,19 @@ int dijkstras(lua_State *L)
                index++;
        }
 
+       lua_pushnumber(L, last_from);
+       lua_setfield(L, 1, "from");
+
+       lua_pushnumber(L, last_to);
+       lua_setfield(L, 1, "to");
+
+       lua_pushnumber(L, last_weight);
+       lua_setfield(L, 1, "weight");
+
+       lua_pushboolean(L, connected_nodes == NULL);
+
        //put shorest_distance linked list into table and return table
        delete_dj(shortest_distance);
-       return 1;
+       return 2;
 }
 
index 5c287b3710b401429c79eb6af12c1a6e5472726b..d3f6c3fc1d2d456fe90a8a429408e38319f5ffb2 100644 (file)
@@ -67,7 +67,6 @@ int del_node(lua_State *L)
        header head = (header)lua_touserdata(L,1);
        int nid = lua_tointeger(L,2);
 
-
        //find the node
        connect walker = head->front;
        connect follower = walker;
@@ -108,14 +107,17 @@ int del_node(lua_State *L)
                                if (edge_walker == node_walker->neighbor_list)
                                {
                                        node_walker->neighbor_list = node_walker->neighbor_list->next_edge;
+                                       free(edge_walker);
+                                       edge_walker = node_walker->neighbor_list;
+                                       delete_walker = edge_walker;
                                }
                                else
                                {
-                                       delete_walker->next_edge = edge_walker;
+                                       delete_walker->next_edge = edge_walker->next_edge;
                                        delete_walker = delete_walker->next_edge;
+                                       edge_walker = edge_walker->next_edge;
+                                       free(delete_walker);                            
                                }
-                               edge_walker = edge_walker->next_edge;
-                               free(delete_walker);
                        }
                        else
                        {
@@ -126,7 +128,6 @@ int del_node(lua_State *L)
                node_walker = node_walker->next_node;
        }
 
-
        //delete the node
        if (walker == head->front)
        {