Add the blind-reading emitter for this panel and record the role-prompt reading verdict
This commit is contained in:
parent
273d2df41f
commit
eb49b651d4
1 changed files with 112 additions and 0 deletions
|
|
@ -573,6 +573,113 @@ def cmd_selftest() -> int:
|
||||||
return bad
|
return bad
|
||||||
|
|
||||||
|
|
||||||
|
# ── СЛЕПОЕ ЧТЕНИЕ ПАНЕЛИ ЭТОГО ЗАМЕРА ────────────────────────────────────────────────────────
|
||||||
|
# ⚠ ПЕРВИЧНЫЙ ПРИБОР КОНТРАСТА — ЧТЕНИЕ, А НЕ СЧЁТ (решение владельца 20.08). Основание замерено:
|
||||||
|
# счётчик ошибок согласен с владельцем на китайской паре (+0.80) и АНТИ-согласен на английской
|
||||||
|
# (−0.80), а слепое чтение — +0.80 на обеих. Всё, что новый промт меняет (вольность, регистр),
|
||||||
|
# лежит ровно в осях, к которым счётчик слеп, поэтому судить им этот контраст значит гарантированно
|
||||||
|
# получить «неотличимо» и не понять, эффекта нет или прибора нет.
|
||||||
|
# ⚠ РАМКА ПАКЕТА НЕЙТРАЛЬНА. Норма, заведённая 20.08 после того, как я нашёл подсказку в СВОЁМ же
|
||||||
|
# пакете («вариант с наименьшим числом ошибок читался почти хуже всех»): пакет не имеет права
|
||||||
|
# называть читателю ни вердикт другого прибора, ни существование контроля. Замер показал, что
|
||||||
|
# подсказка стоила 0.20 Спирмена — верх и низ порядка устояли, но средние места переставились.
|
||||||
|
# ⚠ Перетасовка меток берётся у `chtenie.layout` — второй реализации того же не заводится.
|
||||||
|
CH = _load("chtenie_r", ZONE / "chtenie.py")
|
||||||
|
READ_SALT = "rol-2026-08-20"
|
||||||
|
READ_PANEL = ("ZP", "RN", "Z0", "ZF") # склейка · новая роль · боевая связка · её 2-я генерация
|
||||||
|
READ_DIR = Path.home() / "books" / "chtenie-rol"
|
||||||
|
READ_KEY = OUT / "blind-keys-rol" / "rol-KEY.json"
|
||||||
|
READ_HEAD = """
|
||||||
|
Ниже {n} перевода одного и того же отрывка, сделанных разными способами. Какой чем сделан — не
|
||||||
|
сказано намеренно, метки перемешаны, расшифровка лежит отдельно и до твоего ответа не открывается.
|
||||||
|
Метки сквозные: `Т1` в первом отрывке и `Т1` во втором — один и тот же способ.
|
||||||
|
|
||||||
|
Твоя задача одна: **расставить варианты по тому, какой ты взял бы в книгу** — как русскую
|
||||||
|
художественную прозу, при условии что смысл исходника не переврали. Исходник приложен.
|
||||||
|
|
||||||
|
## Что записать — в файл `{answer}`
|
||||||
|
|
||||||
|
1. **ПОРЯДОК** — строкой: `Т3 > Т1 > Т2 > Т4`, от лучшего к худшему. Неразличимые соединяй `=`.
|
||||||
|
2. **По фразе на вариант**: почему.
|
||||||
|
|
||||||
|
Если какой-то вариант покажется откровенно машинным — скажи прямо.
|
||||||
|
|
||||||
|
---
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def read_texts(p: str, uid: str) -> dict:
|
||||||
|
"""Тексты панели чтения. Пусто у любого арма — глава в пакет не идёт целиком."""
|
||||||
|
out = {"_src": next(u["source"] for u in chosen(p) if u["uid"] == uid)}
|
||||||
|
for a in READ_PANEL:
|
||||||
|
t = free_text(p, a, uid) if a in FREE else (
|
||||||
|
cell(tag(p, a, uid)) if a in ARMS else ZK.cell(ZK.tag(p, a, uid)))
|
||||||
|
out[a] = t
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def emit_read(p: str, n_units: int = 3) -> None:
|
||||||
|
"""Пакет слепого чтения: ключ пишется ДО ответов, раскладка ОДНА на пару."""
|
||||||
|
cfg = PAIRS[p]
|
||||||
|
cfg["wire"]()
|
||||||
|
full = []
|
||||||
|
for u in chosen(p):
|
||||||
|
tx = read_texts(p, u["uid"])
|
||||||
|
if all(tx[a].strip() for a in READ_PANEL):
|
||||||
|
full.append((u["uid"], tx))
|
||||||
|
full.sort(key=lambda x: -sum(len(x[1][a]) for a in READ_PANEL))
|
||||||
|
take = full[:n_units]
|
||||||
|
if not take:
|
||||||
|
raise SystemExit(f"⛔ у пары {p} нет ни одной главы с ПОЛНОЙ панелью {READ_PANEL}")
|
||||||
|
READ_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
READ_KEY.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
key = json.loads(READ_KEY.read_text(encoding="utf-8")) if READ_KEY.exists() else {
|
||||||
|
"_что": "слепое чтение панели замера «однопроходка как роль»",
|
||||||
|
"_соль": READ_SALT, "_панель": list(READ_PANEL),
|
||||||
|
"_контроль": "Z0 и ZF — две генерации ОДНОЙ боевой связки"}
|
||||||
|
ans = READ_DIR / f"ОТВЕТ-{p}.md"
|
||||||
|
lay = CH.layout(p, f"ROL-ALL|{READ_SALT}", "READER", READ_PANEL)
|
||||||
|
body = [f"# {'КИТАЙСКАЯ' if p == 'zh' else 'АНГЛИЙСКАЯ'} ПАРА — слепое чтение\n",
|
||||||
|
READ_HEAD.format(n=len(READ_PANEL), answer=ans)]
|
||||||
|
for j, (uid, tx) in enumerate(take, 1):
|
||||||
|
body += [f"\n# ОТРЫВОК {j}\n",
|
||||||
|
f"## Исходник ({'китайский' if p == 'zh' else 'английский'})\n", tx["_src"], ""]
|
||||||
|
for lab, arm in lay.items():
|
||||||
|
body += ["\n---\n", f"## Отрывок {j}, вариант {lab}\n", tx[arm], ""]
|
||||||
|
key.setdefault(p, {})[str(j)] = {"uid": uid, "метки": lay,
|
||||||
|
"знаков": {a: len(tx[a]) for a in READ_PANEL}}
|
||||||
|
(READ_DIR / f"ЧТЕНИЕ-{p}.md").write_text("\n".join(body), encoding="utf-8")
|
||||||
|
if not ans.exists():
|
||||||
|
ans.write_text(f"# Ответ — пара {p}\n\nПОРЯДОК: \n\nПо вариантам:\n", encoding="utf-8")
|
||||||
|
READ_KEY.write_text(json.dumps(key, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||||
|
print(f" {p}: глав {len(take)} · вариантов {len(READ_PANEL)} · "
|
||||||
|
f"{sum(len(tx[a]) for _u, tx in take for a in READ_PANEL) // 1000} тыс. знаков")
|
||||||
|
print(f" пакет → {READ_DIR / f'ЧТЕНИЕ-{p}.md'} · ключ → {READ_KEY} (читателю НЕ давать)")
|
||||||
|
|
||||||
|
|
||||||
|
def score_read() -> None:
|
||||||
|
if not READ_KEY.exists():
|
||||||
|
raise SystemExit("⛔ ключа нет — сначала --emit-read")
|
||||||
|
key = json.loads(READ_KEY.read_text(encoding="utf-8"))
|
||||||
|
import re as _re # noqa: PLC0415
|
||||||
|
for p in PAIRS:
|
||||||
|
f = READ_DIR / f"ОТВЕТ-{p}.md"
|
||||||
|
if not f.exists() or p not in key:
|
||||||
|
continue
|
||||||
|
txt = f.read_text(encoding="utf-8", errors="replace")
|
||||||
|
seen: list[str] = []
|
||||||
|
for x in _re.findall(r"Т\d+", txt):
|
||||||
|
if x not in seen:
|
||||||
|
seen.append(x)
|
||||||
|
lay = key[p]["1"]["метки"]
|
||||||
|
order = [lay[x] for x in seen if x in lay]
|
||||||
|
if len(order) < len(READ_PANEL):
|
||||||
|
print(f" {p}: порядок не разобран ({seen})")
|
||||||
|
continue
|
||||||
|
print(f" {p}: {' > '.join(order)}")
|
||||||
|
print(f" контроль шума Z0/ZF на местах {order.index('Z0') + 1} и {order.index('ZF') + 1}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
a = sys.argv[1:] or ["--dry"]
|
a = sys.argv[1:] or ["--dry"]
|
||||||
if a[0] == "--selftest":
|
if a[0] == "--selftest":
|
||||||
|
|
@ -583,6 +690,11 @@ if __name__ == "__main__":
|
||||||
cmd_show(next((x for x in a[1:] if x in PAIRS), "zh"))
|
cmd_show(next((x for x in a[1:] if x in PAIRS), "zh"))
|
||||||
elif a[0] == "--canon":
|
elif a[0] == "--canon":
|
||||||
canon()
|
canon()
|
||||||
|
elif a[0] == "--emit-read":
|
||||||
|
for x in ([y for y in a[1:] if y in PAIRS] or list(PAIRS)):
|
||||||
|
emit_read(x)
|
||||||
|
elif a[0] == "--score-read":
|
||||||
|
score_read()
|
||||||
elif a[0] == "--coverage":
|
elif a[0] == "--coverage":
|
||||||
for p in ([x for x in a[1:] if x in PAIRS] or list(PAIRS)):
|
for p in ([x for x in a[1:] if x in PAIRS] or list(PAIRS)):
|
||||||
print(f"\n=== ПОКРЫТИЕ БОЕВЫХ ПРОМТОВ, пара {p} ===")
|
print(f"\n=== ПОКРЫТИЕ БОЕВЫХ ПРОМТОВ, пара {p} ===")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue