Advertisement
Guest User

Untitled

a guest
May 27th, 2015
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.98 KB | None | 0 0
  1. import Prelude
  2. import Data.Maybe
  3. import Data.Char (isDigit)
  4. import Data.List ((\\), delete, sort, group)
  5.  
  6.  
  7. import Eventloop.EventloopCore
  8. import Eventloop.DefaultConfiguration
  9. import Eventloop.Types.EventTypes
  10.  
  11. import qualified Eventloop.Module.Websocket.Canvas as C
  12. import qualified Eventloop.Module.BasicShapes as B
  13. import qualified Eventloop.Module.Websocket.Mouse as M
  14. import qualified Eventloop.Module.Websocket.Keyboard as K
  15. import qualified Eventloop.Module.StdOut as S
  16. import Eventloop.Module.Graphs
  17.  
  18.  
  19. {- | Start
  20. This function will start the eventloop system using the eventloopConfig
  21. -}
  22. start = startMainloop eventloopConfig
  23.  
  24. {- | The configuration of the Eventloop system
  25. Uses the graphs module to display graphs. This module
  26. depends on the Keyboard, Mouse, Canvas and BasicShapes modules
  27. -}
  28. eventloopConfig = defaultConfig { moduleConfigurations=[ defaultGraphsModuleConfiguration
  29. , B.defaultBasicShapesModuleConfiguration
  30. , C.defaultCanvasModuleConfiguration
  31. , M.defaultMouseModuleConfiguration
  32. , K.defaultKeyboardModuleConfiguration
  33. , S.defaultStdOutModuleConfiguration
  34. ]}
  35. where
  36. defaultConfig = allModulesEventloopConfiguration beginProgramState eventloop -- Uses beginProgramState and eventloop to build config
  37.  
  38.  
  39. {- | ProgramState
  40. This datatype shows which variables are kept
  41. -}
  42. data ProgramState
  43. = ProgramState { pressedKey :: [Char]
  44. , node1Select :: Maybe Node
  45. , node2Select :: Maybe Node
  46. , graph :: Graph
  47. }
  48.  
  49.  
  50. {- | Begingraph
  51. This is the start state of the graph
  52. -}
  53. beginGraph = Graph allNodes allEdges Undirected Unweighted
  54. where
  55. allNodes = [ ('a', (50, 50), Red)
  56. , ('b', (150, 50), Blue)
  57. , ('c', (200, 200), Orange)
  58. ]
  59. allEdges = [ ('a', 'b', Green, 5, Thick)
  60. , ('c', 'b', Orange, 3, Thin)
  61. , ('c', 'a', Purple, 2, Thin)
  62. ]
  63.  
  64.  
  65. {-| The beginstate of the ProgramState
  66. -}
  67. beginProgramState = ProgramState [] Nothing Nothing beginGraph
  68.  
  69.  
  70. {- | Instructions
  71. This is the list of all possible instructions
  72. Feel free to add your own
  73. -}
  74. instructions = [ "Instructions"
  75. , "Press 'n' and click on the screen to create a new node"
  76. , "Press 'r', click on a node and press a letter to rename the node"
  77. , "Press 'e', click on two nodes to create an edge"
  78. , "Press 'd', click on a node to delete the node"
  79. , "Press 'w', click on two nodes and press a number to weight the edge in between"
  80. , "Press 'f', click on two nodes to delete an edge"
  81. , "Press 'c', click on a node to color it red"
  82. , "Press 'b', click on a node to color its neighborhood blue"
  83. , "Press 'a', click on a node to reset all the coloring"
  84. , "Press 'k' and select 2 nodes to check if there's a path between them."
  85. , "Press 'esc' to abort the current operation and start another"
  86. ]
  87.  
  88.  
  89. {- | A variable showing which labels are used for visually added nodes
  90. -}
  91. automaticPossibleLabels :: [Label]
  92. automaticPossibleLabels = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']
  93.  
  94.  
  95. {- | A function to determine which label can be used next
  96. -}
  97. nextLabel :: [Node] -> Label
  98. nextLabel nodes
  99. | null leftOverLabels = error "Did not have a leftover label to give to a node. Please do not create so many nodes!"
  100. | otherwise = head leftOverLabels
  101. where
  102. currentLabels = map (\(l, _, _) -> l) nodes
  103. leftOverLabels = automaticPossibleLabels \\ currentLabels
  104.  
  105.  
  106. {- | Add a node to the graph
  107. -}
  108. addNode :: Graph -> Node -> Graph
  109. addNode g@(Graph{nodes=ns}) n = g {nodes=(n:ns)}
  110.  
  111. {- returns a list of neighbours of a node -}
  112. getNeighbors :: Graph -> Node -> [Label]
  113. getNeighbors g@(Graph{edges=es, directed=d}) (l,_,_) = getNeighborsByEdges es l d
  114.  
  115. getNeighborsByEdges :: [Edge] -> Label -> Directed -> [Label]
  116. getNeighborsByEdges [] n d = []
  117. getNeighborsByEdges ((l1, l2, _, _, _):es) l Directed
  118. | l1 == l = [l2]++(getNeighborsByEdges es l Directed)
  119. | otherwise = getNeighborsByEdges es l Directed
  120.  
  121. getNeighborsByEdges ((l1, l2, _, _, _):es) l Undirected
  122. | l1 == l = [l2]++(getNeighborsByEdges es l Undirected)
  123. | l2 == l = [l1]++(getNeighborsByEdges es l Undirected)
  124. | otherwise = getNeighborsByEdges es l Undirected
  125.  
  126. existsPath :: Graph -> Node -> Node -> Bool
  127. existsPath g n1 n2 = existsHelper g [n1] n2
  128.  
  129. existsHelper :: Graph -> [Node] -> Node -> Bool
  130. existsHelper g ns n
  131. | elem n ns = True
  132. | length ns == length ns' = False
  133. | otherwise = existsHelper g ns' n
  134. where ns' = ns ++ (getNeighborsByNodeList g ns)
  135.  
  136. getNeighborsByNodeList :: Graph -> [Node] -> [Node]
  137. getNeighborsByNodeList _ [] = []
  138. getNeighborsByNodeList g (n:ns) = rmdups ((getNodesByLabels g (getNeighbors g n)) ++ (getNeighborsByNodeList g ns))
  139.  
  140. {- | Paints the list of nodes to a certain colour. -}
  141. paintItColor :: [Node] -> Color -> [Node]
  142. paintItColor [] clr = []
  143. paintItColor ((l,p,c):ns) clr = [(l,p,clr)]++(paintItColor ns clr)
  144. {-
  145. swap123to312 :: (a -> b -> c -> d) -> (b -> c -> a -> d)
  146. swap123to312 f a b c = f c a b
  147.  
  148. existsPath :: Graph -> Node -> Node -> Bool
  149. existsPath g@(Graph{nodes=ns, edges=es}) n1 n2
  150. | n1 == n2 = False
  151. | not (findEdgeFromNodeToNode n1 n2 g == Nothing) = True
  152. | findEdgesBetweenNodes n1 n2 g == [] = any ((swap123to312 findEdgesBetweenNodes) ((removeNodeWithAdjoiningEdges n1 g) n1)) (getNodesByLabels (getNeighbors (removeNodeWithAdjoiningEdges n1 g) n2 ))
  153. | otherwise = True
  154. -}
  155. rmdups :: Eq a => [a] -> [a]
  156. rmdups [] = []
  157. rmdups (x:xs) | elem x xs = rmdups xs
  158. | otherwise = [x]++(rmdups xs)
  159.  
  160. {- | Gets a list of nodes by using a list of labels. -}
  161. getNodesByLabels :: Graph -> [Label] -> [Node]
  162. getNodesByLabels g@(Graph{nodes=ns}) labels = getNBL ns labels
  163.  
  164. getNBL :: [Node] -> [Label] -> [Node]
  165. getNBL ns [] = []
  166. getNBL ns (l:ls) = [getNodeByLabel ns l]++(getNBL ns ls)
  167.  
  168. getNodeByLabel :: [Node] -> Label -> Node
  169. getNodeByLabel [] label = error "Node is not found"
  170. getNodeByLabel ((l,a,b):ns) label | l == label = (l,a,b)
  171. | otherwise = getNodeByLabel ns label
  172.  
  173. {- | Add an edge to the graph
  174. -}
  175. addEdge :: Graph -> Edge -> Graph
  176. addEdge g@(Graph{edges=es}) e = g {edges=(e:es)}
  177.  
  178.  
  179. {- | Create an edge based on two nodes
  180. Is drawn from node1 to node2
  181. -}
  182. createEdge :: Node -> Node -> Edge
  183. createEdge (l1, _, c) (l2, _, _)
  184. = (l1, l2, c, 0, Thin)
  185.  
  186.  
  187. {- | Finds the edge directed from the first to the second node
  188. -}
  189. findEdgeFromNodeToNode :: Node -> Node -> Graph -> Maybe Edge
  190. findEdgeFromNodeToNode n1 n2 g
  191. | null possibleEdges = Nothing
  192. | otherwise = Just $ head possibleEdges
  193. where
  194. allEdges = edges g
  195. possibleEdges = filter (edgeRunsFromNodeToNode n1 n2) allEdges
  196.  
  197.  
  198. {- | Finds all edges connected to this node
  199. -}
  200. findEdgesAtNode :: Node -> Graph -> [Edge]
  201. findEdgesAtNode (l, _, _) g
  202. = filter (\(el1, el2, _, _, _) -> el1 == l || el2 == l) allEdges
  203. where
  204. allEdges = edges g
  205.  
  206.  
  207. {- | Finds all edges that are between two nodes
  208. -}
  209. findEdgesBetweenNodes :: Node -> Node -> Graph -> [Edge]
  210. findEdgesBetweenNodes n1 n2 g
  211. = filter (edgeIsBetweenNodes n1 n2) allEdges
  212. where
  213. allEdges = edges g
  214.  
  215.  
  216. {- | Conditional to check if an edge is connected to both nodes
  217. -}
  218. edgeIsBetweenNodes :: Node -> Node -> Edge -> Bool
  219. edgeIsBetweenNodes (l1, _, _) (l2, _, _) (el1, el2, _, _, _)
  220. = (el1 == l1 && el2 == l2) || (el1 == l2 && el2 == l1)
  221.  
  222.  
  223. {- | Conditional to check if the runs is directed from the first
  224. to the second node
  225. -}
  226. edgeRunsFromNodeToNode :: Node -> Node -> Edge -> Bool
  227. edgeRunsFromNodeToNode (l1, _, _) (l2, _, _) (el1, el2, _, _, _)
  228. = (l1 == el1) && (l2 == el2)
  229.  
  230.  
  231. {- | Removes the node from the graph
  232. -}
  233. removeNode :: Node -> Graph -> Graph
  234. removeNode n g
  235. = g {nodes = allNodes'}
  236. where
  237. allNodes = nodes g
  238. allNodes' = delete n allNodes
  239.  
  240. {- | Removes the edge from the graph
  241. -}
  242. removeEdge :: Edge -> Graph -> Graph
  243. removeEdge e g
  244. = g {edges = allEdges'}
  245. where
  246. allEdges = edges g
  247. allEdges' = delete e allEdges
  248.  
  249. {- | Removes a node, and all edges connected to it,
  250. from the graph
  251. -}
  252. removeNodeWithAdjoiningEdges :: Node -> Graph -> Graph
  253. removeNodeWithAdjoiningEdges n g
  254. = g''
  255. where
  256. g' = removeNode n g
  257. g'' = foldr removeEdge g' (findEdgesAtNode n g)
  258.  
  259. {- | Rename a node in the edge to the new label
  260. if the node is connected to that edge
  261. -}
  262. renameNodeInEdge :: Node -> Label -> Edge -> Edge
  263. renameNodeInEdge (oldL, _, _) newL (el1, el2, color, weight, thickness)
  264. | oldL == el1 = (newL, el2, color, weight, thickness)
  265. | oldL == el2 = (el1, newL, color, weight, thickness)
  266. | otherwise = (el1, el2, color, weight, thickness)
  267.  
  268.  
  269. {- | The eventloop
  270. This function uses the current state and an In event to determine
  271. the new state and what changes should be made as a list of Out events.
  272. -}
  273. eventloop :: ProgramState -> In -> (ProgramState, [Out])
  274.  
  275. eventloop ps Start
  276. = (ps, [OutGraphs SetupGraphs, OutGraphs $ DrawGraph (graph ps), OutGraphs $ Instructions instructions])
  277.  
  278. eventloop ps@(ProgramState "f" (Just node1s) _ g) (InGraphs (Mouse (Click _) p))
  279. | nodeAtPosM == Nothing = (ps, [])
  280. | edgeM == Nothing = (ProgramState [] Nothing Nothing g, [])
  281. | otherwise = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Deleted edge from '" ++ [l1] ++ "' to '" ++ [l2] ++ "'\n"])
  282. where
  283. nodeAtPosM = onNode allNodes p
  284. (Just nodeAtPos) = nodeAtPosM
  285. allNodes = nodes g
  286. edgeM = findEdgeFromNodeToNode node1s nodeAtPos g
  287. (Just edge) = edgeM
  288. (l1, l2, _, _, _) = edge
  289. g' = removeEdge edge g
  290.  
  291. {- | If 'w' has been pressed, two nodes are selected and the next key
  292. is a digit, the edge running from node1s to node2s is weighted as that
  293. digit
  294. -}
  295. eventloop ps@(ProgramState "w" (Just node1s) (Just node2s) g) (InGraphs (Key [key]))
  296. | isDigit key && edgeM /= Nothing = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Weighted edge from '" ++ [l1] ++ "' to '" ++ [l2] ++ "' with " ++ (show weight) ++ "\n"])
  297. | otherwise = (ProgramState [] Nothing Nothing g, [])
  298. where
  299. edgeM = findEdgeFromNodeToNode node1s node2s g
  300. (Just edge@(l1, l2, col, w, thick)) = edgeM
  301. weight = read [key] :: Weight
  302. edge' = (l1, l2, col, weight, thick)
  303. g' = (flip addEdge) edge' $ removeEdge edge g
  304.  
  305. {- | color the selected node red -}
  306. eventloop ps@(ProgramState "c" _ _ g) (InGraphs (Mouse (Click _) pos))
  307. | nodeAtPosM == Nothing = (ps, [])
  308. | otherwise = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Colored node " ++ [l] ++ " red.\n"])
  309. where
  310. nodeAtPosM = onNode allNodes pos
  311. (Just nodeAtPos) = nodeAtPosM
  312. (l, p, _) = nodeAtPos
  313. newNode = (l, p, Red)
  314. allNodes = nodes g
  315. g' = addNode (removeNode nodeAtPos g) newNode
  316.  
  317. {- | color the neighbourhood blue -}
  318. eventloop ps@(ProgramState "b" _ _ g) (InGraphs (Mouse (Click _) pos))
  319. | nodeAtPosM == Nothing = (ps, [])
  320. | otherwise = (ProgramState [] Nothing Nothing g'', [OutGraphs $ DrawGraph g'', OutStdOut $ S.StdOutMessage $ "Colored the neighborhood of " ++ [l] ++ " blue.\n"])
  321. where
  322. nodeAtPosM = onNode allNodes pos
  323. (Just nodeAtPos) = nodeAtPosM
  324. (l, p, c) = nodeAtPos
  325. nbs = getNeighbors g nodeAtPos
  326. nbsNew = paintItColor (getNodesByLabels g nbs) Blue
  327. allNodes = nodes g
  328. g' = foldl (flip removeNode) g (getNodesByLabels g nbs)
  329. g'' = foldl addNode g' nbsNew
  330.  
  331.  
  332. {- | color everything back to normal -}
  333. eventloop ps@(ProgramState "a" _ _ g) (InGraphs (Mouse (Click _) pos))
  334. | nodeAtPosM == Nothing = (ps, [])
  335. | otherwise = (ProgramState [] Nothing Nothing g'', [OutGraphs $ DrawGraph g'', OutStdOut $ S.StdOutMessage $ "Reset the coloring.\n"])
  336. where
  337. nodeAtPosM = onNode allNodes pos
  338. (Just nodeAtPos) = nodeAtPosM
  339. (l, p, c) = nodeAtPos
  340. nodesNew = paintItColor allNodes Orange
  341. allNodes = nodes g
  342. g' = foldl (flip removeNode) g (allNodes)
  343. g'' = foldl addNode g' nodesNew
  344.  
  345.  
  346. {- | If 'd' has been pressed and a node is selected
  347. , the node is deleted from the graph
  348. -}
  349. eventloop ps@(ProgramState "d" _ _ g) (InGraphs (Mouse (Click _) p))
  350. | nodeAtPosM == Nothing = (ps, [])
  351. | otherwise = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Deleted node '" ++ [l] ++ "'\n"])
  352. where
  353. (l, _, _) = nodeAtPos
  354. nodeAtPosM = onNode allNodes p
  355. (Just nodeAtPos) = nodeAtPosM
  356. allNodes = nodes g
  357. g' = removeNodeWithAdjoiningEdges nodeAtPos g
  358.  
  359.  
  360. {- | If 'e' has been pressed, a node selected and a new node is selected
  361. an edge is drawn between the two nodes
  362. -}
  363. eventloop ps@(ProgramState "e" (Just node1s) _ g) (InGraphs (Mouse (Click _) p))
  364. | nodeAtPosM == Nothing = (ps, [])
  365. | otherwise = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Created edge from '" ++ [l1] ++ "' to '" ++ [l2] ++ "'\n"])
  366. where
  367. (l1, _, _) = node1s
  368. (l2, _, _) = nodeAtPos
  369. nodeAtPosM = onNode allNodes p
  370. allNodes = nodes g
  371. (Just nodeAtPos) = nodeAtPosM
  372. g' = addEdge g $ createEdge node1s nodeAtPos
  373.  
  374. {- | If 'k' has been pressed, a node selected and a new node is selected
  375. an edge is drawn between the two nodes
  376. -}
  377. eventloop ps@(ProgramState "k" (Just node1s) _ g) (InGraphs (Mouse (Click _) p))
  378. | nodeAtPosM == Nothing = (ps, [])
  379. | otherwise = (ProgramState [] Nothing Nothing g, [OutGraphs $ DrawGraph g, OutStdOut $ S.StdOutMessage $ "Edge from '" ++ [l1] ++ "to " ++ [l2] ++ "'exists: '" ++ (show hasPath) ++ ".'\n"])
  380. where
  381. (l1, _, _) = node1s
  382. (l2, _, _) = nodeAtPos
  383. nodeAtPosM = onNode allNodes p
  384. allNodes = nodes g
  385. (Just nodeAtPos) = nodeAtPosM
  386. hasPath = existsPath g node1s nodeAtPos
  387.  
  388. {- | If 'r' has been pressed, a node selected and a new key stroke
  389. comes in, the label of the selected node is changed
  390. -}
  391. eventloop ps@(ProgramState "r" (Just node1s) _ g) (InGraphs (Key [l]))
  392. = (ProgramState [] Nothing Nothing g'', [OutGraphs $ DrawGraph g'', OutStdOut $ S.StdOutMessage $ "Renamed node '" ++ [oldL] ++ "' to '" ++ [l] ++ "'\n"])
  393. where
  394. allNodes = nodes g
  395. allEdges = edges g
  396. (oldL, p, color) = node1s
  397. node' = (l, p, color)
  398. allEdges' = map (renameNodeInEdge node1s l) allEdges :: [Edge]
  399. g' = (flip addNode) node' $ removeNode node1s g
  400. g'' = g' {edges = allEdges'}
  401.  
  402.  
  403. {- | If 'n' has been pressed and the mouse has
  404. clicked at a position where there is no node yet,
  405. a new node is inserted at that point
  406. -}
  407. eventloop ps@(ProgramState "n" _ _ g) (InGraphs (Mouse (Click _) p))
  408. | nodeAtPosM == Nothing = (ProgramState [] Nothing Nothing g', [OutGraphs $ DrawGraph g', OutStdOut $ S.StdOutMessage $ "Inserted node '" ++ [nextlabel] ++ "'\n"])
  409. | otherwise = (ps, [OutStdOut $ S.StdOutMessage "Tried to insert a node on another node"])
  410. where
  411. nodeAtPosM = onNode allNodes p
  412. allNodes = nodes g
  413. nextlabel = nextLabel allNodes
  414. newNode = (nextlabel, p, Orange)
  415. g' = g {nodes=(newNode:allNodes)}
  416.  
  417.  
  418. {- | Buffer the last node selected if it doesn't
  419. trigger an event on first spot
  420. -}
  421. eventloop ps@(ProgramState _ Nothing _ g) (InGraphs (Mouse (Click _) p))
  422. | nodeAtPosM == Nothing = (ps, [])
  423. | otherwise = (ps {node1Select = Just nodeAtPos}, [OutStdOut $ S.StdOutMessage $ "[1st Select] Click on node '" ++ [l] ++ "'\n"])
  424. where
  425. (l, _, _) = nodeAtPos
  426. (Just nodeAtPos) = nodeAtPosM
  427. nodeAtPosM = onNode allNodes p
  428. allNodes = nodes g
  429.  
  430.  
  431. {- | Buffer the last node selected if it doesn't trigger an event on second spot -}
  432. eventloop ps@(ProgramState _ (Just _) Nothing g) (InGraphs (Mouse (Click _) p))
  433. | nodeAtPosM == Nothing = (ps, [OutStdOut $ S.StdOutMessage "Clicked on not a node\n"])
  434. | otherwise = (ps {node2Select = Just nodeAtPos}, [OutStdOut $ S.StdOutMessage $ "[2nd Select] Click on node '" ++ [l] ++ "'\n"])
  435. where
  436. (l, _, _) = nodeAtPos
  437. (Just nodeAtPos) = nodeAtPosM
  438. nodeAtPosM = onNode allNodes p
  439. allNodes = nodes g
  440.  
  441.  
  442. {- | Abort current operation and reset start on "esc" -}
  443. eventloop ps (InGraphs (Key "esc"))
  444. = (ProgramState [] Nothing Nothing (graph ps), [OutStdOut $ S.StdOutMessage "Aborted current operation\n"])
  445.  
  446.  
  447. {- | Stop the system on "s" -}
  448. eventloop ps (InGraphs (Key "s"))
  449. = (ps, [OutStdOut $ S.StdOutMessage "Stopping system...\n", Stop])
  450.  
  451.  
  452. {- | Buffer the last press key if it doesn't trigger an event -}
  453. eventloop ps@(ProgramState _ _ _ _) (InGraphs (Key key))
  454. = (ps {pressedKey = key}, [OutStdOut $ S.StdOutMessage $ "Buffered keystroke '" ++ key ++ "'\n" ])
  455.  
  456.  
  457. {- | For all other In events, do nothing -}
  458. eventloop ps _ = (ps, [])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement