Spaces:
Running
Running
| // /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; | |
| } | |
| } | |