feat(trainer): уровни сложности заданий (Лёгкий/Средний/Сложный + Авто)

- движок: instantiate(gen,{level}) масштабирует диапазоны pick (_scaleRange): L2=база, L1 меньше магнитуды/меньше отрицательных, L3 шире → сложнее; универсально для всех генераторов (корень-вперёд + самопроверка держат корректность), opt-out gen.noScale; generateBatch прокидывает level
- страница: контрол «Сложность: Авто / Лёгкий / Средний / Сложный» в рабочей зоне; «Авто» поднимает уровень с серией верных (streak≥2→2, ≥4→3, ошибка→1); скрыт для текстовых задач из банка
- смоук движка 682/682 (T18: 36 ген × L1/L2/L3, L3 шире L1, L2==база), страница 34/34; эмодзи/eval 0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-25 16:10:28 +03:00
parent 6eaf68a158
commit d07cb2a434
3 changed files with 65 additions and 3 deletions
+22 -2
View File
@@ -68,6 +68,24 @@
}
function randInt(rng, lo, hi) { return lo + Math.floor(rng() * (hi - lo + 1)); }
/* ── Уровни сложности: масштабирование диапазона pick ──
level 2 — базовый (как задано); 1 — легче (меньше магнитуды, меньше
отрицательных); 3 — сложнее (шире магнитуды). Универсально для всех
генераторов; корректность держит «корень-вперёд» + самопроверка. */
function _scaleRange(r, level) {
var lo = r[0], hi = r[1];
if (!level || level === 2) return [lo, hi];
if (level === 1) {
var nlo = lo < 0 ? Math.ceil(lo / 2) : lo;
var nhi = hi > 0 ? Math.max(nlo + 1, Math.round(hi / 2)) : hi;
return [nlo, nhi];
}
var elo = lo < 0 ? Math.floor(lo * 1.8) : lo;
var ehi = Math.round(hi * 1.8);
if (ehi <= elo) ehi = elo + 1;
return [elo, ehi];
}
/* ── Кэш компиляции выражений (рендеренные строки часто повторяются) ── */
var _cache = Object.create(null);
function compileExpr(src) {
@@ -245,8 +263,10 @@
for (var attempt = 0; attempt < maxTries; attempt++) {
var env = {};
var pk = gen.pick || {}, k;
var lvl = opts.level;
for (k in pk) if (Object.prototype.hasOwnProperty.call(pk, k)) {
env[k] = randInt(rng, pk[k][0], pk[k][1]);
var rk = (lvl && !gen.noScale) ? _scaleRange(pk[k], lvl) : pk[k];
env[k] = randInt(rng, rk[0], rk[1]);
}
if (gen.constraint && !truthy(evalExpr(gen.constraint, env))) continue;
@@ -354,7 +374,7 @@
var out = [], seen = Object.create(null);
var guard = n * 20 + 50;
while (out.length < n && guard-- > 0) {
var p = instantiate(gen, { rng: rng, strict: opts.strict, maxTries: opts.maxTries });
var p = instantiate(gen, { rng: rng, strict: opts.strict, maxTries: opts.maxTries, level: opts.level });
if (!p) break;
if (seen[p.display]) continue;
seen[p.display] = 1;