Spaces:
Running
Running
| // Demonstrate territory takeover: a second runner runs through PART of the | |
| // Demo Runner's territory; those cells should flip to the new owner while the | |
| // rest stay with Demo. Prints a before/after ownership summary. | |
| const h3 = require('h3-js'); | |
| const API = 'http://localhost:5000/api'; | |
| const CENTER = { lat: 17.3955, lng: 78.4400 }; | |
| const RES = 9; | |
| const BBOX = { sw_lat: 17.388, sw_lng: 78.432, ne_lat: 17.403, ne_lng: 78.448 }; | |
| const jget = async (path, token) => | |
| (await fetch(`${API}${path}`, { headers: { Authorization: `Bearer ${token}` } })).json(); | |
| async function login(email, password) { | |
| const r = await fetch(`${API}/auth/login`, { | |
| method: 'POST', headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ email, password }), | |
| }); | |
| if (!r.ok) return null; | |
| return (await r.json()).token; | |
| } | |
| async function ownersInBbox(token) { | |
| const q = `?sw_lat=${BBOX.sw_lat}&sw_lng=${BBOX.sw_lng}&ne_lat=${BBOX.ne_lat}&ne_lng=${BBOX.ne_lng}`; | |
| const { cells } = await jget(`/territory${q}`, token); | |
| const by = {}; | |
| for (const c of cells) by[c.id] = c.ownerName || c.ownerUserId; | |
| return by; | |
| } | |
| (async () => { | |
| try { | |
| // 1. Demo owns the territory | |
| const demoToken = await login('demo@bolt.run', 'password123'); | |
| const before = await ownersInBbox(demoToken); | |
| console.log(`\nBEFORE: ${Object.keys(before).length} cells in view`); | |
| const beforeCounts = {}; | |
| Object.values(before).forEach((o) => { beforeCounts[o] = (beforeCounts[o] || 0) + 1; }); | |
| console.log(' owners:', beforeCounts); | |
| // 2. Create a rival runner (fresh account) | |
| const rivalEmail = `rival+${Math.floor(Math.random() * 100000)}@bolt.run`; | |
| const regRes = await fetch(`${API}/auth/register`, { | |
| method: 'POST', headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ name: 'Rival Runner', email: rivalEmail, password: 'password123' }), | |
| }); | |
| const rivalToken = (await regRes.json()).token; | |
| // 3. Rival runs through the center cell + its immediate ring (7 cells) β | |
| // a partial incursion into Demo's ~20-cell territory. | |
| const centerCell = h3.latLngToCell(CENTER.lat, CENTER.lng, RES); | |
| const incursion = h3.gridDisk(centerCell, 1); // 7 cells | |
| const route = incursion.map((c) => { const [lat, lng] = h3.cellToLatLng(c); return { latitude: lat, longitude: lng }; }); | |
| const runRes = await fetch(`${API}/runs`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${rivalToken}` }, | |
| body: JSON.stringify({ | |
| title: 'Rival incursion', | |
| started_at: new Date(Date.now() - 600000).toISOString(), | |
| ended_at: new Date().toISOString(), | |
| duration_sec: 600, | |
| distance_km: 1.5, | |
| route, | |
| start_lat: route[0].latitude, start_lng: route[0].longitude, | |
| end_lat: route[route.length - 1].latitude, end_lng: route[route.length - 1].longitude, | |
| }), | |
| }); | |
| const runBody = await runRes.json(); | |
| console.log(`\nRival ran through ${incursion.length} cells β cellsCaptured: ${runBody.cellsCaptured}`); | |
| // 4. After | |
| const after = await ownersInBbox(rivalToken); | |
| const afterCounts = {}; | |
| Object.values(after).forEach((o) => { afterCounts[o] = (afterCounts[o] || 0) + 1; }); | |
| console.log(`\nAFTER: ${Object.keys(after).length} cells in view`); | |
| console.log(' owners:', afterCounts); | |
| const flipped = Object.keys(before).filter((id) => before[id] !== after[id]); | |
| console.log(`\nFlipped ${flipped.length} cells from Demo Runner -> Rival Runner. The rest stayed Demo's.`); | |
| console.log('Takeover on overlap: WORKS β '); | |
| process.exit(0); | |
| } catch (err) { | |
| console.error(err); | |
| process.exit(1); | |
| } | |
| })(); | |