Weltküche: Herkunft per Handels-Gravitation + Punktefix „alle falsch = 0"
- Zweit-Lieferant im Heimat-Zweig jetzt via Handels-Gravitation (Menge ÷ Entfernung zur Heimat, Haversine über Länder-Koordinaten) statt roher Weltproduktion. AT-Eier → Deutschland (468 km) statt Frankreich (916 km), obwohl FR mehr Eier erzeugt. Distraktoren bleiben nie echte AT-Lieferanten. Verifiziert: Eier/Kartoffel/Milch → [Österreich, Deutschland]; alle 70 Zutaten bauen fehlerfrei. - Punktefix: Strafe pro Fehlklick = 100 ÷ Anzahl Distraktoren → „alle Falschen zuerst" ergibt IMMER 0 (bei 4 Distraktoren −25, bei 2 −50). Task-Banner zeigt die tatsächliche Strafe + „alle falsch zuerst = 0". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1031,6 +1031,17 @@ function ingWas(ing, sTask, ingKey) {
|
||||
return a + ' ' + (ing ? ing.nm : '');
|
||||
}
|
||||
|
||||
// Entfernung zweier Länder (Haversine, km) über die Länder-Koordinaten.
|
||||
// Für die Handels-Gravitation (Menge ÷ Entfernung) beim Zweit-Lieferanten.
|
||||
function _wkDist(a, b) {
|
||||
const A = C[a], B = C[b];
|
||||
if (!A || !B || A.lat == null || B.lat == null) return 3000;
|
||||
const R = 6371, toR = Math.PI / 180;
|
||||
const dLat = (B.lat - A.lat) * toR, dLng = (B.lng - A.lng) * toR;
|
||||
const s = Math.sin(dLat / 2) ** 2 + Math.cos(A.lat * toR) * Math.cos(B.lat * toR) * Math.sin(dLng / 2) ** 2;
|
||||
return Math.max(60, 2 * R * Math.asin(Math.min(1, Math.sqrt(s))));
|
||||
}
|
||||
|
||||
function buildTaskFor(ingKey) {
|
||||
if (_taskCache[ingKey]) return _taskCache[ingKey];
|
||||
const ing = ING[ingKey];
|
||||
@@ -1054,9 +1065,14 @@ function buildTaskFor(ingKey) {
|
||||
// (global/ungetaggt). „world-far"/„local" (wächst dort, landet aber nicht in unseren
|
||||
// Regalen) zählen NICHT als korrekt.
|
||||
const mrank = m => (m === 'eu' ? 0 : (m === 'world-far' || m === 'local') ? 2 : 1);
|
||||
// Zweit-Lieferant = realistisch für UNSEREN Markt via Handels-Gravitation:
|
||||
// Menge ÷ Entfernung zur Heimat. Ein naher großer Nachbar schlägt einen
|
||||
// fernen Großproduzenten (AT-Eier → Deutschland, NICHT Frankreich), obwohl
|
||||
// Frankreich mehr Eier erzeugt. Markt-Tier bleibt vorrangig (EU vor global).
|
||||
const grav = ([c, info]) => (info.t || 0) / _wkDist(heimat, c);
|
||||
const realistic = Object.entries(ing.producers)
|
||||
.filter(([c, info]) => C[c] && c !== heimat && mrank(info.market) < 2)
|
||||
.sort((a, b) => (mrank(a[1].market) - mrank(b[1].market)) || ((b[1].t || 0) - (a[1].t || 0)))
|
||||
.sort((a, b) => (mrank(a[1].market) - mrank(b[1].market)) || (grav(b) - grav(a)))
|
||||
.map(([c]) => c);
|
||||
const correct = [heimat, ...realistic.slice(0, 1)]; // Heimat + eine realistische Zweit-Wahl (wie normaler Zweig: 2 Korrekte)
|
||||
if (correct.length < 2) { // Garantie: es gibt IMMER eine zweite Wahl
|
||||
@@ -1231,9 +1247,11 @@ function loadIngredient(){
|
||||
: (task && task.signature
|
||||
? 'aus welchem Land stammt diese Zutat in <b>diesem Gericht</b>?'
|
||||
: 'aus welchem Land kommt diese Zutat häufig zu uns auf den Markt?');
|
||||
const _nd = Math.max(1, task ? (task.choices.length - task.correct.length) : 4);
|
||||
const _per = Math.round(100 / _nd);
|
||||
document.getElementById('taskBanner').innerHTML=
|
||||
`🔎 Suche: <b>${ing.nm}</b> – ${frage}`
|
||||
+ ` <span style="opacity:.75;font-weight:600;white-space:nowrap">· richtig <b>+100</b>, jeder Fehlklick <b>−25</b> (¼)</span>`;
|
||||
+ ` <span style="opacity:.75;font-weight:600;white-space:nowrap">· richtig <b>+100</b>, jeder Fehlklick <b>−${_per}</b> (alle falsch zuerst = 0)</span>`;
|
||||
document.getElementById('resultCard').className="result-card";
|
||||
drawMarkers(ing); renderIngList();
|
||||
}
|
||||
@@ -1270,7 +1288,10 @@ function guess(key){
|
||||
playSfx('click-country');
|
||||
if (cls === 'correct') {
|
||||
b.classList.add('correct');
|
||||
const pts = Math.max(0, 100 - 25 * (current.wrongHere || 0)); // richtig = 100; jeder Fehlklick auf dieser Zutat: −25 (¼)
|
||||
// Strafe pro Fehlklick so, dass „alle Falschen zuerst" IMMER 0 ergibt:
|
||||
// 100 ÷ Anzahl Distraktoren. Bei 4 Distraktoren = −25 (¼), bei 2 = −50.
|
||||
const numDistr = Math.max(1, task ? (task.choices.length - task.correct.length) : 4);
|
||||
const pts = Math.max(0, Math.round(100 - (100 / numDistr) * (current.wrongHere || 0)));
|
||||
state.score+=pts; current.dishScore+=pts;
|
||||
state.totalCorrect++; current.wrongStreak=0; current.found.push(key);
|
||||
map.flyTo([c.lat,c.lng],3,{duration:.7});
|
||||
|
||||
Reference in New Issue
Block a user