Skip to content

Instantly share code, notes, and snippets.

@pgtwitter
Last active March 21, 2025 15:38
Show Gist options
  • Save pgtwitter/1d66a655c3c53b021b4ccc46f3fc8cc3 to your computer and use it in GitHub Desktop.
Save pgtwitter/1d66a655c3c53b021b4ccc46f3fc8cc3 to your computer and use it in GitHub Desktop.
モール信号をツリー表示(dotファイル)にするpythonスクリプトをGrok3に書かせてみた.morse.txtを読み込んでmorse_tree.dotを作成する.
# %%
def read_morse_file(filename):
"""モールス信号データをファイルから読み込む"""
morse_data = {}
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
char, code = line.strip().split('\t')
morse_data[char] = code
return morse_data
def build_morse_graph(morse_data):
"""モールス信号のツリー構造を構築する"""
edges = [] # エッジのリスト
rank_groups = {} # 「-」の出現回数ごとのノードグループ
node_map = {'': '(start)'} # プレフィックスとノードのマッピング("START"を"(start)"に変更)
dummy_count = 0 # ダミーノードのカウンタ
# Trieの構築
trie = {}
for char, code in morse_data.items():
current = trie
for symbol in code:
if symbol not in current:
current[symbol] = {}
current = current[symbol]
current['char'] = char
# プレフィックスごとのノードを生成
def generate_nodes(prefix, current_trie, parent_node):
nonlocal dummy_count
node_name = None
if 'char' in current_trie:
node_name = current_trie['char'] # 定義された文字
else:
dummy_count += 1
node_name = f'(dummy{dummy_count})' # ダミーノード
node_map[prefix] = node_name
if parent_node != '(start)' or prefix:
last_symbol = prefix[-1]
edges.append((parent_node, node_name, last_symbol))
dot_count = prefix.count('.')
if dot_count not in rank_groups:
rank_groups[dot_count] = set()
rank_groups[dot_count].add(node_name)
for symbol in ['.', '-']:
if symbol in current_trie:
next_prefix = prefix + symbol
generate_nodes(next_prefix, current_trie[symbol], node_name)
for symbol in ['.', '-']:
if symbol in trie:
generate_nodes(symbol, trie[symbol], '(start)')
if 0 not in rank_groups:
rank_groups[0] = set()
rank_groups[0].add('(start)')
return edges, rank_groups, node_map
def generate_dot_code(edges, rank_groups, node_map, morse_data):
"""GraphvizのDOTコードを生成する"""
dot_lines = [
'digraph MorseTree {',
' rankdir=TB;',
' bgcolor="white";',
' nodesep=0.5;',
' pad=0.2;',
''
]
# ノード定義
dot_lines.append(' "(start)" [shape=diamond, label="(start)"];') # "(start)"を菱形に
for prefix, node in node_map.items():
if node == '(start)':
continue
if '(dummy' in node:
last_symbol = prefix[-1]
shape = 'circle' if last_symbol == '.' else 'rectangle'
dot_lines.append(f' "{node}" [shape={shape}, label="(N/A)", margin=0];')
else:
code = morse_data.get(node, '')
if code:
last_symbol = code[-1]
shape = 'circle' if last_symbol == '.' else 'rectangle'
else:
shape = 'rectangle' # デフォルト
dot_lines.append(f' "{node}" [shape={shape}];')
# エッジ定義
dot_lines.append('')
for src, dst, symbol in edges:
if symbol == '.':
dot_lines.append(f' "{src}" -> "{dst}" [penwidth=2, weight=2000, style=dashed];')
elif symbol == '-':
dot_lines.append(f' "{src}" -> "{dst}" [penwidth=2];')
# rank指定
dot_lines.append('')
for bar_count in sorted(rank_groups.keys()):
nodes = ' '.join(f'"{node}"' for node in sorted(rank_groups[bar_count]))
dot_lines.append(f' {{rank=same; {nodes}}}')
dot_lines.append('}')
return '\n'.join(dot_lines)
# メイン処理(morse.txtを読み込む関数は省略されていると仮定)
morse_data = read_morse_file('morse.txt')
edges, rank_groups, node_map = build_morse_graph(morse_data)
dot_code = generate_dot_code(edges, rank_groups, node_map, morse_data)
with open('morse_tree.dot', 'w', encoding='utf-8') as f:
f.write(dot_code)
print("Generated morse_tree.dot")
A .-
B -...
C -.-.
D -..
E .
F ..-.
G --.
H ....
I ..
J .---
K -.-
L .-..
M --
N -.
O ---
P .--.
Q --.-
R .-.
S ...
T -
U ..-
V ...-
W .--
X -..-
Y -.--
Z --..
5 .....
4 ....-
3 ...--
2 ..---
1 .----
6 -....
7 --...
8 ---..
9 ----.
0 -----
訂正 ........
ピリオド .-.-.-
digraph MorseTree {
rankdir=TB;
bgcolor="white";
nodesep=0.5;
pad=0.2;
"(start)" [shape=diamond, label="(start)"];
"E" [shape=circle];
"I" [shape=circle];
"S" [shape=circle];
"H" [shape=circle];
"5" [shape=circle];
"(dummy1)" [shape=circle, label="(N/A)", margin=0];
"(dummy2)" [shape=circle, label="(N/A)", margin=0];
"訂正" [shape=circle];
"4" [shape=rectangle];
"V" [shape=rectangle];
"3" [shape=rectangle];
"U" [shape=rectangle];
"F" [shape=circle];
"(dummy3)" [shape=rectangle, label="(N/A)", margin=0];
"2" [shape=rectangle];
"A" [shape=rectangle];
"R" [shape=circle];
"L" [shape=circle];
"(dummy4)" [shape=rectangle, label="(N/A)", margin=0];
"(dummy5)" [shape=circle, label="(N/A)", margin=0];
"ピリオド" [shape=rectangle];
"W" [shape=rectangle];
"P" [shape=circle];
"J" [shape=rectangle];
"1" [shape=rectangle];
"T" [shape=rectangle];
"N" [shape=circle];
"D" [shape=circle];
"B" [shape=circle];
"6" [shape=circle];
"X" [shape=rectangle];
"K" [shape=rectangle];
"C" [shape=circle];
"Y" [shape=rectangle];
"M" [shape=rectangle];
"G" [shape=circle];
"Z" [shape=circle];
"7" [shape=circle];
"Q" [shape=rectangle];
"O" [shape=rectangle];
"(dummy6)" [shape=circle, label="(N/A)", margin=0];
"8" [shape=circle];
"(dummy7)" [shape=rectangle, label="(N/A)", margin=0];
"9" [shape=circle];
"0" [shape=rectangle];
"(start)" -> "E" [penwidth=2, weight=2000, style=dashed];
"E" -> "I" [penwidth=2, weight=2000, style=dashed];
"I" -> "S" [penwidth=2, weight=2000, style=dashed];
"S" -> "H" [penwidth=2, weight=2000, style=dashed];
"H" -> "5" [penwidth=2, weight=2000, style=dashed];
"5" -> "(dummy1)" [penwidth=2, weight=2000, style=dashed];
"(dummy1)" -> "(dummy2)" [penwidth=2, weight=2000, style=dashed];
"(dummy2)" -> "訂正" [penwidth=2, weight=2000, style=dashed];
"H" -> "4" [penwidth=2];
"S" -> "V" [penwidth=2];
"V" -> "3" [penwidth=2];
"I" -> "U" [penwidth=2];
"U" -> "F" [penwidth=2, weight=2000, style=dashed];
"U" -> "(dummy3)" [penwidth=2];
"(dummy3)" -> "2" [penwidth=2];
"E" -> "A" [penwidth=2];
"A" -> "R" [penwidth=2, weight=2000, style=dashed];
"R" -> "L" [penwidth=2, weight=2000, style=dashed];
"R" -> "(dummy4)" [penwidth=2];
"(dummy4)" -> "(dummy5)" [penwidth=2, weight=2000, style=dashed];
"(dummy5)" -> "ピリオド" [penwidth=2];
"A" -> "W" [penwidth=2];
"W" -> "P" [penwidth=2, weight=2000, style=dashed];
"W" -> "J" [penwidth=2];
"J" -> "1" [penwidth=2];
"(start)" -> "T" [penwidth=2];
"T" -> "N" [penwidth=2, weight=2000, style=dashed];
"N" -> "D" [penwidth=2, weight=2000, style=dashed];
"D" -> "B" [penwidth=2, weight=2000, style=dashed];
"B" -> "6" [penwidth=2, weight=2000, style=dashed];
"D" -> "X" [penwidth=2];
"N" -> "K" [penwidth=2];
"K" -> "C" [penwidth=2, weight=2000, style=dashed];
"K" -> "Y" [penwidth=2];
"T" -> "M" [penwidth=2];
"M" -> "G" [penwidth=2, weight=2000, style=dashed];
"G" -> "Z" [penwidth=2, weight=2000, style=dashed];
"Z" -> "7" [penwidth=2, weight=2000, style=dashed];
"G" -> "Q" [penwidth=2];
"M" -> "O" [penwidth=2];
"O" -> "(dummy6)" [penwidth=2, weight=2000, style=dashed];
"(dummy6)" -> "8" [penwidth=2, weight=2000, style=dashed];
"O" -> "(dummy7)" [penwidth=2];
"(dummy7)" -> "9" [penwidth=2, weight=2000, style=dashed];
"(dummy7)" -> "0" [penwidth=2];
{rank=same; "(dummy7)" "(start)" "0" "M" "O" "T"}
{rank=same; "(dummy6)" "1" "9" "A" "E" "G" "J" "K" "N" "Q" "W" "Y"}
{rank=same; "(dummy3)" "(dummy4)" "2" "8" "C" "D" "I" "P" "R" "U" "X" "Z"}
{rank=same; "(dummy5)" "3" "7" "B" "F" "L" "S" "V" "ピリオド"}
{rank=same; "4" "6" "H"}
{rank=same; "5"}
{rank=same; "(dummy1)"}
{rank=same; "(dummy2)"}
{rank=same; "訂正"}
}
@pgtwitter
Copy link
Author

morse_tree

@pgtwitter
Copy link
Author

morse_tree

@pgtwitter
Copy link
Author

morse_tree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment