ThetaPhiPsi commited on
Commit
a35d7b3
·
verified ·
1 Parent(s): 6a4c654

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +152 -8
index.html CHANGED
@@ -44,6 +44,16 @@
44
  .sad-face {
45
  transform: rotate(180deg);
46
  }
 
 
 
 
 
 
 
 
 
 
47
  </style>
48
  </head>
49
  <body class="bg-blue-50 min-h-screen flex flex-col items-center font-sans">
@@ -54,7 +64,7 @@
54
  </header>
55
 
56
  <main class="container mx-auto px-4 py-8 flex-grow flex flex-col items-center">
57
- <div class="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6 mb-8">
58
  <div class="flex flex-col md:flex-row gap-8">
59
  <!-- Hangman Drawing -->
60
  <div class="w-full md:w-1/2 flex flex-col items-center">
@@ -92,6 +102,7 @@
92
  <div class="w-full md:w-1/2 flex flex-col">
93
  <div class="mb-6">
94
  <p class="text-gray-600 mb-2">Kategorie: <span id="category" class="font-semibold">Tiere</span></p>
 
95
  <div id="word-display" class="flex justify-center gap-2 mb-6 flex-wrap"></div>
96
  </div>
97
 
@@ -111,7 +122,7 @@
111
  <div id="message" class="hidden mb-4 p-3 rounded-lg text-center font-bold"></div>
112
 
113
  <button id="new-game-button" class="mt-auto bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition-colors hidden">
114
- Neues Spiel starten
115
  </button>
116
  </div>
117
  </div>
@@ -146,6 +157,46 @@
146
  </div>
147
  </div>
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  <div class="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6">
150
  <h2 class="text-xl font-bold mb-4 text-center">Wie spielt man?</h2>
151
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
@@ -292,6 +343,16 @@
292
  let gameHistory = JSON.parse(localStorage.getItem('norasGameHistory')) || [];
293
  let wins = 0;
294
  let losses = 0;
 
 
 
 
 
 
 
 
 
 
295
 
296
  // DOM elements
297
  const wordDisplay = document.getElementById('word-display');
@@ -318,6 +379,16 @@
318
  const wrongSound = document.getElementById('wrong-sound');
319
  const winSound = document.getElementById('win-sound');
320
  const loseSound = document.getElementById('lose-sound');
 
 
 
 
 
 
 
 
 
 
321
 
322
  // Initialize the game
323
  function initGame() {
@@ -344,17 +415,33 @@
344
  face.classList.remove('sad-face');
345
  face.classList.add('happy-face');
346
 
347
- // Select a random category
348
- const categories = Object.keys(wordCategories);
349
- currentCategory = categories[Math.floor(Math.random() * categories.length)];
 
 
 
 
 
 
 
 
 
350
  categoryDisplay.textContent = wordCategories[currentCategory].name;
351
 
352
- // Select a random word from the category
353
- const words = wordCategories[currentCategory].words;
354
- const randomWordObj = words[Math.floor(Math.random() * words.length)];
 
 
 
355
  currentWord = randomWordObj.word;
356
  hintText.textContent = randomWordObj.hint;
357
 
 
 
 
 
358
  // Update UI
359
  updateMistakesDisplay();
360
  createWordDisplay();
@@ -489,6 +576,9 @@
489
  winSound.currentTime = 0;
490
  winSound.play();
491
 
 
 
 
492
  // Add to game history
493
  addToGameHistory(true);
494
  createConfetti();
@@ -508,6 +598,11 @@
508
  loseSound.currentTime = 0;
509
  loseSound.play();
510
 
 
 
 
 
 
511
  // Add to game history
512
  addToGameHistory(false);
513
 
@@ -554,6 +649,7 @@
554
 
555
  // Save to localStorage
556
  localStorage.setItem('norasGameHistory', JSON.stringify(gameHistory));
 
557
 
558
  // Update stats
559
  updateStats();
@@ -592,6 +688,39 @@
592
  lossesDisplay.textContent = losses;
593
  }
594
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
  // Show hint
