298 lines
12 KiB
Python
298 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""Bind Pythagorean numerology onto number-words already inside the thousand.
|
|
|
|
Does not add cells. Master numbers 11, 22 and 33 stay unreduced.
|
|
Rebuilds the stale lexicon.json so its ids match words_data.dart.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
|
|
from repair_canon_integrity import ( # noqa: E402
|
|
CANON_A,
|
|
CANON_B,
|
|
HTML,
|
|
KB_ASSETS,
|
|
KB_OUT,
|
|
LEX,
|
|
embed_html,
|
|
ensure_tag,
|
|
load_dart,
|
|
write_alpha,
|
|
write_dart,
|
|
)
|
|
|
|
# word, station id, name (also the tag detail), group, symbol, cluster words, lore
|
|
STATIONS = [
|
|
(
|
|
"один",
|
|
"n1",
|
|
"1 Характер (Монада)",
|
|
"Квадрат Пифагора · воля и эго",
|
|
"1",
|
|
["воля", "характер"],
|
|
"Первопроходец ряда. Ячейка квадрата держит характер и волю: одну точку, из которой начинается счёт.",
|
|
),
|
|
(
|
|
"два",
|
|
"n2",
|
|
"2 Энергия (Дуада)",
|
|
"Квадрат Пифагора · пара и мера сил",
|
|
"2",
|
|
[],
|
|
"Дипломат пары. Ячейка квадрата — запас действия: хватает ли сил на шаг, или шаг берёт силы у другого.",
|
|
),
|
|
(
|
|
"три",
|
|
"n3",
|
|
"3 Интерес (Триада)",
|
|
"Квадрат Пифагора · познание",
|
|
"3",
|
|
["интерес"],
|
|
"Творец. Ячейка квадрата — интерес: внимание, которое выбирает один предмет и не отпускает его.",
|
|
),
|
|
(
|
|
"четыре",
|
|
"n4",
|
|
"4 Тело (Тетрада)",
|
|
"Квадрат Пифагора · опора",
|
|
"4",
|
|
["тело"],
|
|
"Строитель основания. Ячейка квадрата — тело и запас сил: то, на чём держится долгий труд.",
|
|
),
|
|
(
|
|
"пять",
|
|
"n5",
|
|
"5 Логика (Пентада)",
|
|
"Квадрат Пифагора · расчёт",
|
|
"5",
|
|
[],
|
|
"Странник. Ячейка квадрата — логика и чутьё: шаг просчитан, и всё же горизонт ещё не закрыт.",
|
|
),
|
|
(
|
|
"шесть",
|
|
"n6",
|
|
"6 Труд (Гексада)",
|
|
"Квадрат Пифагора · ремесло",
|
|
"6",
|
|
["труд"],
|
|
"Хранитель очага. Ячейка квадрата — труд руками: ремесло, которое заземляет слово.",
|
|
),
|
|
(
|
|
"семь",
|
|
"n7",
|
|
"7 Удача (Септенер)",
|
|
"Квадрат Пифагора · покров",
|
|
"7",
|
|
[],
|
|
"Искатель истины. Ячейка квадрата — везение: покров, которого нет в труде и который трудом не покупается.",
|
|
),
|
|
(
|
|
"восемь",
|
|
"n8",
|
|
"8 Долг (Октава)",
|
|
"Квадрат Пифагора · совесть",
|
|
"8",
|
|
[],
|
|
"Владыка материи. Ячейка квадрата — долг: слово, которое человек держит, когда выгоды уже нет.",
|
|
),
|
|
(
|
|
"девять",
|
|
"n9",
|
|
"9 Память (Эннеада)",
|
|
"Квадрат Пифагора · ум",
|
|
"9",
|
|
["память", "ум"],
|
|
"Мудрец конца ряда. Ячейка квадрата — память и ум: что удержано, прежде чем счёт перейдёт в десяток.",
|
|
),
|
|
(
|
|
"одиннадцать",
|
|
"n11",
|
|
"11 Духовный проводник",
|
|
"Мастер-числа · озарение",
|
|
"11",
|
|
["истина"],
|
|
"Мастер-число. Канал озарения, который не свёртывается в двойку. Проводник несёт свет, а не отчёт.",
|
|
),
|
|
(
|
|
"двадцать два",
|
|
"n22",
|
|
"22 Великий архитектор",
|
|
"Мастер-числа · система",
|
|
"22",
|
|
[],
|
|
"Мастер-число. Строитель, который переводит замысел в систему: двадцать два аркана и двадцать два пути Древа.",
|
|
),
|
|
(
|
|
"тридцать три",
|
|
"n33",
|
|
"33 Мастер-число (33 ряда Домов)",
|
|
"Мастер-числа · служение",
|
|
"33",
|
|
["любовь"],
|
|
"Мастер-число служения и сострадания. Тем же числом названы 33 ряда домов поля: престол считает ряды, а не клетки лексикона.",
|
|
),
|
|
]
|
|
|
|
|
|
def _load_html_words():
|
|
html = HTML.read_text(encoding="utf-8")
|
|
marker = "const WORDS_DATA = "
|
|
start = html.find(marker)
|
|
end = html.find(";\n", start)
|
|
if start < 0 or end < 0:
|
|
raise SystemExit("WORDS_DATA markers missing")
|
|
return json.loads(html[start + len(marker) : end])
|
|
|
|
|
|
def _chip(word, by_id_html, items_by_word):
|
|
src = by_id_html[items_by_word[word]["id"]]
|
|
it = items_by_word[word]
|
|
return {
|
|
"id": it["id"],
|
|
"word": word,
|
|
"emoji": src.get("emoji", ""),
|
|
"pos": it["pos"],
|
|
"category": it["cat"],
|
|
"desc": it["desc"],
|
|
}
|
|
|
|
|
|
def _patch_html_maps():
|
|
html = HTML.read_text(encoding="utf-8")
|
|
css = " .badge-system.system-numerology { border-color: rgba(255, 213, 79, 0.45); background: rgba(255, 213, 79, 0.12); color: #fff3c4; }\n"
|
|
anchor = " .badge-system.system-cosmo { border-color: rgba(159, 122, 234, 0.4); background: rgba(159, 122, 234, 0.12); color: #e9d8fd; }\n"
|
|
if "system-numerology" not in html:
|
|
if anchor not in html:
|
|
raise SystemExit("css anchor missing")
|
|
html = html.replace(anchor, anchor + css, 1)
|
|
|
|
sys_row = " { id: 'Нумерология', name: 'Нумерология (Квадрат Пифагора)', icon: '🔢', css: 'system-numerology' },\n { id: 'Матрица', name: '33 ряда Домов', icon: '🏛️', css: 'system-numerology' },\n"
|
|
sys_anchor = " { id: 'Месяцы года', name: 'Додекада (12 Месяцев Года)', icon: '🗓️', css: 'system-months' },\n ];"
|
|
if "{ id: 'Нумерология'" not in html:
|
|
if sys_anchor not in html:
|
|
raise SystemExit("CANONICAL_SYSTEMS anchor missing")
|
|
html = html.replace(
|
|
sys_anchor,
|
|
" { id: 'Месяцы года', name: 'Додекада (12 Месяцев Года)', icon: '🗓️', css: 'system-months' },\n" + sys_row + " ];",
|
|
1,
|
|
)
|
|
|
|
key_anchor = " 'Алхимия': 'alchemy'\n };"
|
|
key_add = " 'Алхимия': 'alchemy',\n 'Нумерология': 'numerology',\n 'Матрица': 'numerology'\n };"
|
|
if "'Нумерология': 'numerology'" not in html:
|
|
if key_anchor not in html:
|
|
raise SystemExit("SYSTEM_TO_CANON_KEY anchor missing")
|
|
html = html.replace(key_anchor, key_add, 1)
|
|
HTML.write_text(html, encoding="utf-8")
|
|
|
|
|
|
def main():
|
|
text, items = load_dart()
|
|
by_word = {it["word"]: it for it in items}
|
|
for row in STATIONS:
|
|
word = row[0]
|
|
if word not in by_word:
|
|
raise SystemExit(f"primary missing: {word}")
|
|
for extra in row[5]:
|
|
if extra not in by_word:
|
|
raise SystemExit(f"cluster missing: {extra}")
|
|
|
|
for word, _sid, name, _group, _symbol, cluster, _lore in STATIONS:
|
|
tag = f"[Нумерология: {name}]"
|
|
by_word[word]["desc"] = ensure_tag(by_word[word]["desc"], tag)
|
|
for extra in cluster:
|
|
by_word[extra]["desc"] = ensure_tag(by_word[extra]["desc"], tag)
|
|
by_word["тридцать три"]["desc"] = ensure_tag(
|
|
by_word["тридцать три"]["desc"],
|
|
"[Матрица: 33 ряда Домов]",
|
|
)
|
|
|
|
html_words = _load_html_words()
|
|
by_html = {w["id"]: w for w in html_words}
|
|
if len(by_html) != 1000:
|
|
raise SystemExit("html words != 1000")
|
|
|
|
stations = []
|
|
for word, sid, name, group, symbol, cluster, lore in STATIONS:
|
|
stations.append(
|
|
{
|
|
"id": sid,
|
|
"name": name,
|
|
"symbol": symbol,
|
|
"group": group,
|
|
"lore": lore,
|
|
"primary": _chip(word, by_html, by_word),
|
|
"cluster": [_chip(w, by_html, by_word) for w in cluster],
|
|
}
|
|
)
|
|
|
|
canon = json.loads(CANON_A.read_text(encoding="utf-8"))
|
|
canon["numerology"] = {
|
|
"id": "numerology",
|
|
"name": "Нумерология и Квадрат Пифагора",
|
|
"icon": "🔢",
|
|
"count": len(stations),
|
|
"description": "Девять ячеек квадрата и три мастер-числа. Код суток свёртывает день, месяц и год по отдельности и оставляет 11, 22 и 33. Управители — числовые слова тысячи.",
|
|
"stations": stations,
|
|
}
|
|
# Refresh chip descriptions from the stamped dictionary.
|
|
for trad in canon.values():
|
|
for st in trad.get("stations", []):
|
|
for node in [st.get("primary")] + list(st.get("cluster") or []):
|
|
if isinstance(node, dict) and node.get("word") in by_word:
|
|
node["desc"] = by_word[node["word"]]["desc"]
|
|
|
|
raw_a = json.dumps(canon, ensure_ascii=False, indent=2) + "\n"
|
|
CANON_A.write_text(raw_a, encoding="utf-8")
|
|
CANON_B.write_text(raw_a, encoding="utf-8")
|
|
|
|
for kb_path in (KB_ASSETS, KB_OUT):
|
|
kb = json.loads(kb_path.read_text(encoding="utf-8"))
|
|
for it in items:
|
|
for key in (it["word"], str(it["id"])):
|
|
entry = kb.get(key)
|
|
if isinstance(entry, dict):
|
|
entry["description"] = it["desc"]
|
|
entry["word"] = it["word"]
|
|
entry["id"] = it["id"]
|
|
kb_path.write_text(json.dumps(kb, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
|
|
write_dart(text, items)
|
|
|
|
for w in html_words:
|
|
it = by_word[w["word"]]
|
|
w["description"] = it["desc"]
|
|
w["pos"] = it["pos"]
|
|
w["category"] = it["cat"]
|
|
embed_html(canon, html_words)
|
|
_patch_html_maps()
|
|
|
|
lexicon = [
|
|
{
|
|
"id": w["id"],
|
|
"word": w["word"],
|
|
"emoji": w.get("emoji", ""),
|
|
"pos": w.get("pos", ""),
|
|
"category": w.get("category", ""),
|
|
}
|
|
for w in sorted(html_words, key=lambda x: x["id"])
|
|
]
|
|
if len({row["word"] for row in lexicon}) != 1000:
|
|
raise SystemExit("lexicon words not unique")
|
|
LEX.write_text(json.dumps(lexicon, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
write_alpha(lexicon)
|
|
print("numerology stations", len(stations))
|
|
print("tagged", by_word["одиннадцать"]["desc"][:80])
|
|
print("matrix", "[Матрица:" in by_word["тридцать три"]["desc"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|