2PlayerGame/chapter1/test.js
2026-07-23 17:03:26 +03:00

54 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Fair-play перевірка кейса: node test.js
const assert = require('assert');
const { CASE, checkAccusation } = require('./case.js');
// 1. Кожен доказ досяжний рівно одним джерелом (spot / query / topic.gives)
const sources = {};
for (const l of CASE.locations) for (const sp of l.spots) if (sp.ev) (sources[sp.ev] ??= []).push('spot:' + sp.id);
for (const s of CASE.systems) for (const q of s.queries) if (q.ev) (sources[q.ev] ??= []).push('query:' + q.id);
for (const p of Object.values(CASE.people)) for (const t of p.topics) if (t.gives) (sources[t.gives] ??= []).push('topic:' + t.id);
for (const id of Object.keys(CASE.evidence))
assert(sources[id]?.length === 1, `evidence "${id}" має ${sources[id]?.length || 0} джерел`);
for (const id of Object.keys(sources))
assert(CASE.evidence[id], `джерело посилається на неіснуючий доказ "${id}"`);
// 2. Роль джерела збігається з роллю доказу
for (const l of CASE.locations) for (const sp of l.spots) if (sp.ev) assert(CASE.evidence[sp.ev].role === 'field');
for (const s of CASE.systems) for (const q of s.queries) if (q.ev) assert(CASE.evidence[q.ev].role === 'analyst');
// 3. Усі requires існують і досяжні без циклів (симуляція повного проходження)
const allReq = [];
for (const ev of Object.values(CASE.evidence)) if (ev.requires) allReq.push(...ev.requires);
for (const p of Object.values(CASE.people)) for (const t of p.topics) if (t.requires) allReq.push(...t.requires);
for (const r of allReq) assert(CASE.evidence[r], `requires посилається на неіснуючий доказ "${r}"`);
const pinned = new Set();
let progress = true;
while (progress) {
progress = false;
const ok = req => !req || req.every(r => pinned.has(r));
for (const l of CASE.locations) for (const sp of l.spots)
if (sp.ev && !pinned.has(sp.ev)) { pinned.add(sp.ev); progress = true; }
for (const s of CASE.systems) for (const q of s.queries)
if (q.ev && !pinned.has(q.ev) && ok(q.requires ?? CASE.evidence[q.ev].requires)) { pinned.add(q.ev); progress = true; }
for (const p of Object.values(CASE.people)) for (const t of p.topics)
if (t.gives && !pinned.has(t.gives) && ok(t.requires)) { pinned.add(t.gives); progress = true; }
}
for (const id of Object.keys(CASE.evidence)) assert(pinned.has(id), `доказ "${id}" недосяжний (deadlock у requires)`);
// 4. Звинувачення: правильна комбінація виграє
assert(checkAccusation('elena', 'push', ['override_log', 'guard', 'entry_log', 'fabric']).ok);
assert(checkAccusation('elena', 'push', ['print_match', 'elena_lie', 'struggle']).ok);
// 5. Кожна зламана ланка дає осмислену підказку, а не перемогу
assert(!checkAccusation('rook', 'push', ['override_log', 'guard', 'entry_log', 'fabric']).ok);
assert(!checkAccusation('elena', 'poison', ['override_log', 'guard', 'entry_log', 'fabric']).ok);
assert(!checkAccusation('elena', 'push', ['guard', 'entry_log', 'fabric']).ok); // без способу
assert(!checkAccusation('elena', 'push', ['override_log', 'guard', 'fabric']).ok); // суперечність неповна
assert(!checkAccusation('elena', 'push', ['override_log', 'guard', 'entry_log']).ok); // без контакту
for (const bad of [['rook','push'],['elena','poison']].map(([s,m]) => checkAccusation(s, m, [])))
assert(bad.hint && bad.hint.length > 10);
// 6. Ключове протиріччя вимагає обох ролей
assert(CASE.evidence.guard.role === 'field' && CASE.evidence.entry_log.role === 'analyst');
console.log('OK — кейс розв\'язний, fair-play дотримано.');