2PlayerGame/detective-game/casegen/runtime.js
2026-08-15 14:07:39 +03:00

44 lines
2.2 KiB
JavaScript
Raw 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 тест (solve)
// і живий сервер — розійтися вони не можуть.
function newState() {
return { found: [], identity: false, keys: [], warrants: [], filters: [], pointed: [], puzzlesSolved: [] };
}
function candidates(cs, st) {
return cs.citizens.filter(c => c.id !== cs.victim && st.filters.every(f =>
f.tol ? Math.abs(c[f.attr] - f.val) <= f.tol : c[f.attr] === f.val));
}
// Чи можна увійти в приватне житло
function unitAccess(cs, st, unit) {
if (st.keys.includes(unit)) return true;
const victim = cs.citizens.find(c => c.id === cs.victim);
if (unit === victim.home && st.identity) return true; // житло жертви — після ідентифікації
return cs.citizens.some(c => c.home === unit && st.warrants.includes(c.id));
}
// Чи досяжний доказ за поточного стану. opts.ignorePuzzles — для симулятора.
function available(cs, st, ev, opts = {}) {
// «сплячі» докази (зламане алібі) відкриває лише сервер за фактом суперечності
if (ev.special === 'alibi') return false;
if (ev.requires.some(id => !st.found.includes(id))) return false;
if (ev.needsIdentity && !st.identity) return false;
if (ev.puzzle && !opts.ignorePuzzles && !st.puzzlesSolved.includes(ev.puzzle)) return false;
if (ev.at.type === 'unit') return unitAccess(cs, st, ev.at.unit);
return true; // start / spot / person / sys / lab — гейти вище
}
// Застосувати наслідки знайденого доказу
function applyFound(cs, st, ev) {
if (st.found.includes(ev.id)) return;
st.found.push(ev.id);
const g = ev.gives;
if (g.identity) st.identity = true;
if (g.key && !st.keys.includes(g.key)) st.keys.push(g.key);
if (g.filter) st.filters.push(g.filter);
if (g.pointsTo && !st.pointed.includes(g.pointsTo)) st.pointed.push(g.pointsTo);
}
module.exports = { newState, candidates, unitAccess, available, applyFound };