diff --git a/src/atcoder/extra/graph/visualize.nim b/src/atcoder/extra/graph/visualize.nim deleted file mode 100644 index 28098ac0..00000000 --- a/src/atcoder/extra/graph/visualize.nim +++ /dev/null @@ -1,76 +0,0 @@ -when not declared ATCODER_GRAPH_VISUALIZE_HPP: - const ATCODER_GRAPH_VISUALIZE_HPP* = 1 - import atcoder/extra/graph/graph_template - import std/strformat, std/os - - proc is_weighted*(g:Graph):bool = - static: - assert g.adjType is ADJTYPE_SEQ - for u in 0 ..< g.len: - for e in g[u]: - if e.weight != 1: return true - return false - - proc is_directed*(g:Graph):bool = - static: - assert g.adjType is ADJTYPE_SEQ - for u in 0 ..< g.len: - for e in g[u]: - if e.rev == -1: return true - return false - - proc visualize*(g:Graph) = - var f: File = open("graph.html", FileMode.fmWrite) - var - nodes_array:seq[string] = @[] - edges_array:seq[string] = @[] - let is_directed = g.is_directed - let is_weighted = g.is_weighted - var found = initSet[(int, int)]() - for u in 0 ..< g.len: - nodes_array.add(fmt"{{id: {u}, label: '{u}'}}") - for i, e in g[u]: - if not is_directed: - if (u, i) in found: continue - found.incl((e.dst, e.rev)) - var s = fmt"from: {u}, to: {e.dst}" - if is_weighted: - s &= fmt", label: '{e.weight}'" - if is_directed: - s &= ", arrows: 'to'" - edges_array.add(fmt"{{ {s} }}") - let - nodes_info = nodes_array.join(",") - edges_info = edges_array.join(",") - var s = fmt""" - -
- - - - - - - - - -""" - f.write(s) - f.close - var r = execShellCmd("brave-browser graph.html") diff --git a/src/atcoder/extra/graph/visualizer.nim b/src/atcoder/extra/graph/visualizer.nim new file mode 100644 index 00000000..5759abff --- /dev/null +++ b/src/atcoder/extra/graph/visualizer.nim @@ -0,0 +1,86 @@ +when not declared ATCODER_GRAPH_VISUALIZER_HPP: + const ATCODER_GRAPH_VISUALIZER_HPP* = 1 + import atcoder/extra/graph/graph_template + import std/strformat, std/sets, std/strutils, std/browsers + proc visualize*(g:Graph, labels:seq[string] = @[], base = 0) = + var + node_data:seq[string] + edge_data:seq[string] + useNodeLabels = if labels.len == 0: false else: true + isEdgeWeighted = block: + var r = false + for u in 0 ..< g.len: + for e in g[u]: + if e.weight != 1: r = true + r + if useNodeLabels: + doAssert labels.len == g.len + for u in 0 ..< g.len: + var node_name = if useNodeLabels: labels[u] else: $(u + base) + node_data.add fmt"{{id: {$u}, label: '{node_name}'}}" + var undirected_edges = initHashSet[(int, int)]() + for u in 0 ..< g.len: + for e in g[u]: + let v = e.dst + var edge_label = if isEdgeWeighted: fmt"'{$e.weight}'" else: "undefined" + if e.rev == -1: + edge_data.add(fmt"{{from: {$u}, to: {$v}, arrows: 'to', label: {edge_label} }}") + else: + if (u, v) in undirected_edges: continue + edge_data.add(fmt"{{from: {$u}, to: {$v}, label: {edge_label} }}") + undirected_edges.incl((u, v)) + undirected_edges.incl((v, u)) + var html = """ + + + + + + + + + + + +""" + html = html.replace("<<