Created
March 25, 2025 06:20
-
-
Save pgtwitter/742a1b852e9148a3ced10efa2ad0b484 to your computer and use it in GitHub Desktop.
幅80に収めて可読性を多少考えた版 https://gist.github.com/pgtwitter/2e0e0037928680dd6b10d531c591595e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# %% | |
def morse2Dot(in_filename, out_filename): | |
ROOT_LABEL = '(start)' | |
ROOT_CODE = 'START' | |
DUMMY = 'dummy' | |
DOT_SHAPE = 'shape=circle' | |
BAR_SHAPE = 'shape=rectangle' | |
ROOT_SHAPE = 'shape=diamond' | |
PROP_LINES = '\n\trankdir=TB;\n\tnodesep=0.5;\n\tpad=0.2;' | |
DUMMY_NODE_ATTR = ', label="(N/A)", margin=0' | |
DOT_EDGE_ATTR = 'penwidth=2, weight=1000, style=dashed' | |
BAR_EDGE_ATTR = 'penwidth=2' | |
class m: | |
def __init__(self, l, c): | |
self.code = c | |
self.n = c.count('.') | |
self.children = [] | |
self.p = ROOT_CODE if len(c) == 1 else c[0:-1] | |
self.shape = DOT_SHAPE if c[-1] == '.' else BAR_SHAPE | |
self.l = f'{DUMMY}{self.code}' if l == DUMMY else l | |
self.node_attr = DUMMY_NODE_ATTR if l == DUMMY else '' | |
self.edge_attr = DOT_EDGE_ATTR if c[-1] == '.' else BAR_EDGE_ATTR | |
self.node_line = f'\n\t"{self.l}" [{self.shape}{self.node_attr}];' | |
def node_lines(n): | |
ret = [n.node_line] if n.code != ROOT_CODE else [] | |
ret.extend([l for c in n.children for l in node_lines(c)]) | |
return ret | |
def edge_lines(n): | |
ret = [f'\n\t"{n.l}" -> "{c.l}" [{c.edge_attr}];' for c in n.children] | |
ret.extend([l for c in n.children for l in edge_lines(c)]) | |
return ret | |
def read(in_filename): | |
ms = {ROOT_CODE: m(ROOT_LABEL, ROOT_CODE)} | |
with open(in_filename, 'r', encoding='utf-8') as f: | |
kv = {(k, m(v, k)) for v, k in [l.strip().split('\t') for l in f]} | |
ms.update(kv) | |
return ms | |
def build(ms): | |
while (flag := True): | |
for n in [v for v in ms.values() if v.code != ROOT_CODE]: | |
ms[n.p] = m(DUMMY, n.p) if n.p not in ms else ms[n.p] | |
if n not in ms[n.p].children and ms[n.p] != n: | |
ms[n.p].children.append(n) | |
flag = False | |
if flag: | |
break | |
return ms | |
def generate(ms): | |
lines = f'\n\n\t"{ROOT_LABEL}" [{ROOT_SHAPE}];' | |
lines += ''.join(sorted(node_lines(ms[ROOT_CODE]))) | |
lines += '\n' + ''.join(sorted(edge_lines(ms[ROOT_CODE]))) + '\n' | |
for i in range(max([n.n for n in ms.values()]) + 1): | |
nodes = sorted([f'"{n.l}"' for n in ms.values() if n.n == i]) | |
lines += '\n\t{rank=same; ' + ' '.join(nodes) + '}' | |
return 'digraph MorseTree {' + PROP_LINES + lines + '\n}' | |
with open(out_filename, 'w', encoding='utf-8') as f: | |
f.write(generate(build(read(in_filename)))) | |
morse2Dot('morse.txt', 'own_tree.dot') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment