// /src/state/runStore.js export const runStore = { params: { N: 100, speed: 1.0, seed: 1234 }, metrics: { totalDistance: 0, steps: 0, timeElapsed: 0, energy: 0 }, pointsCollected: 0, points: [], // array of {x, y, collected: bool} order: [], // order in which visitar (índices) botPath: [], // punto por punto que sigue (incluye inicio) startRun(params) { this.params = { ...this.params, ...params }; this.resetMetrics(); this._initPoints(); this._computeOrder(); this.botPath = [this._startPosition()]; }, resetRun() { this.metrics = { totalDistance: 0, steps: 0, timeElapsed: 0, energy: 0 }; this.pointsCollected = 0; this.points.forEach(p => p.collected = false); this.order = []; this.botPath = []; }, exportJSON() { return JSON.stringify({ params: this.params, metrics: this.metrics, pointsCollected: this.pointsCollected, order: this.order, points: this.points }, null, 2); }, _initPoints() { const { N, seed } = this.params; this.points = []; const rng = mulberry32(seed); for (let i = 0; i < N; i++) { this.points.push({ x: rng() * 1, // normalizar al espacio unitario [0,1] y: rng() * 1, collected: false }); } }, _startPosition() { return { x: 0, y: 0 }; }, _computeOrder() { // greedy nearest neighbor en espacio unitario const pts = this.points; const visited = new Set(); let cur = this._startPosition(); this.order = []; for (let i = 0; i < pts.length; i++) { let bestIdx = -1; let bestD = Infinity; pts.forEach((p, idx) => { if (visited.has(idx)) return; const dx = p.x - cur.x, dy = p.y - cur.y; const d = dx*dx + dy*dy; if (d < bestD) { bestD = d; bestIdx = idx; } }); if (bestIdx < 0) break; visited.add(bestIdx); this.order.push(bestIdx); cur = { x: pts[bestIdx].x, y: pts[bestIdx].y }; } }, recordStep(from, to) { const dx = to.x - from.x, dy = to.y - from.y; const dist = Math.hypot(dx, dy); this.metrics.totalDistance += dist; this.metrics.steps += 1; // tiempo se puede acumular externo this.botPath.push({ x: to.x, y: to.y }); }, markCollected(idx) { this.points[idx].collected = true; this.pointsCollected += 1; }, finalize(timeElapsedSec, energyFactor = 1.0) { this.metrics.timeElapsed = timeElapsedSec; this.metrics.energy = this.metrics.totalDistance * energyFactor; } }; // PRNG auxiliar (por reproducibilidad) function mulberry32(a) { return function() { var t = a += 0x6D2B79F5; t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; } }