mirror of
https://github.com/tiennm99/vngeoguessr.git
synced 2026-10-20 00:15:57 +00:00
refactor(lib): split game.js into scoring and username modules
Extract username generation into a dedicated module, simplify game.js to focus on round scoring logic, and update consumers accordingly.
This commit is contained in:
1 parent
3177e70e67
commit
9133a3efc2
4 files changed
+43
-37
No files matched your search
@@ -3,7 +3,20 @@
|
||||
import { Medal } from 'lucide-react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { formatDistance, getDistanceColor } from '../../lib/game';
|
||||
import { formatDistance, calculateScore } from '../../lib/game';
|
||||
|
||||
// Keyed by the round score the distance would earn, so the tint tracks the
|
||||
// scoring ladder instead of re-typing its thresholds.
|
||||
const DISTANCE_COLORS = {
|
||||
5: 'text-green-700 dark:text-green-300',
|
||||
4: 'text-blue-700 dark:text-blue-300',
|
||||
3: 'text-yellow-700 dark:text-yellow-300',
|
||||
2: 'text-orange-700 dark:text-orange-300',
|
||||
};
|
||||
|
||||
function getDistanceColor(distance) {
|
||||
return DISTANCE_COLORS[calculateScore(distance)] ?? 'text-red-700 dark:text-red-300';
|
||||
}
|
||||
|
||||
function getScoreColor(score) {
|
||||
if (score >= 50) return 'text-purple-700 dark:text-purple-300';
|
||||
|
||||
+13
-35
@@ -17,14 +17,21 @@ export function calculateDistance(lat1, lon1, lat2, lon2) {
|
||||
}
|
||||
}
|
||||
|
||||
// Distance ceiling in meters -> points. The single scoring ladder; anything
|
||||
// that bands a result (colors, labels, the scoring table on the home page)
|
||||
// should derive from calculateScore rather than re-typing these thresholds.
|
||||
export const SCORE_BANDS = [
|
||||
{ maxMeters: 50, points: 5 },
|
||||
{ maxMeters: 100, points: 4 },
|
||||
{ maxMeters: 200, points: 3 },
|
||||
{ maxMeters: 500, points: 2 },
|
||||
{ maxMeters: 1000, points: 1 },
|
||||
];
|
||||
|
||||
// Calculate score based on distance (0-5 points scale)
|
||||
export function calculateScore(distance) {
|
||||
if (distance <= 50) return 5;
|
||||
if (distance <= 100) return 4;
|
||||
if (distance <= 200) return 3;
|
||||
if (distance <= 500) return 2;
|
||||
if (distance <= 1000) return 1;
|
||||
return 0;
|
||||
const band = SCORE_BANDS.find((entry) => distance <= entry.maxMeters);
|
||||
return band ? band.points : 0;
|
||||
}
|
||||
|
||||
// Format distance for display
|
||||
@@ -35,32 +42,3 @@ export function formatDistance(distance) {
|
||||
return `${(distance / 1000).toFixed(2)}km`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get or set username from localStorage
|
||||
export function getUsername() {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('vngeoguessr_username');
|
||||
}
|
||||
|
||||
export function setUsername(username) {
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.setItem('vngeoguessr_username', username);
|
||||
}
|
||||
|
||||
// Get result message based on score
|
||||
export function getResultMessage(score, distance) {
|
||||
if (score > 4) return "Excellent! Outstanding guess!";
|
||||
if (score > 2) return "Good job! Nice work!";
|
||||
if (score > 0) return "Not bad! Keep trying!";
|
||||
return "Nice try! Better luck next time!";
|
||||
}
|
||||
|
||||
// Get distance color for leaderboard display
|
||||
export function getDistanceColor(distance) {
|
||||
if (distance <= 50) return 'text-green-700 dark:text-green-300';
|
||||
if (distance <= 100) return 'text-blue-700 dark:text-blue-300';
|
||||
if (distance <= 200) return 'text-yellow-700 dark:text-yellow-300';
|
||||
if (distance <= 500) return 'text-orange-700 dark:text-orange-300';
|
||||
return 'text-red-700 dark:text-red-300';
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
// replaces asking the Graph API what is near a random point, which fails
|
||||
// outright in dense districts and takes seconds where it works.
|
||||
//
|
||||
// SERVER-SIDE ONLY. These files are ~25MB of exact answers; importing them from
|
||||
// SERVER-SIDE ONLY. These files are ~28MB of exact answers; importing them from
|
||||
// anywhere the browser can reach hands every round's solution to the player.
|
||||
// src/lib/regions.js is the client-safe view of the same tree and deliberately
|
||||
// imports nothing from here -- tests/regions.test.js enforces that boundary.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Player name in localStorage, mirroring theme.js: one module owns one
|
||||
// browser-storage concern, so server code importing lib/game.js for scoring
|
||||
// never touches window.
|
||||
|
||||
export const USERNAME_STORAGE_KEY = 'vngeoguessr_username';
|
||||
|
||||
export function getUsername() {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem(USERNAME_STORAGE_KEY);
|
||||
}
|
||||
|
||||
export function setUsername(username) {
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.setItem(USERNAME_STORAGE_KEY, username);
|
||||
}
|
||||
Reference in new issue
Block a user