Files
crumbmissions/crumbblocks/bashpanda_guertelpruefung.html
Branko May Trinkwald d4d75af428 🐼 feat(dojo): BashPanda Gürtel-System - Von Schwarz auf Weiss 🥋
Der 18. Waldwächter betritt den Wald: BashPanda lehrt Bash als Kampfkunst!

 Neue Features:

🐼 BashPanda Waldwächter:
- Kung Fu Meister Persönlichkeit
- Lehrt Bash durch Kampfkunst-Metaphern
- Integriert in waldwaechter.sh Library
- Crew Memory: Kennt alle anderen Waldwächter

🥋 6 Gürtel-Missionen (Progressive Bash-Meisterschaft):
- 🖤 Schwarzer Gürtel: echo, Variablen, read, ANSI codes
- 💖 Pinker Gürtel: if/then, while/for, Arrays, Arithmetik
- 💙 Blauer Gürtel: sed, case, bc, Textverarbeitung
- 💚 Grüner Gürtel: grep, regex, Pattern Matching
- 💛 Gelber Gürtel: Funktionen, source, Parameter
- 🤍 Weisser Gürtel: Background jobs, Prozesse, Parallelität

📝 Interaktives Quiz-System:
- Browser-based Gürtelprüfung (crumbblocks)
- 30 Fragen (5 pro Gürtel)
- Farbcodiert nach Gürtel
- Auto-Export via Clipboard
- Terminal-Auswertung mit Zertifikaten

🎓 Zertifikate-System:
- Automatische Generierung bei 80%+
- Gespeichert in logs/zertifikate/
- BashPanda's Segen & Weisheiten

📚 Dokumentation:
- CLAUDE.md komplett aktualisiert
- BashPanda als 18. Waldwächter dokumentiert
- Vollständige Dojo-Architektur beschrieben

"Der Weg des Codes ist wie der Weg der Kampfkunst:
 Geduld, Präzision, Wiederholung."

 - BashPanda 🐼🎋

Crumbforest wächst! 🌲 Der Wurzelbau geht weiter! 🌳

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 00:29:30 +01:00

632 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🐼 BashPanda Gürtelprüfung 🥋</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
color: #e0e0e0;
padding: 20px;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.header {
text-align: center;
padding: 30px 20px;
background: rgba(0,0,0,0.3);
border-radius: 15px;
margin-bottom: 30px;
border: 2px solid #4a4a4a;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.header .subtitle {
font-size: 1.2em;
opacity: 0.8;
}
.belt-selector {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.belt-btn {
padding: 20px;
border: 3px solid;
border-radius: 10px;
cursor: pointer;
text-align: center;
font-size: 1.1em;
font-weight: bold;
transition: all 0.3s;
background: rgba(0,0,0,0.3);
}
.belt-btn:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
}
.belt-btn.active {
box-shadow: 0 0 20px currentColor;
background: rgba(255,255,255,0.1);
}
.black { border-color: #000; color: #fff; }
.pink { border-color: #ff69b4; color: #ff69b4; }
.blue { border-color: #4169e1; color: #4169e1; }
.green { border-color: #32cd32; color: #32cd32; }
.yellow { border-color: #ffd700; color: #ffd700; }
.white { border-color: #f0f0f0; color: #f0f0f0; }
.quiz-container {
background: rgba(0,0,0,0.3);
border-radius: 15px;
padding: 30px;
border: 2px solid #4a4a4a;
display: none;
}
.quiz-container.active {
display: block;
}
.question {
margin-bottom: 30px;
}
.question-text {
font-size: 1.3em;
margin-bottom: 20px;
padding: 15px;
background: rgba(255,255,255,0.05);
border-left: 4px solid;
border-radius: 5px;
}
.options {
display: flex;
flex-direction: column;
gap: 10px;
}
.option {
padding: 15px 20px;
border: 2px solid #4a4a4a;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
background: rgba(0,0,0,0.2);
}
.option:hover {
background: rgba(255,255,255,0.1);
border-color: #6a6a6a;
}
.option.selected {
border-color: #ffd700;
background: rgba(255, 215, 0, 0.2);
}
.option.correct {
border-color: #32cd32;
background: rgba(50, 205, 50, 0.2);
}
.option.wrong {
border-color: #ff4444;
background: rgba(255, 68, 68, 0.2);
}
.controls {
display: flex;
gap: 15px;
margin-top: 30px;
}
.btn {
flex: 1;
padding: 15px 30px;
border: 2px solid #4a4a4a;
border-radius: 8px;
background: rgba(0,0,0,0.3);
color: #e0e0e0;
font-size: 1.1em;
cursor: pointer;
transition: all 0.3s;
}
.btn:hover {
background: rgba(255,255,255,0.1);
border-color: #6a6a6a;
}
.btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: #764ba2;
}
.btn-primary:hover {
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.results {
display: none;
text-align: center;
padding: 40px;
background: rgba(0,0,0,0.3);
border-radius: 15px;
border: 2px solid #4a4a4a;
}
.results.show {
display: block;
}
.results h2 {
font-size: 2.5em;
margin-bottom: 20px;
}
.results .score {
font-size: 3em;
font-weight: bold;
margin: 30px 0;
}
.results .verdict {
font-size: 1.5em;
margin: 20px 0;
padding: 20px;
border-radius: 10px;
background: rgba(255,255,255,0.05);
}
.export-info {
margin-top: 30px;
padding: 20px;
background: rgba(255, 215, 0, 0.1);
border: 2px solid #ffd700;
border-radius: 10px;
}
.progress {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
padding: 10px;
background: rgba(0,0,0,0.2);
border-radius: 8px;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.pulse {
animation: pulse 2s infinite;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🐼 BashPanda Gürtelprüfung 🥋</h1>
<div class="subtitle">"Beweise dein Wissen, junger Schüler"</div>
</div>
<div class="belt-selector" id="beltSelector">
<div class="belt-btn black" data-belt="schwarz">🖤<br>Schwarz</div>
<div class="belt-btn pink" data-belt="pink">💖<br>Pink</div>
<div class="belt-btn blue" data-belt="blau">💙<br>Blau</div>
<div class="belt-btn green" data-belt="gruen">💚<br>Grün</div>
<div class="belt-btn yellow" data-belt="gelb">💛<br>Gelb</div>
<div class="belt-btn white" data-belt="weiss">🤍<br>Weiss</div>
</div>
<div class="quiz-container" id="quizContainer">
<div class="progress" id="progress"></div>
<div id="questionContainer"></div>
<div class="controls">
<button class="btn" id="prevBtn" disabled>⬅️ Zurück</button>
<button class="btn btn-primary" id="nextBtn">Weiter ➡️</button>
</div>
</div>
<div class="results" id="results"></div>
</div>
<script>
const quizData = {
schwarz: [
{
question: "Was gibt 'echo $HOME' aus?",
options: ["Dein Home-Verzeichnis", "Die Umgebungsvariable HOME", "Beide Antworten sind richtig", "Einen Fehler"],
correct: 2,
color: "#fff"
},
{
question: "Wie erstellt man eine Variable?",
options: ["name = value", "name=value", "$name=value", "set name=value"],
correct: 1,
color: "#fff"
},
{
question: "Was macht 'read -p \"Name: \" name'?",
options: ["Liest eine Datei", "Zeigt 'Name:' und speichert Eingabe in $name", "Gibt $name aus", "Nichts"],
correct: 1,
color: "#fff"
},
{
question: "Welcher ANSI Code macht Text fett?",
options: ["\\e[0m", "\\e[1m", "\\e[4m", "\\e[32m"],
correct: 1,
color: "#fff"
},
{
question: "Was ist der Unterschied zwischen ' und \" in echo?",
options: ["Keiner", "' ignoriert Variablen, \" ersetzt sie", "\" ignoriert Variablen", "Beide ersetzen Variablen"],
correct: 1,
color: "#fff"
}
],
pink: [
{
question: "Was prüft [ $a -eq $b ]?",
options: ["String-Gleichheit", "Zahlen-Gleichheit", "Größer als", "Kleiner als"],
correct: 1,
color: "#ff69b4"
},
{
question: "Wie greift man auf das 3. Array-Element zu?",
options: ["${arr[3]}", "${arr[2]}", "$arr[2]", "arr[3]"],
correct: 1,
color: "#ff69b4"
},
{
question: "Was macht 'while [ $i -le 5 ]; do ... done'?",
options: ["Läuft 4 mal", "Läuft 5 mal", "Läuft 6 mal", "Endlosschleife"],
correct: 1,
color: "#ff69b4"
},
{
question: "Wie zählt man Arrays hoch?",
options: ["i++", "i=$((i + 1))", "let i++", "Alle sind richtig"],
correct: 1,
color: "#ff69b4"
},
{
question: "Was gibt ${#arr[@]} zurück?",
options: ["Erstes Element", "Letztes Element", "Anzahl Elemente", "Fehler"],
correct: 2,
color: "#ff69b4"
}
],
blau: [
{
question: "Was macht 'sed s/alt/neu/'?",
options: ["Löscht 'alt'", "Ersetzt erstes 'alt' mit 'neu'", "Ersetzt alle 'alt' mit 'neu'", "Sucht nach 'alt'"],
correct: 1,
color: "#4169e1"
},
{
question: "Wofür nutzt man 'case' statt if/then?",
options: ["Für Schleifen", "Für mehrere if-Alternativen", "Für Arrays", "Für Funktionen"],
correct: 1,
color: "#4169e1"
},
{
question: "Wie rechnet man mit Fließkommazahlen?",
options: ["$(( ))", "bc", "let", "expr"],
correct: 1,
color: "#4169e1"
},
{
question: "Was bedeutet das * in case?",
options: ["Multiplikation", "Wildcard (alles)", "Default-Fall", "Fehler"],
correct: 2,
color: "#4169e1"
},
{
question: "Wie nutzt man bc für Division?",
options: ["bc 10/3", "echo '10/3' | bc", "10/3 | bc", "bc(10/3)"],
correct: 1,
color: "#4169e1"
}
],
gruen: [
{
question: "Was macht grep -i?",
options: ["Zeigt Zeilennummern", "Ignoriert Groß-/Kleinschreibung", "Invertiert Suche", "Rekursiv suchen"],
correct: 1,
color: "#32cd32"
},
{
question: "Was bedeutet ^ in Regex?",
options: ["Zeilenanfang", "Zeilenende", "Beliebiges Zeichen", "Wiederholung"],
correct: 0,
color: "#32cd32"
},
{
question: "Was matched [0-9]+ in Regex?",
options: ["Genau eine Ziffer", "Eine oder mehr Ziffern", "Null oder mehr Ziffern", "Keine Ziffer"],
correct: 1,
color: "#32cd32"
},
{
question: "Wie sucht man rekursiv in allen Dateien?",
options: ["grep muster *", "grep -r muster .", "grep -i muster", "grep -n muster"],
correct: 1,
color: "#32cd32"
},
{
question: "Was matched .* in Regex?",
options: ["Nichts", "Punkt und Stern", "Beliebige Zeichen (0+)", "Ein Zeichen"],
correct: 2,
color: "#32cd32"
}
],
gelb: [
{
question: "Wie definiert man eine Funktion?",
options: ["func name() {}", "function name() {}", "def name() {}", "Beide 1 und 2"],
correct: 3,
color: "#ffd700"
},
{
question: "Was ist $1 in einer Funktion?",
options: ["Erster Buchstabe", "Erster Parameter", "Exit-Code", "PID"],
correct: 1,
color: "#ffd700"
},
{
question: "Was macht 'source datei.sh'?",
options: ["Führt Datei aus", "Lädt Funktionen in aktuelle Shell", "Kopiert Datei", "Löscht Datei"],
correct: 1,
color: "#ffd700"
},
{
question: "Was macht 'return 42' in einer Funktion?",
options: ["Gibt 42 aus", "Beendet Skript", "Verlässt Funktion mit Code 42", "Fehler"],
correct: 2,
color: "#ffd700"
},
{
question: "Was ist $@ in einer Funktion?",
options: ["Erster Parameter", "Alle Parameter", "Anzahl Parameter", "Funktionsname"],
correct: 1,
color: "#ffd700"
}
],
weiss: [
{
question: "Was macht & am Ende eines Befehls?",
options: ["Beendet ihn", "Startet im Hintergrund", "Wiederholt ihn", "Nichts"],
correct: 1,
color: "#f0f0f0"
},
{
question: "Was ist $! ?",
options: ["Exit-Code", "PID des letzten Background-Jobs", "Anzahl Parameter", "Home-Verzeichnis"],
correct: 1,
color: "#f0f0f0"
},
{
question: "Was macht 'wait'?",
options: ["Wartet 1 Sekunde", "Wartet auf Eingabe", "Wartet auf Background-Jobs", "Pausiert Skript"],
correct: 2,
color: "#f0f0f0"
},
{
question: "Wie zeigt man alle Background-Jobs?",
options: ["ps", "jobs", "bg", "fg"],
correct: 1,
color: "#f0f0f0"
},
{
question: "Was macht 'fg %1'?",
options: ["Beendet Job 1", "Bringt Job 1 in Vordergrund", "Startet Job 1", "Pausiert Job 1"],
correct: 1,
color: "#f0f0f0"
}
]
};
let currentBelt = null;
let currentQuestion = 0;
let answers = [];
let score = 0;
// Belt Selection
document.getElementById('beltSelector').addEventListener('click', (e) => {
const btn = e.target.closest('.belt-btn');
if (!btn) return;
document.querySelectorAll('.belt-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentBelt = btn.dataset.belt;
currentQuestion = 0;
answers = [];
score = 0;
document.getElementById('quizContainer').classList.add('active');
document.getElementById('results').classList.remove('show');
showQuestion();
});
function showQuestion() {
if (!currentBelt) return;
const questions = quizData[currentBelt];
const q = questions[currentQuestion];
document.getElementById('progress').innerHTML = `
<span>Frage ${currentQuestion + 1} von ${questions.length}</span>
<span>🐼 BashPanda beobachtet</span>
`;
const questionHTML = `
<div class="question">
<div class="question-text" style="border-color: ${q.color}">
${currentQuestion + 1}. ${q.question}
</div>
<div class="options">
${q.options.map((opt, idx) => `
<div class="option" data-index="${idx}">
${String.fromCharCode(65 + idx)}. ${opt}
</div>
`).join('')}
</div>
</div>
`;
document.getElementById('questionContainer').innerHTML = questionHTML;
// Restore previous answer if exists
if (answers[currentQuestion] !== undefined) {
const selected = document.querySelector(`[data-index="${answers[currentQuestion]}"]`);
if (selected) selected.classList.add('selected');
}
// Option selection
document.querySelectorAll('.option').forEach(opt => {
opt.addEventListener('click', () => {
document.querySelectorAll('.option').forEach(o => o.classList.remove('selected'));
opt.classList.add('selected');
answers[currentQuestion] = parseInt(opt.dataset.index);
document.getElementById('nextBtn').disabled = false;
});
});
updateButtons();
}
function updateButtons() {
document.getElementById('prevBtn').disabled = currentQuestion === 0;
document.getElementById('nextBtn').disabled = answers[currentQuestion] === undefined;
const questions = quizData[currentBelt];
if (currentQuestion === questions.length - 1) {
document.getElementById('nextBtn').textContent = '🎯 Auswerten';
} else {
document.getElementById('nextBtn').textContent = 'Weiter ➡️';
}
}
document.getElementById('prevBtn').addEventListener('click', () => {
if (currentQuestion > 0) {
currentQuestion--;
showQuestion();
}
});
document.getElementById('nextBtn').addEventListener('click', () => {
const questions = quizData[currentBelt];
if (currentQuestion < questions.length - 1) {
currentQuestion++;
showQuestion();
} else {
showResults();
}
});
function showResults() {
const questions = quizData[currentBelt];
score = 0;
answers.forEach((ans, idx) => {
if (ans === questions[idx].correct) {
score++;
}
});
const percentage = (score / questions.length * 100).toFixed(0);
let verdict, color, emoji;
if (percentage >= 80) {
verdict = "🎉 BESTANDEN! 🎉<br>Der Gürtel gehört dir!";
color = "#32cd32";
emoji = "✅";
} else if (percentage >= 60) {
verdict = "Fast geschafft!<br>Übe noch ein wenig.";
color = "#ffd700";
emoji = "⚠️";
} else {
verdict = "Noch nicht bereit.<br>Lerne weiter, junger Schüler.";
color = "#ff4444";
emoji = "❌";
}
const resultData = {
belt: currentBelt,
score: score,
total: questions.length,
percentage: percentage,
passed: percentage >= 80,
timestamp: new Date().toISOString()
};
document.getElementById('results').innerHTML = `
<h2>${emoji} Gürtelprüfung: ${currentBelt.toUpperCase()}</h2>
<div class="score" style="color: ${color}">
${score} / ${questions.length}
</div>
<div style="font-size: 2em; margin: 20px 0;">
${percentage}%
</div>
<div class="verdict" style="border-color: ${color}">
${verdict}
</div>
<div class="export-info">
<p><strong>📋 Ergebnis exportiert!</strong></p>
<p>Die Ergebnisse wurden in die Zwischenablage kopiert.</p>
<p>Füge sie im Terminal ein für die Auswertung!</p>
<br>
<button class="btn btn-primary" onclick="location.reload()">🔄 Neue Prüfung</button>
</div>
`;
document.getElementById('quizContainer').classList.remove('active');
document.getElementById('results').classList.add('show');
// Copy to clipboard
const exportText = JSON.stringify(resultData, null, 2);
navigator.clipboard.writeText(exportText).then(() => {
console.log('Ergebnisse in Zwischenablage kopiert!');
});
}
</script>
</body>
</html>