feat: split metro and tram
All checks were successful
deploy to cloudflare pages / deploy (push) Successful in 33s

This commit is contained in:
uku 2024-11-21 22:40:51 +01:00
parent 98967bc491
commit a2c27899f7
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
7 changed files with 69 additions and 58 deletions

View file

@ -46,17 +46,21 @@ export async function saveScore(
scoreCalc: (dist: number) => number,
db: D1Database,
): Promise<CheckResponse | null> {
const stop = await findStopByName(stopName);
if (stop === null) return null;
const row = await db
.prepare("SELECT id, game_id, stop_name, points FROM round WHERE game_id = ? AND stop_name = ?")
.prepare(
"SELECT round.id, round.stop_name, round.points, game.stops_type FROM round INNER JOIN game ON game.id = round.game_id WHERE round.game_id = ? AND round.stop_name = ?",
)
.bind(uuid, stopName)
.first();
if (row === null || row.points !== -1) return null;
const coords = (stop.geometry as GeoJSON.Point).coordinates;
const type = row.stops_type as "metro" | "tram";
const stops = (await getMergedStops(type)).filter((f) => f.properties?.nom === stopName);
if (stops.length === 0) return null;
const coords = (stops[0].geometry as GeoJSON.Point).coordinates;
const latlng: [number, number] = [coords[1], coords[0]];
const distance = Math.round(distanceCalc(latlng));
@ -102,6 +106,21 @@ export async function getTram(): Promise<[GeoJSON.Feature, string][]> {
return lazyTram;
}
async function getLineCodes(stopsType: "metro" | "tram"): Promise<Set<string>> {
let lines;
switch (stopsType) {
case "metro":
lines = await getMetro();
break;
case "tram":
lines = await getTram();
break;
}
return new Set<string>(lines.map(([f]) => f.properties!.code_ligne));
}
async function getStops(): Promise<GeoJSON.Feature[]> {
if (!lazyStops) {
const stops: GeoJSON.FeatureCollection = await fetch(stopsUrl).then((r) => r.json());
@ -111,8 +130,9 @@ async function getStops(): Promise<GeoJSON.Feature[]> {
return lazyStops;
}
export async function getMergedStops(lineCodes: Set<string>): Promise<GeoJSON.Feature[]> {
export async function getMergedStops(stopsType: "metro" | "tram"): Promise<GeoJSON.Feature[]> {
const stops = await getStops();
const lineCodes = await getLineCodes(stopsType);
const crossingStops = stops.filter((f) => {
if (f.properties?.desserte) {
@ -129,48 +149,40 @@ export async function getMergedStops(lineCodes: Set<string>): Promise<GeoJSON.Fe
const mergedStops = Array.from(new Set(crossingStops.map((f) => f.properties?.nom))).map(
(nom) => {
const matching = crossingStops.filter((f) => f.properties?.nom === nom);
return mergeStops(matching)!;
const longs = matching.map((f) => (f.geometry as GeoJSON.Point).coordinates[0]);
const lonAvg = longs.reduce((a, b) => a + b) / longs.length;
const lats = matching.map((f) => (f.geometry as GeoJSON.Point).coordinates[1]);
const latAvg = lats.reduce((a, b) => a + b) / lats.length;
const desserte = matching.map((f) => f.properties?.desserte).join(",");
const feature: GeoJSON.Feature = {
...matching[0],
geometry: { type: "Point", coordinates: [lonAvg, latAvg] },
properties: { ...matching[0].properties, desserte },
};
return feature;
},
);
return mergedStops;
}
async function findStopByName(name: string): Promise<GeoJSON.Feature | null> {
const stops = await getStops();
return mergeStops(stops.filter((f) => f.properties?.nom === name));
}
function mergeStops(stops: GeoJSON.Feature[]): GeoJSON.Feature | null {
if (stops.length === 0) return null;
const longs = stops.map((f) => (f.geometry as GeoJSON.Point).coordinates[0]);
const lonAvg = longs.reduce((a, b) => a + b) / longs.length;
const lats = stops.map((f) => (f.geometry as GeoJSON.Point).coordinates[1]);
const latAvg = lats.reduce((a, b) => a + b) / lats.length;
const desserte = stops.map((f) => f.properties?.desserte).join(",");
const feature = stops[0];
feature.geometry = { type: "Point", coordinates: [lonAvg, latAvg] };
if (feature.properties) feature.properties.desserte = desserte;
return feature;
}
export function parseOptions(url: URL): GameOptions {
const mode = url.searchParams.get("mode");
if (mode !== "easy" && mode !== "hard" && mode !== "extreme demon ultra miguel") {
error(400, "gamemode is invalid");
}
return {
mode,
metro: url.searchParams.has("metro"),
tram: url.searchParams.has("tram"),
};
const stopsType = url.searchParams.get("stops_type");
if (stopsType !== "metro" && stopsType !== "tram") {
error(400, "stops_type is invalid");
}
return { mode, stopsType };
}
// https://underscorejs.org/docs/modules/sample.html

View file

@ -1,7 +1,6 @@
export interface GameOptions {
mode: "easy" | "hard" | "extreme demon ultra miguel";
metro: boolean;
tram: boolean;
stopsType: "metro" | "tram";
}
export interface MapData {

View file

@ -33,10 +33,12 @@
</select>
</label>
<div>
<label>metro: <input type="checkbox" name="metro" checked /></label>
<label>tram: <input type="checkbox" name="tram" /></label>
</div>
<label>
arrets: <select name="stops_type">
<option value="metro">Métro</option>
<option value="tram">Tram</option>
</select>
</label>
<input type="submit" value="LANCER LA PARTIE" />
</form>

View file

@ -1,6 +1,6 @@
import { error } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import { createGame, getMergedStops, getMetro, getTram, parseOptions, sample } from "$lib";
import { createGame, getMergedStops, parseOptions, sample } from "$lib";
export const GET: RequestHandler = async ({ url, platform, locals }) => {
const db = platform?.env?.TCL_GUESSR_D1 ?? null;
@ -10,13 +10,8 @@ export const GET: RequestHandler = async ({ url, platform, locals }) => {
if (user === null) error(401, "not logged in");
const options = parseOptions(url);
const lineColors: [GeoJSON.Feature, string][] = [];
if (options.metro) lineColors.push(...(await getMetro()));
if (options.tram) lineColors.push(...(await getTram()));
const lineCodes = new Set<string>(lineColors.map(([f]) => f.properties!.code_ligne));
const crossingStops = await getMergedStops(lineCodes);
const crossingStops = await getMergedStops(options.stopsType);
const randomStops = sample(crossingStops, 5);
if (!randomStops) {

View file

@ -7,16 +7,17 @@ export const GET: RequestHandler = async ({ url }) => {
const mapData: MapData = { lines: [], stops: [] };
if (options.mode !== "extreme demon ultra miguel") {
const lineColors: [GeoJSON.Feature, string][] = [];
if (options.metro) lineColors.push(...(await getMetro()));
if (options.tram) lineColors.push(...(await getTram()));
mapData.lines = lineColors;
switch (options.stopsType) {
case "metro":
mapData.lines = await getMetro();
break;
case "tram":
mapData.lines = await getTram();
break;
}
if (options.mode === "easy") {
const lineCodes = new Set<string>(lineColors.map(([f]) => f.properties!.code_ligne));
const crossingStops = await getMergedStops(lineCodes);
const crossingStops = await getMergedStops(options.stopsType);
const strippedStops: [number, number][] = crossingStops.map((f) => {
const coords = (f.geometry as GeoJSON.Point).coordinates;

View file

@ -1,12 +1,12 @@
<script lang="ts">
import type { CheckData, CheckResponse, ClientGameData, MapData } from "$lib/types";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
import { goto } from "$app/navigation";
const zoom = 13;
const center: [number, number] = [45.742858495, 4.86163814];