Skip to content

Commit 59a58b4

Browse files
committed
Fix shuffling locations bugs and update World map to remove invalid locations
1 parent 75b4422 commit 59a58b4

File tree

7 files changed

+36
-25
lines changed

7 files changed

+36
-25
lines changed

api/map/mapHome.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import sendableMap from "../../components/utils/sendableMap.js";
22
import Map from "../../models/Map.js";
33
import User from "../../models/User.js";
44
import officialCountryMaps from '../../public/officialCountryMaps.json' with { type: "json" };
5+
import shuffle from "../../utils/shuffle.js";
56

67
let mapCache = {
78
popular: {
@@ -160,7 +161,7 @@ export default async function handler(req, res) {
160161

161162
// for spotlight randomize the order
162163
if(method === "spotlight") {
163-
response[method] = response[method].sort(() => Math.random() - 0.5);
164+
response[method] = shuffle(response[method]);
164165
}
165166
} else {
166167
// retrieve from db
@@ -208,7 +209,7 @@ export default async function handler(req, res) {
208209
response[method] = sendableMaps;
209210
// if spotlight, randomize the order
210211
if(method === "spotlight") {
211-
response[method] = response[method].sort(() => Math.random() - 0.5);
212+
response[method] = shuffle(response[method]);
212213
}
213214

214215
mapCache[method].data = sendableMaps;

components/home.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useEffect, useState, useRef } from "react";
88
import Navbar from "@/components/ui/navbar";
99
import GameUI from "@/components/gameUI";
1010
import BannerText from "@/components/bannerText";
11+
import shuffle from "@/utils/shuffle";
1112
// findLatLongRandom is dynamically imported when needed to avoid loading Google Maps API on page load
1213
import Link from "next/link";
1314
import MultiplayerHome from "@/components/multiplayerHome";
@@ -2088,7 +2089,7 @@ export default function Home({ }) {
20882089
let options = JSON.parse(JSON.stringify(onboarding.locations[onboarding.round - 1].otherOptions));
20892090
options.push(onboarding.locations[onboarding.round - 1].country)
20902091
// shuffle
2091-
options = options.sort(() => Math.random() - 0.5)
2092+
options = shuffle(options)
20922093
setOtherOptions(options)
20932094
} else {
20942095
async function defaultMethod() {
@@ -2129,8 +2130,11 @@ export default function Home({ }) {
21292130
}
21302131
}
21312132

2132-
// shuffle data.locations
2133-
data.locations = data.locations.sort(() => Math.random() - 0.5)
2133+
// Fisher-Yates shuffle (unbiased)
2134+
for (let i = data.locations.length - 1; i > 0; i--) {
2135+
const j = Math.floor(Math.random() * (i + 1));
2136+
[data.locations[i], data.locations[j]] = [data.locations[j], data.locations[i]];
2137+
}
21342138

21352139

21362140
setAllLocsArray(data.locations)
@@ -2185,24 +2189,18 @@ export default function Home({ }) {
21852189
if ((locIndex === -1) || allLocsArray.length === 1) {
21862190
fetchMethod()
21872191
} else {
2188-
if (gameOptions.location === "all") {
2189-
const loc = allLocsArray[locIndex + 1] ?? allLocsArray[0];
2190-
setLatLong(loc);
2191-
} else {
2192-
// prevent repeats: remove the prev location from the array
2193-
setAllLocsArray((prev) => {
2194-
const newArr = prev.filter((l) => l.lat !== latLong.lat && l.long !== latLong.long)
2195-
2196-
2197-
// community maps are randomized
2198-
const loc = newArr[Math.floor(Math.random() * newArr.length)];
2192+
// prevent repeats: remove the prev location from the array (for both all and community maps)
2193+
setAllLocsArray((prev) => {
2194+
const newArr = prev.filter((l) => l.lat !== latLong.lat || l.long !== latLong.long);
21992195

2196+
// Pick next location
2197+
const loc = gameOptions.location === "all"
2198+
? newArr[0] // World map: take first from shuffled remaining
2199+
: newArr[Math.floor(Math.random() * newArr.length)]; // Community: random
22002200

2201-
setLatLong(loc);
2202-
return newArr;
2203-
})
2204-
2205-
}
2201+
setLatLong(loc);
2202+
return newArr;
2203+
})
22062204
}
22072205

22082206
}

cron.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ app.get('/clueCountries.json', (req, res) => {
595595
if (clueLocations.length === 0) {
596596
return res.json({ ready: false });
597597
} else {
598-
return res.json({ ready: true, locations: clueLocations.sort(() => Math.random() - 0.5) });
598+
return res.json({ ready: true, locations: shuffle([...clueLocations]) });
599599
}
600600
});
601601

public/world-main.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import countries from './public/countries.json' with { type: "json" };
3131

3232
// colors
3333
import colors from 'colors';
34+
import shuffle from './utils/shuffle.js';
3435

3536
// express
3637
import express from 'express';
@@ -212,7 +213,7 @@ app.get('/countryLocations/:country', (req, res) => {
212213
} else {
213214

214215
if( rawOverrides[req.params.country]) {
215-
countryLocations[req.params.country].locations = rawOverrides[req.params.country].customCoordinates.sort(() => Math.random() - 0.5).slice(0, 1000).map(loc => {
216+
countryLocations[req.params.country].locations = shuffle(rawOverrides[req.params.country].customCoordinates).slice(0, 1000).map(loc => {
216217
return {
217218
lat: loc.lat,
218219
long: loc.lng,

utils/shuffle.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Fisher-Yates shuffle (unbiased)
2+
// Returns a new shuffled array without modifying the original
3+
export default function shuffle(arr) {
4+
const result = [...arr];
5+
for (let i = result.length - 1; i > 0; i--) {
6+
const j = Math.floor(Math.random() * (i + 1));
7+
[result[i], result[j]] = [result[j], result[i]];
8+
}
9+
return result;
10+
}

ws/classes/Game.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { setElo } from "../../api/eloRank.js";
1515
import GameModel from "../../models/Game.js";
1616
import User from "../../models/User.js";
1717
import UserStatsService from "../../components/utils/userStatsService.js";
18+
import shuffle from "../../utils/shuffle.js";
1819

1920
export default class Game {
2021
constructor(id, publicLobby, location="all", rounds=5, allLocations, isDuel=false) {
@@ -611,7 +612,7 @@ export default class Game {
611612
key: 'notEnoughLocationsInMap'
612613
});
613614
}
614-
locs = locs.sort(() => Math.random() - 0.5).slice(0, this.rounds).map((loc) => ({
615+
locs = shuffle(locs).slice(0, this.rounds).map((loc) => ({
615616
// lng -> long
616617
...loc,
617618
long: loc.lng,

0 commit comments

Comments
 (0)