/** * SIM-09: Energiemix-Simulator — LOGIK * * Modell: * - Schüler*innen stellen einen Energiemix zusammen * - Drei Zielgrößen: CO₂-Ausstoß, Kosten, Versorgungssicherheit * - Jede Energiequelle hat spezifische Werte für alle drei Dimensionen * - Zielkonflikt sichtbar machen: billiger = dreckiger, sauber = teurer/unsicherer * * Didaktik: * - Keine "richtige" Antwort — es geht um das Abwägen * - Urteilskompetenz: verschiedene Perspektiven einnehmen * - Gamification: Highscore für besten Kompromiss */ import { Simulation, SimulationMeta } from '@core/simulation' const META: SimulationMeta = { id: 'sim-09', name: 'Energiemix-Simulator', educationLevels: [5, 6, 7, 8, 9, 10], primaryLevel: 6, kompetenzbereich: 'Nachhaltiger Umgang mit Energie und Ressourcen', lernziele: [ 'Erneuerbare und nicht erneuerbare Energieträger vergleichen', 'Zielkonflikte zwischen Kosten, Umwelt und Versorgungssicherheit erkennen', 'Eigene Position zu Energiepolitik bilden und begründen', ], basiskonzepte: ['Leistungserstellung und Nachhaltigkeit', 'Ökonomische Prinzipien und Entscheidungsfindung'], dpiMinuten: 25, typ: 'sachsimulation', tier: 1, requiresReading: true, } export interface EnergySource { id: string name: string emoji: string color: string co2PerGWh: number // Tonnen CO₂ pro GWh (Lifecycle) costPerMWh: number // EUR pro MWh reliability: number // 0-1 (1 = immer verfügbar) maxShare: number // maximaler realistischer Anteil (0-1) renewable: boolean description: string } export const ENERGY_SOURCES: EnergySource[] = [ { id: 'coal', name: 'Kohle', emoji: '🪨', color: '#4a4a4a', co2PerGWh: 820, costPerMWh: 65, reliability: 0.85, maxShare: 1, renewable: false, description: 'Billig aber sehr CO₂-intensiv' }, { id: 'gas', name: 'Erdgas', emoji: '🔥', color: '#c4a35a', co2PerGWh: 490, costPerMWh: 55, reliability: 0.87, maxShare: 0.8, renewable: false, description: 'Hälfte des CO₂ von Kohle, flexibel' }, { id: 'nuclear', name: 'Atomkraft', emoji: '⚛️', color: '#8a5caa', co2PerGWh: 12, costPerMWh: 90, reliability: 0.92, maxShare: 0.6, renewable: false, description: 'Kaum CO₂, aber teuer und Atommüll' }, { id: 'wind', name: 'Windkraft', emoji: '🌬️', color: '#5a9aaa', co2PerGWh: 11, costPerMWh: 45, reliability: 0.35, maxShare: 0.5, renewable: true, description: 'Günstig und sauber, aber wetterabhängig' }, { id: 'solar', name: 'Solarenergie', emoji: '☀️', color: '#e8c84a', co2PerGWh: 45, costPerMWh: 40, reliability: 0.25, maxShare: 0.4, renewable: true, description: 'Billigste Quelle, aber nur tagsüber' }, { id: 'hydro', name: 'Wasserkraft', emoji: '💧', color: '#4a7c8a', co2PerGWh: 24, costPerMWh: 50, reliability: 0.55, maxShare: 0.3, renewable: true, description: 'Zuverlässig, aber Standort-begrenzt' }, ] export interface MixResult { totalCO2: number // Tonnen CO₂ pro GWh (gewichteter Durchschnitt) totalCost: number // EUR pro MWh totalReliability: number // 0-1 renewableShare: number // 0-100% score: number // Gesamtbewertung 0-100 rating: string // z.B. "Gut balanciert" } /** * Berechnet die Ergebnisse eines Energiemixes * @param mix Map von SourceID → Anteil (0-100, Summe sollte 100 sein) */ export function computeMixResult(mix: Record): MixResult { let totalCO2 = 0 let totalCost = 0 let totalReliability = 0 let renewableShare = 0 let totalShare = 0 for (const source of ENERGY_SOURCES) { const share = (mix[source.id] || 0) / 100 totalShare += share totalCO2 += source.co2PerGWh * share totalCost += source.costPerMWh * share totalReliability += source.reliability * share if (source.renewable) renewableShare += share * 100 } // Normalisieren falls Summe ≠ 100 if (totalShare > 0 && Math.abs(totalShare - 1) > 0.01) { totalCO2 /= totalShare totalCost /= totalShare totalReliability /= totalShare renewableShare /= totalShare } // Score: Multi-Kriterien-Bewertung const co2Score = Math.max(0, 100 - totalCO2 / 8) // 0 CO₂ = 100, 800 = 0 const costScore = Math.max(0, 100 - (totalCost - 30) / 0.7) // 30€ = 100, 100€ = 0 const reliScore = totalReliability * 100 const score = Math.round((co2Score * 0.4 + costScore * 0.3 + reliScore * 0.3)) let rating = 'Experimentell' if (score >= 80) rating = 'Exzellent! 🌟' else if (score >= 65) rating = 'Gut balanciert 👍' else if (score >= 50) rating = 'Solide Basis' else if (score >= 35) rating = 'Verbesserungswürdig' return { totalCO2: Math.round(totalCO2), totalCost: Math.round(totalCost), totalReliability: Math.round(totalReliability * 100) / 100, renewableShare: Math.round(renewableShare), score, rating, } } export class EnergiemixSimulation extends Simulation { constructor() { super(META) // Startwerte: aktueller europäischer Mix (circa) this.state.variables = { coal: 15, gas: 20, nuclear: 20, wind: 18, solar: 12, hydro: 15, } } getVariableRanges() { const ranges: Record = {} for (const source of ENERGY_SOURCES) { ranges[source.id] = { min: 0, max: Math.round(source.maxShare * 100), default: this.state.variables[source.id] || 0, unit: '%', label: `${source.emoji} ${source.name}`, } } return ranges } /** Normalisiert den Mix auf 100% */ normalizeMix(): void { const total = ENERGY_SOURCES.reduce((s, src) => s + this.getVariable(src.id), 0) if (total > 0) { for (const src of ENERGY_SOURCES) { this.state.variables[src.id] = Math.round(this.getVariable(src.id) / total * 100) } } } compute() { const mix: Record = {} for (const src of ENERGY_SOURCES) { mix[src.id] = this.getVariable(src.id) } const result = computeMixResult(mix) this.state.results = result return result as unknown as Record } protected onVariableChange(): void { this.compute() } }