596
  hintButton.addEventListener('click', function() {
597
  if (!hintUsed && gameActive) {
@@ -604,6 +733,13 @@
604
  // New game button
605
  newGameButton.addEventListener('click', initGame);
606
 
 
 
 
 
 
 
 
607
  // Toggle game history visibility
608
  toggleHistoryButton.addEventListener('click', function() {
609
  if (gameHistorySection.classList.contains('hidden')) {
@@ -644,6 +780,14 @@
644
  }
645
  }
646
 
 
 
 
 
 
 
 
 
647
  // Start the game
648
  initGame();
649
  updateStats();
 
44
  .sad-face {
45
  transform: rotate(180deg);
46
  }
47
+ .final-stats {
48
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
49
+ border-radius: 1rem;
50
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
51
+ }
52
+ .progress-ring {
53
+ transition: stroke-dashoffset 0.5s;
54
+ transform: rotate(-90deg);
55
+ transform-origin: 50% 50%;
56
+ }
57
  </style>
58
  </head>
59
  <body class="bg-blue-50 min-h-screen flex flex-col items-center font-sans">
 
64
  </header>
65
 
66
  <main class="container mx-auto px-4 py-8 flex-grow flex flex-col items-center">
67
+ <div id="game-container" class="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6 mb-8">
68
  <div class="flex flex-col md:flex-row gap-8">
69
  <!-- Hangman Drawing -->
70
  <div class="w-full md:w-1/2 flex flex-col items-center">
 
102
  <div class="w-full md:w-1/2 flex flex-col">
103
  <div class="mb-6">
104
  <p class="text-gray-600 mb-2">Kategorie: <span id="category" class="font-semibold">Tiere</span></p>
105
+ <p class="text-gray-600 mb-2">Wörter übrig: <span id="words-left" class="font-semibold">10</span></p>
106
  <div id="word-display" class="flex justify-center gap-2 mb-6 flex-wrap"></div>
107
  </div>
108
 
 
122
  <div id="message" class="hidden mb-4 p-3 rounded-lg text-center font-bold"></div>
123
 
124
  <button id="new-game-button" class="mt-auto bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition-colors hidden">
125
+ Nächstes Wort
126
  </button>
127
  </div>
128
  </div>
 
157
  </div>
158
  </div>
159
 
160
+ <!-- Final Statistics -->
161
+ <div id="final-stats" class="w-full max-w-4xl final-stats p-8 mb-8 hidden">
162
+ <h2 class="text-3xl font-bold text-center mb-6">Spiel beendet! 🎉</h2>
163
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8 items-center">
164
+ <div>
165
+ <h3 class="text-xl font-semibold mb-4">Zusammenfassung</h3>
166
+ <div class="space-y-4">
167
+ <div class="flex justify-between items-center">
168
+ <span class="text-gray-700">Gewonnene Spiele:</span>
169
+ <span id="final-wins" class="font-bold text-green-600">0</span>
170
+ </div>
171
+ <div class="flex justify-between items-center">
172
+ <span class="text-gray-700">Verlorene Spiele:</span>
173
+ <span id="final-losses" class="font-bold text-red-600">0</span>
174
+ </div>
175
+ <div class="flex justify-between items-center">
176
+ <span class="text-gray-700">Wörter erraten:</span>
177
+ <span id="words-guessed" class="font-bold text-blue-600">0/0</span>
178
+ </div>
179
+ <div class="flex justify-between items-center">
180
+ <span class="text-gray-700">Durchschnittliche Fehler:</span>
181
+ <span id="avg-mistakes" class="font-bold text-purple-600">0</span>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ <div class="flex flex-col items-center">
186
+ <svg width="200" height="200" viewBox="0 0 200 200" class="mb-4">
187
+ <circle cx="100" cy="100" r="90" fill="none" stroke="#e5e7eb" stroke-width="10"/>
188
+ <circle id="win-ring" cx="100" cy="100" r="90" fill="none" stroke="#10b981" stroke-width="10" stroke-dasharray="565.48" stroke-dashoffset="565.48" class="progress-ring"/>
189
+ </svg>
190
+ <p class="text-center text-gray-700">Erfolgsquote: <span id="success-rate" class="font-bold">0</span>%</p>
191
+ </div>
192
+ </div>
193
+ <div class="mt-8 text-center">
194
+ <button id="restart-game-button" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition-colors">
195
+ <i class="fas fa-redo mr-2"></i>Neues Spiel starten
196
+ </button>
197
+ </div>
198
+ </div>
199
+
200
  <div class="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6">
201
  <h2 class="text-xl font-bold mb-4 text-center">Wie spielt man?</h2>
202
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
 
343
  let gameHistory = JSON.parse(localStorage.getItem('norasGameHistory')) || [];
344
  let wins = 0;
345
  let losses = 0;
346
+ let usedWords = {};
347
+ let wordsLeft = 0;
348
+
349
+ // Initialize usedWords object
350
+ function initUsedWords() {
351
+ usedWords = {};
352
+ for (const category in wordCategories) {
353
+ usedWords[category] = [];
354
+ }
355
+ }
356
 
357
  // DOM elements
358
  const wordDisplay = document.getElementById('word-display');
 
379
  const wrongSound = document.getElementById('wrong-sound');
380
  const winSound = document.getElementById('win-sound');
381
  const loseSound = document.getElementById('lose-sound');
382
+ const wordsLeftDisplay = document.getElementById('words-left');
383
+ const finalStatsSection = document.getElementById('final-stats');
384
+ const finalWinsDisplay = document.getElementById('final-wins');
385
+ const finalLossesDisplay = document.getElementById('final-losses');
386
+ const wordsGuessedDisplay = document.getElementById('words-guessed');
387
+ const avgMistakesDisplay = document.getElementById('avg-mistakes');
388
+ const successRateDisplay = document.getElementById('success-rate');
389
+ const restartGameButton = document.getElementById('restart-game-button');
390
+ const winRing = document.getElementById('win-ring');
391
+ const gameContainer = document.getElementById('game-container');
392
 
393
  // Initialize the game
394
  function initGame() {
 
415
  face.classList.remove('sad-face');
416
  face.classList.add('happy-face');
417
 
418
+ // Select a random category that still has words left
419
+ const availableCategories = Object.keys(wordCategories).filter(category => {
420
+ return wordCategories[category].words.length > usedWords[category].length;
421
+ });
422
+
423
+ // If no categories have words left, show final stats
424
+ if (availableCategories.length === 0) {
425
+ showFinalStats();
426
+ return;
427
+ }
428
+
429
+ currentCategory = availableCategories[Math.floor(Math.random() * availableCategories.length)];
430
  categoryDisplay.textContent = wordCategories[currentCategory].name;
431
 
432
+ // Select a random word from the category that hasn't been used yet
433
+ const availableWords = wordCategories[currentCategory].words.filter(wordObj => {
434
+ return !usedWords[currentCategory].includes(wordObj.word);
435
+ });
436
+
437
+ const randomWordObj = availableWords[Math.floor(Math.random() * availableWords.length)];
438
  currentWord = randomWordObj.word;
439
  hintText.textContent = randomWordObj.hint;
440
 
441
+ // Update words left display
442
+ wordsLeft = wordCategories[currentCategory].words.length - usedWords[currentCategory].length - 1;
443
+ wordsLeftDisplay.textContent = wordsLeft;
444
+
445
  // Update UI
446
  updateMistakesDisplay();
447
  createWordDisplay();
 
576
  winSound.currentTime = 0;
577
  winSound.play();
578
 
579
+ // Mark word as used
580
+ usedWords[currentCategory].push(currentWord);
581
+
582
  // Add to game history
583
  addToGameHistory(true);
584
  createConfetti();
 
598
  loseSound.currentTime = 0;
599
  loseSound.play();
600
 
601
+ // Mark word as used (only if not already marked)
602
+ if (!usedWords[currentCategory].includes(currentWord)) {
603
+ usedWords[currentCategory].push(currentWord);
604
+ }
605
+
606
  // Add to game history
607
  addToGameHistory(false);
608
 
 
649
 
650
  // Save to localStorage
651
  localStorage.setItem('norasGameHistory', JSON.stringify(gameHistory));
652
+ localStorage.setItem('norasUsedWords', JSON.stringify(usedWords));
653
 
654
  // Update stats
655
  updateStats();
 
688
  lossesDisplay.textContent = losses;
689
  }
690
 
691
+ // Show final statistics
692
+ function showFinalStats() {
693
+ gameContainer.classList.add('hidden');
694
+ finalStatsSection.classList.remove('hidden');
695
+
696
+ const totalGames = wins + losses;
697
+ const successRate = totalGames > 0 ? Math.round((wins / totalGames) * 100) : 0;
698
+ const totalMistakes = gameHistory.reduce((sum, game) => sum + game.mistakes, 0);
699
+ const avgMistakes = totalGames > 0 ? (totalMistakes / totalGames).toFixed(1) : 0;
700
+
701
+ // Calculate total words guessed
702
+ let totalWords = 0;
703
+ let guessedWords = 0;
704
+ for (const category in wordCategories) {
705
+ totalWords += wordCategories[category].words.length;
706
+ guessedWords += usedWords[category].length;
707
+ }
708
+
709
+ finalWinsDisplay.textContent = wins;
710
+ finalLossesDisplay.textContent = losses;
711
+ wordsGuessedDisplay.textContent = `${guessedWords}/${totalWords}`;
712
+ avgMistakesDisplay.textContent = avgMistakes;
713
+ successRateDisplay.textContent = successRate;
714
+
715
+ // Animate the progress ring
716
+ const circumference = 2 * Math.PI * 90;
717
+ const offset = circumference - (successRate / 100) * circumference;
718
+ winRing.style.strokeDashoffset = offset;
719
+
720
+ // Reset used words for a new game
721
+ initUsedWords();
722
+ }
723
+
724
  // Show hint
725
  hintButton.addEventListener('click', function() {
726
  if (!hintUsed && gameActive) {
 
733
  // New game button
734
  newGameButton.addEventListener('click', initGame);
735
 
736
+ // Restart game button (from final stats)
737
+ restartGameButton.addEventListener('click', function() {
738
+ finalStatsSection.classList.add('hidden');
739
+ gameContainer.classList.remove('hidden');
740
+ initGame();
741
+ });
742
+
743
  // Toggle game history visibility
744
  toggleHistoryButton.addEventListener('click', function() {
745
  if (gameHistorySection.classList.contains('hidden')) {
 
780
  }
781
  }
782
 
783
+ // Load used words from localStorage
784
+ const savedUsedWords = localStorage.getItem('norasUsedWords');
785
+ if (savedUsedWords) {
786
+ usedWords = JSON.parse(savedUsedWords);
787
+ } else {
788
+ initUsedWords();
789
+ }
790
+
791
  // Start the game
792
  initGame();
793
  updateStats();