/
hamster75
/
Life
Обзор
Документация
Войти
/
hamster75
/
Life
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
6
CI/CD
Аналитика
Безопасность
site
js/simulation.js
144 строки
4 KB
Dmitry Smirnov
on the road to fix freeze
26 май 2026, 08:04
26 май 2026, 08:04
d56cea3
Код
Авторство
О чём код?
import { markGenAdvanced } from './quest-events.js'; export const SimState = Object.freeze({ STOPPED: 'stopped', RUNNING: 'running', PAUSED: 'paused', }); export class Simulation { constructor(grid, algorithm) { this.grid = grid; this.algorithm = algorithm; this.state = SimState.STOPPED; this.generation = 0; this.intervalMs = 200; this._snapshot = null; this._timerId = null; this._onTickCallbacks = []; this._onStateCallbacks = []; this._onBusyCallbacks = []; } onTick(cb) { this._onTickCallbacks.push(cb); } onState(cb) { this._onStateCallbacks.push(cb); } onBusy(cb) { this._onBusyCallbacks.push(cb); } _notifyTick() { for (const cb of this._onTickCallbacks) cb(this.generation); } _notifyState() { for (const cb of this._onStateCallbacks) cb(this.state); } _notifyBusy(v) { for (const cb of this._onBusyCallbacks) cb(v); } setAlgorithm(algo) { this.stop(); this.algorithm = algo; } play() { if (this.state === SimState.RUNNING) return; if (this.state === SimState.STOPPED) { this._snapshot = this.grid.clone(); this.generation = 0; } this.state = SimState.RUNNING; this._notifyState(); this._scheduleNext(); } pause() { if (this.state !== SimState.RUNNING) return; this._clearTimer(); this.state = SimState.PAUSED; this._notifyState(); } stop() { this._clearTimer(); this.state = SimState.STOPPED; this._notifyState(); } reset() { this._clearTimer(); if (this._snapshot) { this.grid.loadAlive(this._snapshot._alive); } else { this.grid.clear(); } this.generation = 0; this.state = SimState.STOPPED; this._notifyTick(); this._notifyState(); } clear() { this._clearTimer(); this.grid.clear(); this._snapshot = null; this.generation = 0; this.state = SimState.STOPPED; this._notifyTick(); this._notifyState(); } stepOnce() { if (this.state === SimState.RUNNING) return; if (this.state === SimState.STOPPED) { this._snapshot = this.grid.clone(); this.generation = 0; this.state = SimState.PAUSED; this._notifyState(); } if (typeof this.algorithm.stepAsync === 'function') { this._tickAsync(); } else { this._tick(); } } setSpeed(ticksPerSecond) { this.intervalMs = Math.round(1000 / ticksPerSecond); if (this.state === SimState.RUNNING) { this._clearTimer(); this._scheduleNext(); } } _scheduleNext() { this._timerId = setTimeout(() => { if (this.state !== SimState.RUNNING) return; if (typeof this.algorithm.stepAsync === 'function') { // Async: следующий шаг планируется только после завершения текущего. this._tickAsync().then(() => { if (this.state === SimState.RUNNING) this._scheduleNext(); }); } else { this._tick(); this._scheduleNext(); } }, this.intervalMs); } _clearTimer() { if (this._timerId !== null) { clearTimeout(this._timerId); this._timerId = null; } } _tick() { const genCount = this.algorithm.step(this.grid); this.generation += genCount; this._notifyTick(); if (this.generation > 0) markGenAdvanced(); } async _tickAsync() { this._notifyBusy(true); const genCount = await this.algorithm.stepAsync(this.grid); this._notifyBusy(false); this.generation += genCount; this._notifyTick(); if (this.generation > 0) markGenAdvanced(); } }