/** * 🧮 IHK SUBNETTING DRILL MASTER 🧮 * ================================= * Interaktiver Subnetting-Trainer für AP1 & AP2 (LF 3 & LF 9): * - Endlose Zufallsaufgaben (FLSM & VLSM) * - Magische Zahl (256 - Oktett) Erklärung * - Automatische Validierung aller 6 Parameter */ class SubnettingDrill { constructor(containerId) { this.container = document.getElementById(containerId); this.currentTask = null; this.stats = { total: 0, correct: 0, streak: 0 }; this.init(); } init() { if (!this.container) return; this.render(); this.generateTask(); } render() { this.container.innerHTML = `
🧮 IHK Subnetting-Drill Master
0 gelöst (0%) 🔥 Streak: 0
Gegebene IP-Adresse & CIDR-Prefix:
192.168.10.45 / 27
`; document.getElementById("btn-check-drill").addEventListener("click", () => this.checkAnswer()); document.getElementById("btn-next-drill").addEventListener("click", () => this.generateTask()); document.getElementById("btn-magic-hint").addEventListener("click", () => this.toggleHint()); } generateTask() { // Generiere IP im privaten Bereich (Klasse A, B oder C) const type = Math.floor(Math.random() * 3); let ipParts = []; let prefix = 24; if (type === 0) { ipParts = [192, 168, Math.floor(Math.random() * 100) + 1, Math.floor(Math.random() * 254) + 1]; prefix = Math.floor(Math.random() * 7) + 24; // /24 bis /30 } else if (type === 1) { ipParts = [172, Math.floor(Math.random() * 16) + 16, Math.floor(Math.random() * 254) + 1, Math.floor(Math.random() * 254) + 1]; prefix = Math.floor(Math.random() * 9) + 20; // /20 bis /28 } else { ipParts = [10, Math.floor(Math.random() * 254) + 1, Math.floor(Math.random() * 254) + 1, Math.floor(Math.random() * 254) + 1]; prefix = Math.floor(Math.random() * 12) + 18; // /18 bis /29 } const ipInt = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3]; const maskInt = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0; const netInt = (ipInt & maskInt) >>> 0; const bcastInt = (netInt | ~maskInt) >>> 0; const firstInt = (netInt + 1) >>> 0; const lastInt = (bcastInt - 1) >>> 0; const hostBits = 32 - prefix; const usableHosts = Math.pow(2, hostBits) - 2; const intToIp = (num) => [ (num >>> 24) & 255, (num >>> 16) & 255, (num >>> 8) & 255, num & 255 ].join("."); this.currentTask = { ip: ipParts.join("."), prefix: prefix, mask: intToIp(maskInt), net: intToIp(netInt), first: intToIp(firstInt), last: intToIp(lastInt), bcast: intToIp(bcastInt), hosts: usableHosts, magicNumber: 256 - ((maskInt >>> (8 * (3 - Math.floor(prefix / 8)))) & 255 || 256) }; document.getElementById("drill-ip-display").textContent = `${this.currentTask.ip} / ${this.currentTask.prefix}`; document.getElementById("ans-mask").value = ""; document.getElementById("ans-net").value = ""; document.getElementById("ans-first").value = ""; document.getElementById("ans-last").value = ""; document.getElementById("ans-bcast").value = ""; document.getElementById("ans-hosts").value = ""; const resBox = document.getElementById("drill-result"); resBox.classList.remove("active"); } checkAnswer() { if (!this.currentTask) return; const ansMask = document.getElementById("ans-mask").value.trim(); const ansNet = document.getElementById("ans-net").value.trim(); const ansFirst = document.getElementById("ans-first").value.trim(); const ansLast = document.getElementById("ans-last").value.trim(); const ansBcast = document.getElementById("ans-bcast").value.trim(); const ansHosts = parseInt(document.getElementById("ans-hosts").value.trim(), 10); const checks = [ { name: "Subnetzmaske", correct: ansMask === this.currentTask.mask, expected: this.currentTask.mask, user: ansMask }, { name: "Netzadresse", correct: ansNet === this.currentTask.net, expected: this.currentTask.net, user: ansNet }, { name: "Erste Host-IP", correct: ansFirst === this.currentTask.first, expected: this.currentTask.first, user: ansFirst }, { name: "Letzte Host-IP", correct: ansLast === this.currentTask.last, expected: this.currentTask.last, user: ansLast }, { name: "Broadcast", correct: ansBcast === this.currentTask.bcast, expected: this.currentTask.bcast, user: ansBcast }, { name: "Nutzbare Hosts", correct: ansHosts === this.currentTask.hosts, expected: this.currentTask.hosts, user: ansHosts } ]; const allCorrect = checks.every(c => c.correct); this.stats.total++; if (allCorrect) { this.stats.correct++; this.stats.streak++; } else { this.stats.streak = 0; } const pct = Math.round((this.stats.correct / this.stats.total) * 100); document.getElementById("drill-stats").textContent = `${this.stats.correct}/${this.stats.total} gelöst (${pct}%)`; document.getElementById("drill-streak").textContent = `🔥 Streak: ${this.stats.streak}`; const resBox = document.getElementById("drill-result"); resBox.innerHTML = `

${allCorrect ? '🎉 Perfekt! Alle 6 Werte exakt berechnet.' : '❌ Noch nicht ganz richtig – überprüfe deine Werte:'}

${checks.map(c => ` `).join('')}
ParameterDeine EingabeMusterlösungStatus
${c.name} ${c.user || 'leer'} ${c.expected} ${c.correct ? '✅ Richtig' : '❌ Falsch'}
`; resBox.classList.add("active"); } toggleHint() { if (!this.currentTask) return; const resBox = document.getElementById("drill-result"); const octetIndex = Math.floor(this.currentTask.prefix / 8); const bitsInOctet = this.currentTask.prefix % 8; const octetNum = octetIndex + (bitsInOctet > 0 ? 1 : 0); resBox.innerHTML = `

💡 Das IHK-Geheimnis: Die „Magische Zahl“ (Schrittweite)

Für /${this.currentTask.prefix} liegt das interessante Oktett im ${octetNum}. Oktett.
1. Ermittle den Maskenwert: ${this.currentTask.mask}.
2. Die Schrittweite („Magische Zahl“) ist: 256 - Oktettwert.
3. Die Netzadressen steigen immer in Vielfachen dieser Schrittweite (0, Schrittweite, 2 × Schrittweite, ...) bis kurz vor deine gegebene IP.
4. Broadcast ist immer Nächste Netzadresse - 1.

`; resBox.classList.add("active"); } } window.SubnettingDrill = SubnettingDrill;