44 lines
2.2 KiB
JavaScript
44 lines
2.2 KiB
JavaScript
// Спільні правила гри: коли доказ досяжний, кого пускають у квартиру, кого
|
||
// лишили в колі підозри. Одні й ті самі правила ганяє 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 };
|