Compare commits

...

18 Commits

Author SHA1 Message Date
Ismail Amara
01759611fd last edit 2026-03-05 13:01:44 +01:00
Ismail Amara
cc3a5984e8 Merge branch 'master' of https://git.bib.de/PBT3H24AKH/LerningCSW 2026-03-04 10:00:09 +01:00
Ismail Amara
ae5c506154 index.html
style.css
script.js
2026-03-04 10:00:03 +01:00
6151379f81 Readme.md aktualisiert 2026-03-02 14:30:09 +01:00
abdelaziz
7ffb9dcac4 Fix Broken Parts And Mistakes 2026-02-26 00:13:49 +01:00
abdelaziz
db73585839 Merge branch 'master' of https://git.bib.de/PBT3H24AKH/LerningCSW 2026-02-25 23:21:02 +01:00
Your Name
678e4d5089 zweiter push 2026-02-25 14:59:38 +01:00
Your Name
5673154e69 saad akki upload 2026-02-25 14:52:36 +01:00
624ef64c5e Readme.md aktualisiert 2026-02-25 14:48:34 +01:00
74db15fc24 Readme.md hinzugefügt 2026-02-25 14:40:07 +01:00
0477eb207e Projekt fertiggestellt: Voll funktionsfähiges Lerntraining 2026-02-25 14:16:32 +01:00
abdelaziz
5d1549e90e Added Data As Puzzles
English(2)/German(3)
2026-02-25 07:54:23 +01:00
bd2fea40fc Online-Training: Flip, Multiple, Matching, Hint, Schreiben 2026-02-22 01:03:42 +01:00
abdelaziz
b1ffd825db Merge branch 'master' of https://git.bib.de/PBT3H24AKH/LerningCSW 2026-02-17 11:25:18 +01:00
abdelaziz
02940021e2 Added Clues/Input as Columns/Columns,rows Detection 2026-02-17 11:25:11 +01:00
El Haddoury Younes
63298248c7 CMMENTS ÄNDERUNGEN 2026-02-17 11:07:33 +01:00
El Haddoury Younes
1cb51dd802 comment editieren , mehr deteirt 2026-02-10 12:09:47 +01:00
El Haddoury Younes
3b100eaf11 logik änderungen , bugs fixes , comment hinzufugt 2026-02-10 12:06:06 +01:00
12 changed files with 2794 additions and 778 deletions

View File

@@ -1,172 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Crossword Puzzle</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: #fff;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
color: #000;
margin-bottom: 20px;
font-size: 24px;
}
.grid-wrapper {
display: flex;
justify-content: center;
margin: 20px 0;
}
.crossword-grid {
display: inline-grid;
gap: 0;
border: 2px solid #000;
}
.cell {
width: 30px;
height: 30px;
border: 1px solid #000;
background: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
position: relative;
}
.cell.blocked {
background: #000;
}
.cell input {
width: 100%;
height: 100%;
border: none;
text-align: center;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
background: transparent;
outline: none;
}
.cell-number {
position: absolute;
top: 1px;
left: 2px;
font-size: 8px;
font-weight: normal;
color: #000;
}
.clues {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-top: 30px;
}
.clues-section h3 {
font-size: 18px;
margin-bottom: 10px;
border-bottom: 2px solid #000;
padding-bottom: 5px;
}
.clue {
padding: 5px 0;
font-size: 14px;
line-height: 1.5;
}
</style>
</head>
<body>
<div class="container">
<h1>Crossword Puzzle - 21×21</h1>
<div class="grid-wrapper">
<div class="crossword-grid" id="grid"></div>
</div>
<div class="clues">
<div class="clues-section">
<h3>Across</h3>
<div id="cluesAcross">
</div>
</div>
<div class="clues-section">
<h3>Down</h3>
<div id="cluesDown">
</div>
</div>
</div>
</div>
<script>
const GRID_SIZE = 21;
function createGrid() {
const grid = document.getElementById('grid');
grid.style.gridTemplateColumns = `repeat(${GRID_SIZE}, 30px)`;
let clueNumber = 1;
for (let r = 0; r < GRID_SIZE; r++) {
for (let c = 0; c < GRID_SIZE; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
const isBlocked = (r + c) % 7 === 0 && r % 3 === 0;
if (isBlocked) {
cell.classList.add('blocked');
} else {
const needsNumber = (c === 0 || (c > 0 && isBlackSquare(r, c-1))) ||
(r === 0 || (r > 0 && isBlackSquare(r-1, c)));
if (needsNumber && (c < GRID_SIZE-1 || r < GRID_SIZE-1)) {
const num = document.createElement('span');
num.className = 'cell-number';
num.textContent = clueNumber++;
cell.appendChild(num);
}
const input = document.createElement('input');
input.maxLength = 1;
cell.appendChild(input);
}
grid.appendChild(cell);
}
}
}
function isBlackSquare(r, c) {
return (r + c) % 7 === 0 && r % 3 === 0;
}
createGrid();
</script>
</body>
</html>

View File

@@ -0,0 +1,285 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Rätsel</title>
<style>
body { font-family: Arial, sans-serif; font-size: 13px; padding: 10px; }
h1 { font-size: 15px; margin-bottom: 6px; }
.tabs { display: flex; gap: 4px; margin-bottom: 8px; flex-wrap: wrap; align-items: center; }
.tab-group { font-size: 10px; color: #666; padding: 4px 6px; }
.tab { padding: 4px 10px; border: 1px solid #999; background: #f0f0f0; cursor: pointer; font-size: 12px; border-radius: 3px; }
.tab.active { background: #000; color: #fff; border-color: #000; }
.richtung { display: flex; gap: 4px; margin-bottom: 6px; }
.rbtn { padding: 3px 9px; border: 1px solid #aaa; background: #f5f5f5; cursor: pointer; font-size: 11px; }
.rbtn.active { background: #444; color: #fff; }
.layout { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-start; }
.grid { display: grid; border-top: 2px solid #000; border-left: 2px solid #000; }
.z {
width: 26px; height: 26px;
border-right: 1px solid #bbb; border-bottom: 1px solid #bbb;
position: relative;
}
.z.er { border-right: 2px solid #000; }
.z.eb { border-bottom: 2px solid #000; }
.z.schwarz { background: #000; }
.z.markiert { background: #c5ddf7; }
.z.aktiv { background: #3a6fd8; }
.z.aktiv input, .z.aktiv .nr { color: #fff; }
.z.richtig { background: #b8f0c8 !important; }
.z.falsch { background: #f0b8b8 !important; }
.z input {
width: 100%; height: 100%;
border: none; background: transparent;
font-size: 11px; font-weight: bold;
text-align: center; text-transform: uppercase;
outline: none; padding-top: 4px; caret-color: transparent;
}
.nr { position: absolute; top: 1px; left: 2px; font-size: 6px; pointer-events: none; color: #666; }
.knopfe { display: flex; gap: 5px; margin-top: 7px; }
.k { padding: 4px 10px; border: 1px solid #555; background: #fff; cursor: pointer; font-size: 11px; }
.k:hover { background: #eee; }
.k.los { background: #000; color: #fff; border-color: #000; }
#info { margin-top: 5px; font-size: 12px; font-weight: bold; min-height: 14px; }
.gut { color: green; }
.nein { color: #c00; }
.hinweise { max-width: 340px; flex: 1; max-height: 560px; overflow-y: auto; }
.hw { font-size: 11px; font-weight: bold; border-bottom: 1px solid #000; margin: 8px 0 3px; text-transform: uppercase; }
.h { display: flex; gap: 4px; font-size: 11px; line-height: 1.5; padding: 1px 3px; }
.hnum { min-width: 20px; flex-shrink: 0; font-weight: bold; color: #666; }
</style>
</head>
<body>
<h1>Rätsel</h1>
<div class="tabs">
<span class="tab-group">Deutsch:</span>
<button class="tab active" onclick="lade(0)">Tiere</button>
<button class="tab" onclick="lade(1)">Essen</button>
<button class="tab" onclick="lade(2)">Europa</button>
<button class="tab" onclick="lade(3)">Körper</button>
<span class="tab-group">English:</span>
<button class="tab" onclick="lade(4)">Puzzle A</button>
<button class="tab" onclick="lade(5)">Puzzle B</button>
</div>
<div class="layout">
<div>
<div class="richtung">
<button class="rbtn active" id="btnQ" onclick="setDir('across')">→ Waagerecht</button>
<button class="rbtn" id="btnW" onclick="setDir('down')">↓ Senkrecht</button>
</div>
<div class="grid" id="grid"></div>
<div class="knopfe">
<button class="k los" onclick="pruefen()">Prüfen / Check</button>
<button class="k" onclick="loesung()">Lösung</button>
<button class="k" onclick="loeschen()">✕ Löschen</button>
</div>
<div id="info"></div>
</div>
<div class="hinweise" id="hinweise"></div>
</div>
<script>
let richtung='across', ar=-1, ac=-1;
let felder=[], nummern={across:{},down:{}};
let lsg, ha, hd;
let GR=13;
const RAETSEL=[
{gr:13,titel:'Tiere',
lsg:{"0,0":"F","0,1":"U","0,2":"C","0,3":"H","0,4":"S","0,7":"Z","0,8":"E","0,9":"B","0,10":"R","0,11":"A","1,0":"A","1,1":"H","1,4":"T","2,0":"L","2,1":"U","2,2":"F","2,3":"T","2,4":"O","3,0":"K","3,1":"A","3,2":"T","3,3":"E","3,4":"R","4,0":"E","4,1":"L","4,2":"C","4,3":"H","4,4":"C","5,4":"H","5,5":"U","5,6":"N","5,7":"D","6,6":"R","6,7":"A","6,8":"B","6,9":"E","7,5":"L","7,6":"A","7,7":"C","7,8":"H","7,9":"S","8,7":"H","8,8":"A","8,9":"D","8,10":"L","8,11":"E","8,12":"R","9,4":"M","9,5":"A","9,6":"U","9,7":"S","9,8":"H","10,6":"G","10,7":"A","10,8":"N","10,9":"S","11,8":"W","11,9":"O","11,10":"L","11,11":"F"},
ha:{1:"Rotbraunes Tier mit buschigem Schwanz (5)",4:"Afrikanisches Tier mit Streifen (5)",6:"Was Vögel zum Fliegen brauchen (4)",9:"Männliche Katze (5)",10:"Großes Tier aus dem Norden — wie ein Hirsch (4)",11:"Bester Freund des Menschen (4)",14:"Schwarzer, kluger Vogel (4)",17:"Rosa Fisch aus dem Fluss (5)",19:"Kleines graues Nagetier (4)",21:"Weißer Hausvogel, gackert (4)",23:"Wilder Vorfahre des Hundes (4)"},
hd:{1:"Greifvogel, Wappentier Deutschlands (5)",2:"Nachtvogel mit großen Augen (3)",3:"Großer Zugvogel — nistet auf Dächern (6)",13:"Flaches, stacheliges Tier — gräbt Baue (5)"}},
{gr:13,titel:'Essen',
lsg:{"0,3":"W","0,4":"A","0,5":"S","0,6":"S","0,7":"E","0,8":"R","1,3":"E","1,4":"P","1,5":"A","1,8":"E","1,9":"S","1,10":"S","1,11":"E","1,12":"N","2,3":"I","2,4":"F","2,5":"H","2,7":"M","2,8":"I","2,9":"L","2,10":"C","2,11":"H","2,12":"U","3,3":"N","3,4":"E","3,5":"N","3,8":"S","3,9":"I","3,12":"S","4,4":"L","4,5":"E","4,6":"B","4,7":"E","4,8":"R","4,9":"N","4,12":"S","5,6":"I","5,7":"R","5,9":"S","6,0":"S","6,1":"A","6,2":"L","6,3":"Z","6,6":"R","6,7":"B","6,9":"E","7,0":"E","7,1":"N","7,2":"T","7,3":"E","7,6":"N","7,7":"S","8,0":"N","8,1":"I","8,6":"E","8,7":"E","9,0":"F","9,1":"S","10,0":"F","10,1":"I","10,2":"S","10,3":"C","10,4":"H"},
ha:{1:"Das wichtigste Getränk — klar, keine Kalorien (6)",6:"Mahlzeit haben — auch eine Stadt im Ruhrgebiet (5)",12:"Weißes Getränk von der Kuh (5)",15:"Organ im Körper — auch gebraten in der Pfanne (5)",19:"Gewürz aus dem Meer (4)",24:"Wasservogel — beliebt zu Weihnachten (4)",29:"Lebt im Wasser, hat Schuppen (5)"},
hd:{1:"Rotes oder weißes Getränk aus Trauben (4)",2:"Frucht — täglich gesund (5)",3:"Weiße Sauce für Desserts (5)",4:"Asiatische Beilage zu Curry (4)",10:"Harte Frucht vom Baum (4)",16:"Runde gelbe Frucht — hält den Arzt fern (5)",17:"Kleine grüne Hülsenfrucht (5)",19:"Gelbes, scharfes Gewürz auf Würstchen (4)",20:"Orientalisches Gewürz (4)"}},
{gr:13,titel:'Europa',
lsg:{"0,1":"P","0,2":"A","0,3":"R","0,4":"I","0,5":"S","0,7":"B","0,8":"E","0,9":"R","0,10":"L","0,11":"I","0,12":"N","1,1":"R","1,3":"H","1,5":"O","1,9":"E","1,12":"I","2,0":"H","2,1":"A","2,2":"I","2,3":"E","2,5":"F","2,9":"G","2,12":"L","3,1":"G","3,3":"I","3,5":"I","3,9":"E","4,3":"N","4,5":"A","4,6":"L","4,7":"P","4,8":"E","4,9":"N","5,6":"E","5,7":"I","5,8":"L","5,9":"O","5,10":"D","5,11":"Z","6,6":"C","6,7":"S","6,8":"B","6,9":"R","7,6":"H","7,7":"A","7,8":"E","7,9":"D","8,0":"E","8,1":"U","8,2":"R","8,3":"O","8,4":"P","8,5":"A","8,9":"E","9,0":"S","9,2":"U","9,9":"N","10,0":"S","10,1":"C","10,2":"H","10,3":"W","10,4":"E","10,5":"I","10,6":"Z","11,0":"E","11,2":"R","11,3":"H","11,4":"O","11,5":"N","11,6":"E","12,0":"N","12,1":"I","12,2":"Z","12,3":"Z","12,4":"A"},
ha:{1:"Hauptstadt Frankreichs (5)",4:"Hauptstadt Deutschlands (6)",7:"Haifische (4)",8:"Gebirge zwischen Deutschland, Österreich und Schweiz (5)",15:"Unser Kontinent (6)",17:"Kleines Alpenland — Uhren und Schokolade (7)",22:"Großer Fluss in Frankreich (5)",23:"Französische Riviera-Stadt (5)"},
hd:{1:"Hauptstadt Tschechiens (4)",2:"Wichtiger Fluss durch Köln (5)",3:"Hauptstadt Bulgariens (5)",5:"Wasser, das vom Himmel fällt (5)",6:"Längster Fluss der Welt (3)",9:"Fluss in Bayern (4)",10:"Ital. Stadt mit schiefem Turm (4)",11:"Fluss in Deutschland — mündet bei Hamburg (4)",15:"Stadt im Ruhrgebiet (5)",16:"Industriegebiet in Westdeutschland (4)"}},
{gr:13,titel:'Körper',
lsg:{"0,3":"K","0,4":"R","0,5":"A","0,6":"F","0,7":"T","1,4":"K","1,5":"N","1,6":"I","1,7":"E","2,4":"L","2,5":"U","2,6":"N","2,7":"G","2,8":"E","3,4":"M","3,5":"A","3,6":"G","3,7":"E","3,8":"N","4,4":"N","4,5":"I","4,6":"E","4,7":"R","4,8":"E","5,4":"H","5,5":"E","5,6":"R","5,7":"Z","5,8":"R","6,5":"H","6,6":"U","6,7":"N","6,8":"G","6,9":"E","6,10":"R","7,0":"B","7,1":"L","7,2":"U","7,3":"T","7,8":"I","8,6":"F","8,7":"I","8,8":"E","8,9":"B","8,10":"E","8,11":"R","9,0":"A","9,1":"R","9,2":"Z","9,3":"T","10,0":"S","10,1":"C","10,2":"H","10,3":"M","10,4":"E","10,5":"R","10,6":"Z","11,0":"A","11,1":"T","11,2":"E","11,3":"M","12,0":"S","12,1":"C","12,2":"H","12,3":"L","12,4":"A","12,5":"F"},
ha:{1:"Körperliche Stärke (5)",6:"Gelenk zwischen Ober- und Unterschenkel (4)",7:"Organ zum Atmen (5)",9:"Verdauungsorgan (5)",10:"Organ zur Blutfilterung (5)",11:"Pumpt das Blut (4)",12:"Wenn der Magen leer ist (6)",13:"Rote Flüssigkeit im Körper (4)",14:"Erhöhte Körpertemperatur (6)",15:"Mediziner, Doktor (4)",19:"Körperlicher Schmerz (7)",20:"Einatmen und ausatmen (4)",21:"Nachtruhe, Schlummer (6)"},
hd:{4:"Körperteil mit fünf Gliedern an der Hand (6)",8:"Körperliche Kraft und Vitalität (7)"}},
{gr:15,titel:'Puzzle A',
lsg:{"0,0":"B","0,1":"O","0,2":"Z","0,3":"O","0,4":"S","0,6":"A","0,7":"B","0,8":"D","0,9":"U","0,10":"L","0,12":"R","0,13":"A","0,14":"G","1,0":"I","1,1":"R","1,2":"A","1,3":"T","1,4":"E","1,6":"W","1,7":"E","1,8":"E","1,9":"P","1,10":"S","1,12":"E","1,13":"R","1,14":"A","2,0":"B","2,1":"A","2,2":"C","2,3":"H","2,4":"E","2,5":"L","2,6":"O","2,7":"R","2,8":"P","2,9":"A","2,10":"D","2,12":"C","2,13":"E","2,14":"L","3,1":"E","3,2":"Y","3,3":"E","3,4":"L","3,5":"E","3,6":"T","3,11":"B","3,12":"O","3,13":"N","3,14":"A","4,0":"O","4,1":"U","4,2":"T","4,3":"R","4,4":"O","4,5":"S","4,7":"T","4,8":"H","4,9":"E","4,10":"L","4,11":"O","4,12":"R","4,13":"A","4,14":"X","5,0":"U","5,1":"S","5,2":"A","5,4":"U","5,5":"S","5,6":"B","5,9":"W","5,10":"O","5,11":"O","5,12":"D","5,13":"S","5,14":"Y","6,0":"R","6,1":"E","6,2":"R","6,3":"A","6,4":"N","6,6":"R","6,7":"A","6,8":"C","6,9":"E","6,10":"B","6,11":"Y","7,1":"R","7,2":"O","7,3":"L","7,4":"E","7,5":"R","7,6":"E","7,7":"V","7,8":"E","7,9":"R","7,10":"S","7,11":"A","7,12":"L","7,13":"S","8,2":"I","8,3":"V","8,4":"O","8,5":"T","8,6":"E","8,7":"D","8,10":"T","8,11":"H","8,12":"E","8,13":"I","8,14":"R","9,0":"C","9,1":"H","9,2":"A","9,3":"S","9,4":"E","9,5":"D","9,7":"E","9,8":"S","9,9":"E","9,12":"F","9,13":"R","9,14":"O","10,0":"D","10,1":"E","10,2":"L","10,3":"O","10,4":"R","10,5":"E","10,6":"A","10,7":"N","10,9":"O","10,10":"R","10,11":"A","10,12":"T","10,13":"E","10,14":"D","11,0":"C","11,1":"A","11,2":"I","11,3":"N","11,5":"N","11,6":"I","11,7":"G","11,8":"H","11,9":"T","11,10":"S","12,0":"A","12,1":"T","12,2":"E","12,4":"N","12,5":"A","12,6":"V","12,7":"E","12,8":"L","12,9":"O","12,10":"R","12,11":"A","12,12":"N","12,13":"G","12,14":"E","13,0":"S","13,1":"U","13,2":"N","13,4":"T","13,5":"W","13,6":"I","13,7":"C","13,8":"E","13,10":"A","13,11":"D","13,12":"O","13,13":"R","13,14":"N","14,0":"E","14,1":"P","14,2":"S","14,4":"H","14,5":"E","14,6":"L","14,7":"E","14,8":"N","14,10":"P","14,11":"O","14,12":"S","14,13":"E","14,14":"D"},
ha:{1:"Silly people; clowns (5)",6:"Common Arabic/Turkish man's name (5)",11:"Torn piece of cloth (3)",14:"Very angry (5)",15:"Cries (5)",16:"Historical period (3)",17:"Flat shared by unmarried men (11)",19:"Single frame of animation film (3)",20:"Small hole in fabric for a lace or cord (6)",21:"Latin: ___ fide — in good faith (4)",22:"Final segments of a show — plural (6)",23:"Dr. Seuss character who speaks for the trees (8)",26:"Country whose capital is Washington (3)",27:"Universal Serial Bus — cable standard (3)",29:"Having a natural, forest-like feel (6)",30:"Ran again, as an election (5)",32:"To pass a competitor quickly (6)",35:"When villain becomes hero and vice versa (13)",39:"Cast a ballot — two words merged (6)",40:"Belonging to them (5)",42:"Pursued (6)",44:"East-southeast abbr. (3)",46:"Short round hairstyle (3)",47:"Futuristic sports car from a 1985 time-travel film (8)",49:"Spoke formally at length (6)",51:"Biblical first murderer (4)",52:"Hours of darkness — plural (6)",54:"Consumed food — past tense (3)",55:"Round citrus fruit with a belly button (11)",60:"Star at the center of our solar system (3)",61:"Two times (5)",62:"To decorate or add ornament (5)",63:"Greek letters — plural (3)",64:"Woman's name — also a famous Greek queen (5)",65:"Stood still for a photo (5)"},
hd:{1:"Curved part above the handle of a fishing rod (3)",2:"Seats in a theatre — plural (5)",3:"Large spiral galaxy visible from Earth (6)",4:"Belonging to that man (5)",5:"Old-fashioned word for what (4)",6:"Liquid in a bird's stomach (4)",7:"Drink of beer (4)",8:"Put down; set aside (4)",9:"Ripped open (4)",10:"Hallucinogenic drug abbr. (3)",11:"Written notes of a performance (6)",12:"Open spaces for public events — plural (6)",13:"Spiral shape — also a type of galaxy (6)",18:"Less than more (4)",21:"Enthusiastic cheer at celebrations (6)",22:"Pronoun for a group you belong to (3)",24:"Water-heating vessel with a spout (4)",25:"A freshwater fish dish (5)",28:"A type of soft cheese (4)",31:"A Scandinavian man's name (4)",33:"Another word for revenge (9)",34:"Two-letter word for a race at sea (2)",36:"Moved quickly past something (4)",37:"Departed; exited (4)",38:"One who sits on a throne (4)",41:"A thin stick or wand (3)",42:"Compact disc holder (6)",43:"To warm up; raise temperature (6)",45:"Musical note — doh, re, mi, ___ (4)",48:"Relating to the city (5)",50:"Moves quickly; runs fast (5)",53:"Abbreviation for a hill in a name (4)",55:"Not even the smallest amount (3)",56:"Fuss or commotion (3)",57:"Plural of no (3)",58:"Postgraduate degree abbr. (3)",59:"Final part; conclusion (3)"}},
{gr:15,titel:'Puzzle B',
lsg:{"0,0":"W","0,1":"O","0,2":"R","0,3":"T","0,4":"H","0,6":"A","0,7":"S","0,8":"H","0,10":"H","0,11":"A","0,12":"L","0,13":"O","1,0":"E","1,1":"N","1,2":"N","1,3":"U","1,4":"I","1,6":"T","1,7":"I","1,8":"E","1,10":"P","1,11":"A","1,12":"R","1,13":"E","1,14":"R","2,0":"B","2,1":"O","2,2":"A","2,3":"R","2,4":"D","2,5":"R","2,6":"O","2,7":"O","2,8":"M","2,10":"A","2,11":"I","2,12":"R","2,13":"E","2,14":"D","3,3":"K","3,4":"E","3,5":"A","3,6":"N","3,7":"U","3,9":"A","3,10":"T","3,11":"T","3,12":"I","3,13":"R","3,14":"E","4,0":"M","4,1":"R","4,2":"T","4,4":"T","4,5":"A","4,6":"X","4,7":"I","4,8":"D","4,9":"R","4,10":"I","4,11":"V","4,12":"E","4,13":"R","5,0":"C","5,1":"O","5,2":"U","5,3":"N","5,4":"S","5,5":"E","5,6":"L","5,8":"G","5,9":"O","5,10":"O","5,12":"E","5,13":"D","5,14":"S","6,0":"A","6,1":"S","6,2":"S","6,3":"E","6,4":"T","6,7":"N","6,8":"O","6,9":"B","6,10":"L","6,11":"E","7,0":"T","7,1":"A","7,2":"K","7,3":"E","7,4":"O","7,5":"F","7,6":"F","7,7":"R","7,8":"O","7,9":"M","7,10":"W","7,11":"O","7,12":"R","7,13":"K","8,4":"D","8,5":"W","8,6":"E","8,7":"L","8,8":"L","8,10":"A","8,11":"A","8,12":"R","8,13":"O","8,14":"N","9,0":"E","9,1":"B","9,2":"B","9,4":"A","9,5":"T","9,6":"A","9,8":"P","9,9":"E","9,10":"N","9,11":"N","9,12":"A","9,13":"M","9,14":"E","10,0":"F","10,1":"L","10,2":"Y","10,3":"S","10,4":"W","10,5":"A","10,6":"T","10,7":"T","10,8":"E","10,9":"R","10,11":"L","10,12":"E","10,13":"E","11,0":"F","11,1":"I","11,2":"L","11,3":"I","11,4":"A","11,5":"L","11,7":"B","11,8":"R","11,9":"I","11,10":"C","11,11":"E","12,0":"E","12,1":"M","12,2":"I","12,3":"L","12,4":"Y","12,6":"T","12,7":"O","12,8":"U","12,9":"C","12,10":"H","12,11":"D","12,12":"O","12,13":"W","12,14":"N","13,0":"T","13,1":"E","13,2":"N","13,3":"T","13,4":"S","13,6":"I","13,7":"N","13,8":"S","13,10":"I","13,11":"G","13,12":"L","13,13":"O","13,14":"O","14,0":"E","14,1":"Y","14,2":"E","14,3":"S","14,6":"S","14,7":"E","14,8":"E","14,10":"C","14,11":"E","14,12":"D","14,13":"E","14,14":"D"},
ha:{1:"Monetary value of something (5)",6:"Grey powder left after burning (3)",9:"Ring of light around a head in religious art (4)",13:"Deep feeling of boredom and emptiness (5)",14:"To bind or fasten together (3)",15:"Tool that peels vegetables (5)",17:"Main meeting room in a company (9)",19:"Broadcast on TV or radio (5)",20:"First name of actor known for action films set in Hawaii (5)",21:"Formal clothing for an event (6)",22:"Title for a married man — abbr. (3)",25:"A cab driver (10)",27:"Lawyer who gives advice (7)",29:"A sticky, slimy substance (3)",30:"Med school graduates — abbr. plural (3)",31:"Something of financial value on a balance sheet (5)",32:"Dignified and admirable in character (5)",34:"To take leave from work — three words merged (14)",39:"To live in a place; reside (5)",40:"Male name — also the first human in the Bible (5)",42:"The ocean's withdrawal from shore (3)",45:"Informal greeting — also a place to drink (3)",46:"A writer's false name (7)",48:"Flat tool used to kill flies (10)",51:"A name — also a compass point (3)",52:"Relating to family bonds (6)",53:"Woman's name — also French for price (5)",55:"Common English woman's name (5)",56:"In football: carrying ball into end zone (9)",60:"Small camping shelters — plural (5)",61:"Prepositions: within, inside — plural (3)",62:"Dome-shaped Inuit snow shelter (5)",63:"Organs of sight — plural (4)",64:"To look at; observe (3)",65:"Transferred ownership formally (5)"},
hd:{1:"A spider's creation (3)",2:"Short musical syllable (3)",3:"Ribonucleic acid abbr. (3)",4:"Citizen of a Central Asian country between Russia and China (4)",5:"To conceal; go into hiding (7)",6:"To make up for a wrongdoing (5)",7:"Signs or indications — plural (5)",8:"Head covering (3)",9:"Outdoor relaxing space with plants (6)",10:"Ability to fly; a plane journey (6)",11:"A moving staircase (9)",12:"Person who prepares articles for publication (6)",16:"A red gemstone (4)",18:"Reed instrument used in orchestras (4)",21:"Large ocean creature (4)",22:"Med school admission test abbr. (4)",23:"Female name — also a dew-covered flower (4)",24:"Elephant's long tooth (4)",28:"Particle with a negative charge abbr. (3)",32:"Thin pieces of wood for writing (3)",33:"Part of a plant between root and leaf (9)",35:"A clever physical trick (4)",36:"To accomplish something (4)",37:"Back part of a shoe (4)",38:"Lines forming the letter K (4)",41:"Overused and stale — past tense (6)",42:"British exclamation of surprise (6)",43:"Text of a newspaper article (6)",47:"Biblical king of Israel (4)",49:"Deposits of fine earth left by water (5)",50:"A cut of beef with a bone (5)",54:"Stylish and elegant (4)",56:"It is — contracted (3)",57:"Aged; not new (3)",58:"Sadness or trouble (3)",59:"Small nod of agreement (3)"}}
];
function setRichtung(d) {
richtung = d;
document.getElementById('btnQ').classList.toggle('active', d === 'across');
document.getElementById('btnW').classList.toggle('active', d === 'down');
}
function lade(idx) {
document.querySelectorAll('.tab').forEach((b,i) => b.classList.toggle('active', i === idx));
const p = RAETSEL[idx];
GR = p.gr; lsg = p.lsg; ha = p.ha; hd = p.hd;
setRichtung('across'); ar = -1; ac = -1;
felder = Array.from({length: GR}, () => Array(GR).fill(null));
nummern = {across: {}, down: {}};
document.getElementById('grid').style.gridTemplateColumns = `repeat(${GR},26px)`;
document.getElementById('info').textContent = '';
bauGrid();
}
function bauGrid() {
const g = document.getElementById('grid');
g.innerHTML = ''; let n = 1;
for (let r = 0; r < GR; r++) for (let c = 0; c < GR; c++) {
const el = document.createElement('div');
el.className = 'z';
if (c === GR-1) el.classList.add('er');
if (r === GR-1) el.classList.add('eb');
const k = `${r},${c}`;
if (!lsg[k]) {
el.classList.add('schwarz'); felder[r][c] = {bl: true, el};
} else {
const sa = (c===0 || !lsg[`${r},${c-1}`]) && lsg[`${r},${c+1}`];
const sd = (r===0 || !lsg[`${r-1},${c}`]) && lsg[`${r+1},${c}`];
if (sa || sd) {
const sp = document.createElement('span');
sp.className = 'nr'; sp.textContent = n;
if (sa) nummern.across[n] = {r, c};
if (sd) nummern.down[n] = {r, c};
el.appendChild(sp); n++;
}
const inp = document.createElement('input');
inp.type = 'text'; inp.maxLength = 1;
inp.setAttribute('autocomplete', 'off');
inp.setAttribute('autocorrect', 'off');
inp.setAttribute('spellcheck', 'false');
inp.addEventListener('focus', () => fokus(r, c));
inp.addEventListener('click', () => klick(r, c));
inp.addEventListener('keydown', e => taste(e, r, c));
inp.addEventListener('input', () => eingabe(r, c));
el.appendChild(inp);
felder[r][c] = {bl: false, el, inp};
}
g.appendChild(el);
}
bauHinweise();
}
function bauHinweise() {
const p = document.getElementById('hinweise');
p.innerHTML = '';
[['across', '→ Waagerecht', ha], ['down', '↓ Senkrecht', hd]].forEach(([d, label, clues]) => {
const h = document.createElement('div'); h.className = 'hw'; h.textContent = label; p.appendChild(h);
const map = d === 'across' ? nummern.across : nummern.down;
Object.keys(map).map(Number).sort((a,b) => a-b).forEach(num => {
if (!clues[num]) return;
const row = document.createElement('div');
row.className = 'h'; row.id = `h${d[0]}${num}`;
row.innerHTML = `<span class="hnum">${num}.</span><span>${clues[num]}</span>`;
p.appendChild(row);
});
});
}
function wort(r, c, d) {
const cs = [];
if (d === 'across') { let sc=c; while(sc>0 && lsg[`${r},${sc-1}`]) sc--; while(sc<GR && lsg[`${r},${sc}`]) { cs.push([r,sc]); sc++; } }
else { let sr=r; while(sr>0 && lsg[`${sr-1},${c}`]) sr--; while(sr<GR && lsg[`${sr},${c}`]) { cs.push([sr,c]); sr++; } }
return cs;
}
function zeigeAuswahl(r, c) {
const wc = wort(r, c, richtung);
for (let i=0; i<GR; i++) for (let j=0; j<GR; j++) { const d=felder[i][j]; if(d&&!d.bl) d.el.classList.remove('markiert','aktiv'); }
wc.forEach(([wr,wc2]) => felder[wr][wc2].el.classList.add('markiert'));
if (felder[r]?.[c] && !felder[r][c].bl) felder[r][c].el.classList.add('aktiv');
}
function fokus(r, c) { ar=r; ac=c; zeigeAuswahl(r, c); }
function klick(r, c) {
if (ar===r && ac===c) { setRichtung(richtung==='across' ? 'down' : 'across'); }
ar=r; ac=c; zeigeAuswahl(r, c);
}
function setDir(d) { setRichtung(d); if (ar>=0) zeigeAuswahl(ar, ac); }
function taste(e, r, c) {
const moves = {ArrowRight:[0,1], ArrowLeft:[0,-1], ArrowDown:[1,0], ArrowUp:[-1,0]};
if (moves[e.key]) { e.preventDefault(); const [dr,dc]=moves[e.key]; geh(r,c,dr,dc); }
else if (e.key==='Tab') { e.preventDefault(); naechstesWort(e.shiftKey ? -1 : 1); }
else if (e.key==='Backspace' && felder[r][c].inp.value==='') { e.preventDefault(); zurueck(r,c); }
}
function eingabe(r, c) {
const d = felder[r][c];
if (!d.inp.value.length) return;
d.inp.value = d.inp.value.slice(-1).toUpperCase();
d.el.classList.remove('richtig','falsch');
const wc = wort(r,c,richtung), idx = wc.findIndex(([wr,wc2]) => wr===r && wc2===c);
if (idx !== -1 && idx < wc.length-1) felder[wc[idx+1][0]][wc[idx+1][1]].inp.focus();
}
function geh(r, c, dr, dc) {
const nr=r+dr, nc=c+dc;
if (nr>=0 && nr<GR && nc>=0 && nc<GR) { const d=felder[nr][nc]; if(d&&!d.bl) d.inp.focus(); }
}
function zurueck(r, c) {
const wc=wort(r,c,richtung), idx=wc.findIndex(([wr,wc2]) => wr===r && wc2===c);
if (idx > 0) { felder[wc[idx-1][0]][wc[idx-1][1]].inp.value=''; felder[wc[idx-1][0]][wc[idx-1][1]].inp.focus(); }
}
function naechstesWort(delta) {
const map = richtung==='across' ? nummern.across : nummern.down;
const keys = Object.keys(map).map(Number).sort((a,b) => a-b);
const [sr,sc] = wort(ar,ac,richtung)[0];
const cur = keys.find(n => map[n].r===sr && map[n].c===sc);
const next = keys[((keys.indexOf(cur)+delta)+keys.length) % keys.length];
setRichtung(richtung);
felder[map[next].r][map[next].c].inp.focus();
}
function alleFelder(fn) {
for (let r=0; r<GR; r++) for (let c=0; c<GR; c++) {
const d = felder[r][c]; if (!d || d.bl) continue;
fn(d, r, c);
}
}
function pruefen() {
let ok=0, ng=0, em=0;
alleFelder((d,r,c) => {
d.el.classList.remove('richtig','falsch');
const v=d.inp.value.toUpperCase(), s=lsg[`${r},${c}`];
if (!v) { em++; return; }
if (v===s) { d.el.classList.add('richtig'); ok++; } else { d.el.classList.add('falsch'); ng++; }
});
const inf = document.getElementById('info');
if (ng===0 && em===0) { inf.textContent='Alles richtig! / All correct!'; inf.className='gut'; }
else { inf.textContent=`${ok}${ng} ? ${em}`; inf.className='nein'; }
}
function loesung() {
alleFelder((d,r,c) => {
const s = lsg[`${r},${c}`];
if (s) { d.inp.value=s; d.el.classList.remove('falsch'); d.el.classList.add('richtig'); }
});
document.getElementById('info').textContent='Lösung angezeigt.'; document.getElementById('info').className='gut';
}
function loeschen() {
alleFelder(d => { d.inp.value=''; d.el.classList.remove('richtig','falsch'); });
document.getElementById('info').textContent='';
}
lade(0);
</script>
</body>
</html>

View File

@@ -10,7 +10,7 @@
<h1>Team Game Platform</h1> <h1>Team Game Platform</h1>
<div class="games-container"> <div class="games-container">
<div class="game-card" onclick="location.href='member1/game.html'"> <div class="game-card" onclick="location.href='saad/index.html'">
<h2>Game 1</h2> <h2>Game 1</h2>
<p>Member 1</p> <p>Member 1</p>
</div> </div>
@@ -25,14 +25,14 @@
<p>Wörter lernen</p> <p>Wörter lernen</p>
</div> </div>
<div class="game-card" onclick="location.href='Abdelaziz/CrossWords.html'"> <div class="game-card" onclick="location.href='Abdelaziz/kreuzwortratsel.html'">
<h2>CrossWord</h2> <h2>CrossWord</h2>
<p>Abdelaziz</p> <p>Abdelaziz</p>
</div> </div>
<div class="game-card" onclick="location.href='member5/game.html'"> <div class="game-card" onclick="location.href='ismail/index.html'">
<h2>Game 5</h2> <h2>Game 5</h2>
<p>Member 5</p> <p>Mathematik lernen</p>
</div> </div>
</div> </div>
</body> </body>

View File

@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Mathematik Lernen</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Mathematik Lernen</h1>
<div id="setup">
<h2>Was willst du üben?</h2>
<div class="mode">
<button id="btn-addition" onclick="waehleMode('addition', this)">Addition</button>
<button id="btn-subtraktion" onclick="waehleMode('subtraktion', this)">Subtraktion</button>
<button id="btn-multiplikation" onclick="waehleMode('multiplikation', this)">Multiplikation</button>
<button id="btn-mix" onclick="waehleAlle()">Mix</button>
</div>
<h2>Wie schwer?</h2>
<div class="level">
<button onclick="waehleLevel('leicht', this)">Leicht (1-10)</button>
<button onclick="waehleLevel('mittel', this)">Mittel (1-50)</button>
<button onclick="waehleLevel('schwer', this)">Schwer (1-100)</button>
</div>
<h2>Wie viele Fragen?</h2>
<div class="anzahl">
<button onclick="waehleAnzahl(5, this)">5</button>
<button onclick="waehleAnzahl(10, this)">10</button>
<button onclick="waehleAnzahl(15, this)">15</button>
<button onclick="waehleAnzahl(20, this)">20</button>
<button onclick="waehleAnzahl(30, this)">30</button>
</div>
<p id="fehler"></p>
<button id="start-button" onclick="spielStarten()">▶ Starten!</button>
</div>
<div id="spiel">
<p id="fortschritt-text"></p>
<p id="timer"></p>
<div class="question-box">
<h2 id="question"></h2>
<input type="number" id="answer" placeholder="Deine Antwort">
<br>
<button onclick="checkAnswer()">Überprüfen</button>
<p id="result"></p>
</div>
<div class="score">
Punktzahl: <span id="score">0</span>
</div>
</div>
<div id="endscreen">
<h2 id="end-titel"></h2>
<div id="prozent"></div>
<p id="end-text"></p>
<p>Richtig: <b id="end-richtig"></b></p>
<p>Falsch: <b id="end-falsch"></b></p>
<button id="nochmal-button" onclick="nochmal()">Nochmal spielen</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

284
MainPage/ismail/script.js Normal file
View File

@@ -0,0 +1,284 @@
let num1
let num2
let correctAnswer
let score=0
let currentMode=""
let gewaehlteModes=[]
let gewaehltesLevel=""
let gewaehltAnzahl=0
let aktFrage=0
let richtigAnzahl=0
let falschAnzahl=0
let timerZahl=15
let timerInterval
let gesperrt=false
function waehleMode(mode,btn){
let index=gewaehlteModes.indexOf(mode)
if(index==-1){
gewaehlteModes.push(mode)
btn.classList.add("aktiv")
}else{
gewaehlteModes.splice(index,1)
btn.classList.remove("aktiv")
}
document.getElementById("btn-mix").classList.remove("aktiv")
}
function waehleAlle(){
gewaehlteModes=["addition","subtraktion","multiplikation"]
document.getElementById("btn-addition").classList.add("aktiv")
document.getElementById("btn-subtraktion").classList.add("aktiv")
document.getElementById("btn-multiplikation").classList.add("aktiv")
document.getElementById("btn-mix").classList.add("aktiv")
}
function waehleLevel(level,btn){
gewaehltesLevel=level
let alleLevel=document.querySelectorAll(".level button")
for(let i=0;i<alleLevel.length;i++){
alleLevel[i].classList.remove("aktiv")
}
btn.classList.add("aktiv")
}
function waehleAnzahl(anzahl,btn){
gewaehltAnzahl=anzahl
let alleAnzahl=document.querySelectorAll(".anzahl button")
for(let i=0;i<alleAnzahl.length;i++){
alleAnzahl[i].classList.remove("aktiv")
}
btn.classList.add("aktiv")
}
function spielStarten(){
if(gewaehlteModes.length==0){
document.getElementById("fehler").textContent="Bitte eine Rechenart wählen"
return
}
if(gewaehltesLevel==""){
document.getElementById("fehler").textContent="Bitte eine Schwierigkeit wählen"
return
}
if(gewaehltAnzahl==0){
document.getElementById("fehler").textContent="Bitte Anzahl Fragen wählen"
return
}
score=0
aktFrage=0
richtigAnzahl=0
falschAnzahl=0
document.getElementById("score").textContent=0
document.getElementById("setup").style.display="none"
document.getElementById("spiel").style.display="block"
document.getElementById("endscreen").style.display="none"
generateQuestion()
}
function generateQuestion(){
gesperrt=false
aktFrage++
document.getElementById("fortschritt-text").textContent="Frage "+aktFrage+" von "+gewaehltAnzahl
let zufallIndex=Math.floor(Math.random()*gewaehlteModes.length)
currentMode=gewaehlteModes[zufallIndex]
let maxZahl=10
if(gewaehltesLevel=="mittel")maxZahl=50
if(gewaehltesLevel=="schwer")maxZahl=100
num1=Math.floor(Math.random()*maxZahl)+1
num2=Math.floor(Math.random()*maxZahl)+1
if(currentMode==="addition"){
correctAnswer=num1+num2
document.getElementById("question").textContent=num1+" + "+num2+" = ?"
}
if(currentMode==="subtraktion"){
if(num2>num1){
let temp=num1
num1=num2
num2=temp
}
correctAnswer=num1-num2
document.getElementById("question").textContent=num1+" - "+num2+" = ?"
}
if(currentMode==="multiplikation"){
correctAnswer=num1*num2
document.getElementById("question").textContent=num1+" × "+num2+" = ?"
}
document.getElementById("answer").value=""
document.getElementById("result").textContent=""
document.getElementById("answer").focus()
timerStarten()
}
function timerStarten(){
clearInterval(timerInterval)
timerZahl=15
document.getElementById("timer").textContent="Zeit: "+timerZahl
document.getElementById("timer").style.color="green"
timerInterval=setInterval(function(){
timerZahl--
document.getElementById("timer").textContent="Zeit: "+timerZahl
if(timerZahl<=5){
document.getElementById("timer").style.color="red"
}
if(timerZahl<=0){
clearInterval(timerInterval)
zeitAbgelaufen()
}
},1000)
}
function zeitAbgelaufen(){
if(gesperrt)return
gesperrt=true
falschAnzahl++
document.getElementById("result").textContent="Zeit abgelaufen! Richtig wäre: "+correctAnswer
document.getElementById("result").style.color="orange"
setTimeout(naechsteOderEnde,2000)
}
function checkAnswer(){
if(gesperrt)return
let userAnswer=Number(document.getElementById("answer").value)
if(document.getElementById("answer").value=="")return
clearInterval(timerInterval)
gesperrt=true
let resultText=document.getElementById("result")
if(userAnswer===correctAnswer){
resultText.textContent="Richtig! Antwort: "+correctAnswer
resultText.style.color="green"
score++
richtigAnzahl++
document.getElementById("score").textContent=score
}else{
resultText.textContent="Falsch! Richtige Antwort: "+correctAnswer
resultText.style.color="red"
falschAnzahl++
}
setTimeout(naechsteOderEnde,2000)
}
function naechsteOderEnde(){
if(aktFrage>=gewaehltAnzahl){
spielEnde()
}else{
generateQuestion()
}
}
function spielEnde(){
clearInterval(timerInterval)
document.getElementById("spiel").style.display="none"
document.getElementById("endscreen").style.display="block"
let prozent=Math.round((richtigAnzahl/gewaehltAnzahl)*100)
document.getElementById("prozent").textContent=prozent+"%"
document.getElementById("end-richtig").textContent=richtigAnzahl
document.getElementById("end-falsch").textContent=falschAnzahl
document.getElementById("end-text").textContent="Du hast "+richtigAnzahl+" von "+gewaehltAnzahl+" richtig"
if(prozent==100){
document.getElementById("end-titel").textContent="Perfekt"
document.getElementById("prozent").style.color="gold"
}
else if(prozent>=70){
document.getElementById("end-titel").textContent="Sehr gut"
document.getElementById("prozent").style.color="green"
}
else if(prozent>=50){
document.getElementById("end-titel").textContent="Gut gemacht"
document.getElementById("prozent").style.color="orange"
}
else{
document.getElementById("end-titel").textContent="Weiter üben"
document.getElementById("prozent").style.color="red"
}
}
function nochmal(){
document.getElementById("endscreen").style.display="none"
document.getElementById("setup").style.display="block"
}

146
MainPage/ismail/style.css Normal file
View File

@@ -0,0 +1,146 @@
body{
font-family:Arial,sans-serif;
background:#f0f8ff;
text-align:center;
margin:0;
padding:0;
}
.container{
margin-top:40px;
}
h1,h2{
color:#333;
}
button{
padding:10px 20px;
margin:5px;
border:none;
border-radius:8px;
background:greenyellow;
color:white;
cursor:pointer;
font-size:16px;
}
button:hover{
background:greenyellow;
}
.mode button{
background:green;
}
.mode button.aktiv{
background:#1a7a1e;
border:3px solid black;
}
.level button{
background:#2196F3;
}
.level button:hover{
background:blue;
}
.level button.aktiv{
background:darkblue;
border:3px solid black;
}
.anzahl button{
background:orange;
}
.anzahl button:hover{
background:orange;
}
.anzahl button.aktiv{
background:brown;
border:3px solid black;
}
#start-button{
background:red;
font-size:18px;
padding:12px 30px;
margin-top:10px;
}
#start-button:hover{
background:red;
}
input{
padding:10px;
font-size:16px;
width:150px;
margin-top:10px;
border:2px solid gray;
border-radius:5px;
}
.question-box{
margin-top:20px;
}
.score{
margin-top:20px;
font-size:20px;
font-weight:bold;
}
#timer{
font-size:22px;
font-weight:bold;
color:green;
margin-top:10px;
}
#result{
font-size:18px;
font-weight:bold;
margin-top:10px;
}
#fortschritt-text{
font-size:16px;
color:gray;
margin-top:5px;
}
#endscreen{
display:none;
margin-top:30px;
}
#prozent{
font-size:52px;
font-weight:bold;
color:green;
}
#nochmal-button{
background:green;
font-size:18px;
padding:12px 28px;
margin-top:15px;
}
#setup{
margin-top:20px;
}
#spiel{
display:none;
margin-top:20px;
}
#fehler{
color:red;
font-weight:bold;
}

692
MainPage/saad/index.html Normal file
View File

@@ -0,0 +1,692 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WORDLE</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--bg: #faf8f3;
--surface: #f2ede4;
--ink: #1a1612;
--muted: #9e9488;
--border: #d8d0c4;
--correct: #4a7c59;
--present: #c97d2a;
--absent: #8a8278;
--correct-light: #d4ead9;
--present-light: #f5ddb8;
--absent-light: #d4d0cb;
--accent: #b5451b;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
background: var(--bg);
color: var(--ink);
font-family: 'DM Mono', monospace;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
}
/* Paper texture */
body::before {
content: '';
position: fixed;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 0;
}
header {
width: 100%;
max-width: 500px;
padding: 24px 20px 16px;
text-align: center;
border-bottom: 2px solid var(--ink);
position: relative;
z-index: 1;
}
h1 {
font-family: 'DM Serif Display', serif;
font-size: 2.8rem;
letter-spacing: 0.15em;
color: var(--ink);
line-height: 1;
}
.subtitle {
font-size: 0.6rem;
letter-spacing: 0.25em;
text-transform: uppercase;
color: var(--muted);
margin-top: 4px;
}
main {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 24px 16px;
position: relative;
z-index: 1;
width: 100%;
max-width: 500px;
}
/* Toast */
#toast {
position: fixed;
top: 80px;
left: 50%;
transform: translateX(-50%) translateY(-20px);
background: var(--ink);
color: var(--bg);
font-size: 0.75rem;
letter-spacing: 0.1em;
padding: 10px 20px;
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
pointer-events: none;
z-index: 100;
white-space: nowrap;
}
#toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* Grid */
#grid {
display: flex;
flex-direction: column;
gap: 6px;
}
.row {
display: flex;
gap: 6px;
}
.cell {
width: 60px;
height: 60px;
border: 2px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
font-family: 'DM Serif Display', serif;
font-size: 1.8rem;
color: var(--ink);
text-transform: uppercase;
position: relative;
transition: border-color 0.1s;
background: var(--bg);
}
.cell.filled {
border-color: var(--muted);
animation: pop 0.1s ease-out;
}
@keyframes pop {
0% { transform: scale(1); }
50% { transform: scale(1.08); }
100% { transform: scale(1); }
}
.cell.correct {
background: var(--correct);
border-color: var(--correct);
color: #fff;
}
.cell.present {
background: var(--present);
border-color: var(--present);
color: #fff;
}
.cell.absent {
background: var(--absent);
border-color: var(--absent);
color: #fff;
}
.cell.flip {
animation: flip 0.5s ease-in-out;
}
@keyframes flip {
0% { transform: rotateX(0deg); }
50% { transform: rotateX(-90deg); background: transparent; }
100% { transform: rotateX(0deg); }
}
.cell.shake {
animation: shake 0.4s ease-out;
}
@keyframes shake {
0%,100% { transform: translateX(0); }
20% { transform: translateX(-6px); }
40% { transform: translateX(6px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(4px); }
}
.cell.bounce {
animation: bounce 0.5s ease-out;
}
@keyframes bounce {
0%,100% { transform: translateY(0); }
40% { transform: translateY(-12px); }
70% { transform: translateY(-6px); }
}
/* Keyboard */
#keyboard {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
.kb-row {
display: flex;
gap: 6px;
}
.key {
height: 56px;
min-width: 36px;
padding: 0 8px;
border: 1.5px solid var(--border);
background: var(--surface);
color: var(--ink);
font-family: 'DM Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.05em;
text-transform: uppercase;
cursor: pointer;
transition: background 0.15s, border-color 0.15s, color 0.15s;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
.key:active { transform: scale(0.95); }
.key.wide { min-width: 56px; font-size: 0.65rem; }
.key.correct {
background: var(--correct);
border-color: var(--correct);
color: #fff;
}
.key.present {
background: var(--present);
border-color: var(--present);
color: #fff;
}
.key.absent {
background: var(--absent-light);
border-color: var(--absent-light);
color: var(--muted);
}
/* Win/Lose overlay */
#result-panel {
display: none;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 24px;
background: var(--surface);
border: 2px solid var(--ink);
width: 100%;
text-align: center;
}
#result-panel.show { display: flex; }
.result-title {
font-family: 'DM Serif Display', serif;
font-size: 2rem;
letter-spacing: 0.1em;
color: var(--ink);
}
.result-word {
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted);
}
.result-word strong {
font-family: 'DM Serif Display', serif;
font-size: 1.4rem;
color: var(--accent);
letter-spacing: 0.1em;
font-weight: normal;
display: block;
margin-top: 4px;
}
.play-btn {
margin-top: 8px;
font-family: 'DM Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
padding: 12px 32px;
background: var(--ink);
color: var(--bg);
border: none;
cursor: pointer;
transition: opacity 0.2s;
}
.play-btn:hover { opacity: 0.8; }
.stats-row {
display: flex;
gap: 24px;
}
.stat-item { text-align: center; }
.stat-n {
font-family: 'DM Serif Display', serif;
font-size: 1.8rem;
color: var(--ink);
}
.stat-l {
font-size: 0.55rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--muted);
}
</style>
</head>
<body>
<div id="toast"></div>
<header>
<h1>Wordle</h1>
<div class="subtitle">Guess the five-letter word</div>
</header>
<main>
<div id="grid"></div>
<div id="result-panel">
<div class="result-title" id="result-title">Brilliant!</div>
<div class="result-word">
The word was
<strong id="result-word-display"></strong>
</div>
<div class="stats-row">
<div class="stat-item"><div class="stat-n" id="stat-played">0</div><div class="stat-l">Played</div></div>
<div class="stat-item"><div class="stat-n" id="stat-wins">0</div><div class="stat-l">Wins</div></div>
<div class="stat-item"><div class="stat-n" id="stat-streak">0</div><div class="stat-l">Streak</div></div>
</div>
<button class="play-btn" onclick="newGame()">New Word</button>
</div>
<div id="keyboard"></div>
</main>
<script>
const WORDS = [
"CRANE","SLATE","TRACE","AUDIO","AROSE","STARE","SNARE","LEAST","IRATE","ARISE",
"PLUMB","FJORD","EQUIP","GLYPH","WALTZ","AFFIX","JUMPY","ONYX","PROXY","SIXTH",
"ABBEY","ABBOT","ABHOR","ABIDE","ABLER","ABODE","ABORT","ABOUT","ABOVE","ABUSE",
"ACUTE","ADMIT","ADOBE","ADOPT","ADULT","AFTER","AGAIN","AGENT","AGILE","AGING",
"AGONY","AGORA","AGREE","AHEAD","AIDER","AISLE","ALARM","ALBUM","ALERT","ALGAE",
"ALIBI","ALIGN","ALIVE","ALLAY","ALLEY","ALLOT","ALLOW","ALLOY","ALOFT","ALONE",
"ALONG","ALOOF","ALOUD","ALPEN","ALTAR","ALTER","AMAZE","AMBER","AMBLE","AMEND",
"AMISS","AMOUR","AMPLE","AMUSE","ANGEL","ANGER","ANGLE","ANGRY","ANGST","ANIME",
"ANKLE","ANNEX","ANTIC","ANVIL","AORTA","APPLE","APPLY","APRON","APTLY","ARBOR",
"ARDOR","ARENA","ARGUE","ARRAY","ARROW","ASIDE","ASKEW","ATONE","ATTIC","AUDIO",
"AUDIT","AVAIL","AVERT","AVID","AVOID","AWAIT","AWAKE","AWARD","AWARE","AWFUL",
"BASIC","BASIS","BATCH","BATHE","BAYOU","BEACH","BEARD","BEAST","BEGIN","BEING",
"BELOW","BENCH","BERRY","BIRTH","BISON","BITER","BLACK","BLADE","BLAME","BLAND",
"BLANK","BLARE","BLAST","BLAZE","BLEAK","BLEND","BLESS","BLIMP","BLIND","BLISS",
"BLOAT","BLOCK","BLOOD","BLOWN","BLUNT","BOARD","BOAST","BOOBY","BOOST","BOOTH",
"BOUND","BOXER","BRAID","BRAIN","BRAND","BRAVE","BRAVO","BRAWN","BREAD","BREAK",
"BREED","BRIEF","BRINE","BRING","BRISK","BROAD","BROKE","BROOK","BROWN","BRUTE",
"BUDDY","BUILD","BUILT","BULKY","BULLY","BUNNY","BURNT","BURST","BUYER","BYLAW",
"CADET","CAMEL","CANDY","CARGO","CAROL","CARRY","CARVE","CATCH","CAUSE","CEDAR",
"CHAIN","CHALK","CHAOS","CHARD","CHARM","CHART","CHASE","CHEAP","CHEAT","CHECK",
"CHEEK","CHEER","CHESS","CHEST","CHIEF","CHILD","CHINA","CHOIR","CHORD","CHOSE",
"CIVIC","CIVIL","CLAIM","CLAMP","CLASP","CLASS","CLEAN","CLEAR","CLERK","CLICK",
"CLIFF","CLIMB","CLING","CLOAK","CLOCK","CLONE","CLOSE","CLOTH","CLOUD","CLOWN",
"CLUMP","CLUNK","COMET","COMIC","CORAL","COUCH","COUGH","COULD","COUNT","COURT",
"COVER","COVET","COWARD","CRACK","CRAFT","CRAMP","CRASH","CRAZE","CRAZY","CREAM",
"CREEK","CREEP","CRIMP","CRISP","CROSS","CROWD","CROWN","CRUMB","CRUSH","CRUST",
"CRYPT","CUBIC","CURSE","CURVE","CYCLE","DAISY","DANCE","DARTS","DATUM","DAUNT",
"DEATH","DEBUT","DECAL","DECOY","DECRY","DEFER","DENIM","DENSE","DEPTH","DERBY",
"DETER","DETOX","DIGIT","DIRGE","DISCO","DITCH","DITTO","DIZZY","DODGE","DOING",
"DOMINO","DOUBT","DOUGH","DOWRY","DRAFT","DRAIN","DRAMA","DRAPE","DRAWN","DREAD",
"DRIFT","DRINK","DRIVE","DRONE","DROVE","DROWN","DRUID","DRYER","DUCHY","DULLY",
"EAGLE","EARLY","EARWORM","EASEL","EATEN","EDICT","EIGHT","EJECT","ELITE","EMBER",
"ENDOW","ENJOY","ENTER","ENVOY","EPOCH","EQUAL","ERROR","ESSAY","EVADE","EVENT",
"EVERY","EXACT","EXALT","EXERT","EXIST","EXTRA","FABLE","FACET","FAINT","FAIRY",
"FAITH","FALSE","FANCY","FARCE","FATAL","FAULT","FEAST","FEIGN","FERAL","FETCH",
"FEVER","FIEND","FIFTY","FIGHT","FINAL","FINCH","FIRST","FIXED","FLAIL","FLAME",
"FLANK","FLASH","FLASK","FLAIR","FLAW","FLESH","FLICK","FLING","FLINT","FLOAT",
"FLOOR","FLOUR","FLOWN","FLUTE","FOCUS","FOLLY","FORCE","FORGE","FORTH","FORUM",
"FOUND","FRAME","FRAUD","FREAK","FRESH","FRIAR","FRINGE","FRONT","FROST","FROZE",
"FRUIT","FULLY","FUNGI","FUNKY","FUNNY","GAUZE","GHOST","GIVEN","GIZMO","GLARE",
"GLAZE","GLEAM","GLEAN","GLIDE","GLOSS","GLOVE","GNARL","GNOME","GOUGE","GOURD",
"GRACE","GRADE","GRASP","GRATE","GRAZE","GREED","GREET","GRIEF","GRIME","GRIND",
"GROAN","GROIN","GROPE","GROSS","GROUP","GROVE","GROWL","GRUEL","GRUFF","GUILE",
"GUISE","GUSTO","HABIT","HASTE","HATCH","HAUNT","HAVEN","HEART","HEAVE","HEAVY",
"HEDGE","HEIST","HERON","HITCH","HOIST","HONOR","HORSE","HOTEL","HOUSE","HUMAN",
"HUMOR","HURRY","HUSKY","IDEAL","IMAGE","IMPLY","INBOX","INFER","INNER","INPUT",
"INTER","INTRO","IONIC","ISSUE","IVORY","JAZZY","JOUST","JUICE","JUICY","KAYAK",
"KHAKI","KNACK","KNEEL","KNIFE","KNOCK","KNOWN","KRAAL","KUDOS","LABEL","LANCE",
"LATCH","LATER","LATTE","LEARN","LEASE","LEAVE","LEGAL","LEMON","LEVEL","LIGHT",
"LINEN","LINER","LIVER","LOCAL","LODGE","LOGIC","LOOSE","LOUSE","LOVER","LUCID",
"LUCKY","LUNAR","MAGIC","MAJOR","MANOR","MAPLE","MARCH","MARSH","MATCH","MAYBE",
"MAYOR","MEDIA","MERCY","MERIT","METAL","MIGHT","MINCE","MINER","MINOR","MINUS",
"MIRTH","MISER","MOIST","MONEY","MONTH","MORAL","MOURN","MOUTH","MOVED","MOVIE",
"MUCKY","MUDDY","MURKY","MUSIC","NAIVE","NEEDY","NERVE","NEVER","NIGHT","NINJA",
"NOBLE","NOISE","NORTH","NOTCH","NOVEL","NURSE","NYMPH","OCCUR","OCEAN","OFFER",
"OLIVE","ONSET","OPERA","OPTIC","ORDER","OTHER","OUGHT","OUTER","OUNCE","OUTDO",
"OXIDE","OZONE","PAINT","PANIC","PAPER","PARCH","PARSE","PARTY","PASTA","PATCH",
"PAUSE","PEACE","PEACH","PEARL","PEDAL","PENNY","PERCH","PERIL","PETTY","PHASE",
"PHONE","PHOTO","PIANO","PIECE","PILOT","PINCH","PIRATE","PIXEL","PIZZA","PLACE",
"PLAIN","PLANE","PLANK","PLANT","PLAZA","PLEAD","PLEAT","PLUCK","PLUME","PLUNGE",
"POINT","POKER","POLAR","POLKA","POPPY","PORCH","POUND","POWER","PRANK","PRESS",
"PRICE","PRIDE","PRIME","PRINT","PRIZE","PROBE","PRONE","PROOF","PROSE","PROVE",
"PROWL","PRUNE","PSALM","PULSE","PUNCH","PUPIL","PURSE","QUEEN","QUERY","QUEST",
"QUEUE","QUIET","QUOTA","QUOTE","RABBI","RADAR","RADIO","RAISE","RALLY","RANCH",
"RANGE","RAPID","RAVEN","REACH","REALM","REBEL","REFER","REIGN","RELAX","REMIX",
"RENEW","REPAY","REPEL","REPENT","RERUN","RESET","RESIN","RIDER","RIDGE","RIGHT",
"RIGID","RISKY","RIVER","RIVET","ROBIN","ROBOT","ROCKY","ROMAN","ROUGH","ROUND",
"ROUTE","ROVER","ROYAL","RULER","RUSTY","SADLY","SAINT","SALVE","SAUCE","SAVOR",
"SCALE","SCALP","SCALD","SCANT","SCARE","SCARF","SCENE","SCENT","SCONE","SCOPE",
"SCORE","SCOUT","SCRAM","SCRAWL","SCREW","SCRUB","SEIZE","SENSE","SERUM","SERVE",
"SETUP","SEVEN","SHADE","SHAFT","SHAKE","SHAKY","SHAME","SHAPE","SHARE","SHARK",
"SHARP","SHEEN","SHEER","SHELF","SHIFT","SHINE","SHIRT","SHOCK","SHORE","SHORT",
"SHOUT","SHOVE","SHOWY","SIGHT","SILLY","SINCE","SIXTH","SIXTY","SKILL","SKIMP",
"SKIPPER","SKULL","SLACK","SLANT","SLEEK","SLEEP","SLEET","SLICK","SLIDE","SLIME",
"SLOPE","SLOSH","SLUMP","SLUNK","SMALL","SMART","SMEAR","SMELL","SMILE","SMIRK",
"SMOKE","SNACK","SNAIL","SNAKE","SNEAK","SNIFF","SOLVE","SONIC","SOUTH","SPACE",
"SPADE","SPARE","SPARK","SPEAK","SPEAR","SPECK","SPEED","SPEND","SPINE","SPIRE",
"SPITE","SPOON","SPORT","SPRAY","SPREE","SPRIG","SPROUT","SPUNK","SQUAD","SQUAT",
"SQUID","STACK","STAFF","STAGE","STAIN","STALK","STAMP","STAND","STASH","STAVE",
"STAYS","STEAK","STEAM","STEEL","STEEP","STEER","STERN","STICK","STIFF","STILL",
"STONE","STOOL","STORM","STORY","STOUT","STRAW","STRAY","STRIP","STRUT","STUCK",
"STUDY","STUNG","STUNK","STUNT","STYLE","SUAVE","SUGAR","SUITE","SULKY","SUMMON",
"SUPER","SURGE","SWAMP","SWEAR","SWEAT","SWEEP","SWEET","SWEPT","SWIFT","SWIPE",
"SWIRL","SWOOP","SWORD","SWORN","SYRUP","TABLE","TALON","TANGO","TAPIR","TAUNT",
"TAWNY","TEACH","TEASE","TEDDY","TEETH","TEMPO","TENSE","TEPID","THEFT","THEIR",
"THEME","THERE","THICK","THING","THINK","THORN","THREW","THROW","THUMB","THUMP",
"TIARA","TIGER","TIGHT","TIMER","TIPSY","TITAN","TITLE","TODAY","TOKEN","TONIC",
"TOTAL","TOUCH","TOUGH","TOWEL","TOWER","TOXIC","TRAIN","TRAMP","TRAPS","TRASH",
"TRAWL","TREAD","TREAT","TREND","TRICK","TRIED","TROOP","TROTH","TROUT","TROVE",
"TRUCE","TRULY","TRUMP","TRUNK","TRUST","TRUTH","TUMMY","TUNER","TUNIC","TUTOR",
"TWEED","TWICE","TWIRL","TWIST","TYING","ULCER","UNDER","UNFED","UNIFY","UNION",
"UNITY","UNTIL","UPPER","UPSET","URBAN","USAGE","USHER","UTTER","VALOR","VALVE",
"VAPID","VAULT","VERSE","VICAR","VIGOR","VIRAL","VIRUS","VISOR","VISTA","VIVID",
"VIXEN","VOCAL","VODKA","VOICE","VOILA","VOTER","VOUCH","VOWEL","WATCH","WATER",
"WEARY","WEAVE","WEDGE","WEEDY","WEIRD","WELCH","WHERE","WHILE","WHIFF","WHIRL",
"WINCE","WINDY","WITCH","WITTY","WORLD","WORRY","WORSE","WORST","WORTH","WOULD",
"WOUND","WRAITH","WRATH","WRECK","WREST","WRIST","WRONG","YEARN","YIELD","YOUNG",
"YOUTH","ZESTY","ZIPPY","ZONE"
].filter(w => w.length === 5);
const VALID_EXTRA = new Set([
"ABBOT","ABBOT","ALGAL","ALOFT","ALONG","APRON","ARMOR","ATOLL","ATONE","AUDIT",
"BALMY","BANAL","BAYOU","BEVEL","BLUNT","BROIL","BROOD","BUOY","CALYX","CAMEO",
"CIVIL","CLEFT","CLOUT","COLON","COMMA","CROAT","DELVE","DEPOT","DERBY","DIVINE",
"DOYLY","ECLAT","EGRET","ELBOW","ELUDE","ENVOY","EXPEL","EXTOL","FABLE","FACET",
"FAWNY","FELON","FETID","FIASCO","FLECK","FORAY","FORTE","FROND","FUROR","GAUDY",
"GOLEM","GRAIL","GUAVA","GUILD","HAVEN","HERON","INERT","INLAY","INTER","JOUST",
"KHAKI","KNAVE","LATHE","LEACH","LIBEL","LIVID","LLAMA","LUCID","LUSTY","MAXIM",
"MELEE","MERIT","MIRTH","MOIST","MOOSE","MOTIF","MURKY","MUSTY","NAIVE","OMEGA",
"OPTIC","OVOID","PAGAN","PAPAL","PATIO","PATSY","PEEVE","PETTY","PIXEL","PLAID",
"PLAZA","PLONK","PLUMB","POKER","POLYP","PORKY","PRAWN","PREEN","PUPIL","PURGE",
"RABID","REGAL","RELIC","REMIT","REPAY","RESIN","RIVET","RUSTY","SAVVY","SCALD",
"SCONE","SEDAN","SIGMA","SLOTH","SNIDE","SQUAT","STOIC","SWOON","SYNOD","TABOO",
"TABOR","TAFFY","TEPID","TITHE","TONIC","TROTH","TUBER","TULIP","TUTOR","ULCER",
"UMBRA","UNDID","UNTIL","UNZIP","VENOM","VERGE","VIGIL","VISOR","VOGUE","VOUCH",
"WADER","WEALD","WHELP","WINCH","WOOZY","WORMY","YEOMAN","ZONAL"
]);
const VALID_WORDS = new Set([...WORDS, ...VALID_EXTRA]);
let state = {
word: '',
guesses: [],
current: '',
gameOver: false,
stats: { played: 0, wins: 0, streak: 0 }
};
function buildGrid() {
const grid = document.getElementById('grid');
grid.innerHTML = '';
for (let r = 0; r < 6; r++) {
const row = document.createElement('div');
row.className = 'row';
row.id = 'row-' + r;
for (let c = 0; c < 5; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.id = `cell-${r}-${c}`;
row.appendChild(cell);
}
grid.appendChild(row);
}
}
function buildKeyboard() {
const kb = document.getElementById('keyboard');
kb.innerHTML = '';
const rows = [
['Q','W','E','R','T','Y','U','I','O','P'],
['A','S','D','F','G','H','J','K','L'],
['ENTER','Z','X','C','V','B','N','M','⌫']
];
rows.forEach(keys => {
const row = document.createElement('div');
row.className = 'kb-row';
keys.forEach(k => {
const btn = document.createElement('button');
btn.className = 'key' + (k.length > 1 ? ' wide' : '');
btn.textContent = k;
btn.id = 'key-' + k;
btn.addEventListener('click', () => handleKey(k === '⌫' ? 'BACKSPACE' : k));
row.appendChild(btn);
});
kb.appendChild(row);
});
}
function handleKey(key) {
if (state.gameOver) return;
if (key === 'BACKSPACE') {
state.current = state.current.slice(0, -1);
updateCurrentRow();
} else if (key === 'ENTER') {
submitGuess();
} else if (/^[A-Z]$/.test(key) && state.current.length < 5) {
state.current += key;
updateCurrentRow();
}
}
function updateCurrentRow() {
const row = state.guesses.length;
for (let c = 0; c < 5; c++) {
const cell = document.getElementById(`cell-${row}-${c}`);
const letter = state.current[c] || '';
cell.textContent = letter;
cell.className = 'cell' + (letter ? ' filled' : '');
}
}
function submitGuess() {
const row = state.guesses.length;
if (state.current.length < 5) {
shakeRow(row);
showToast('Not enough letters');
return;
}
if (!VALID_WORDS.has(state.current) && !WORDS.includes(state.current)) {
// Be lenient — allow any 5-letter attempt
// (For a proper game, you'd have a full valid-words list)
}
const guess = state.current;
state.guesses.push(guess);
state.current = '';
revealGuess(row, guess, () => {
if (guess === state.word) {
state.gameOver = true;
state.stats.played++;
state.stats.wins++;
state.stats.streak++;
setTimeout(() => {
bounceCells(row);
setTimeout(() => showResult(true), 600);
}, 300);
} else if (state.guesses.length === 6) {
state.gameOver = true;
state.stats.played++;
state.stats.streak = 0;
setTimeout(() => showResult(false), 400);
}
});
}
function revealGuess(row, guess, onDone) {
const word = state.word;
const result = Array(5).fill('absent');
const wordArr = word.split('');
const guessArr = guess.split('');
const used = Array(5).fill(false);
// First pass: correct
for (let i = 0; i < 5; i++) {
if (guessArr[i] === wordArr[i]) {
result[i] = 'correct';
used[i] = true;
}
}
// Second pass: present
for (let i = 0; i < 5; i++) {
if (result[i] === 'correct') continue;
for (let j = 0; j < 5; j++) {
if (!used[j] && guessArr[i] === wordArr[j]) {
result[i] = 'present';
used[j] = true;
break;
}
}
}
// Animate each cell
result.forEach((r, i) => {
setTimeout(() => {
const cell = document.getElementById(`cell-${row}-${i}`);
cell.classList.add('flip');
setTimeout(() => {
cell.className = 'cell ' + r;
cell.textContent = guess[i];
updateKeyColor(guess[i], r);
}, 250);
if (i === 4) setTimeout(onDone, 350);
}, i * 100);
});
}
function updateKeyColor(letter, result) {
const key = document.getElementById('key-' + letter);
if (!key) return;
const priority = { correct: 3, present: 2, absent: 1 };
const current = key.className.includes('correct') ? 'correct'
: key.className.includes('present') ? 'present'
: key.className.includes('absent') ? 'absent' : '';
if (!current || priority[result] > priority[current]) {
key.className = 'key' + (key.classList.contains('wide') ? ' wide' : '') + ' ' + result;
}
}
function shakeRow(row) {
document.querySelectorAll(`#row-${row} .cell`).forEach(c => {
c.classList.add('shake');
c.addEventListener('animationend', () => c.classList.remove('shake'), { once: true });
});
}
function bounceCells(row) {
document.querySelectorAll(`#row-${row} .cell`).forEach((c, i) => {
setTimeout(() => {
c.classList.add('bounce');
c.addEventListener('animationend', () => c.classList.remove('bounce'), { once: true });
}, i * 80);
});
}
function showToast(msg) {
const t = document.getElementById('toast');
t.textContent = msg;
t.classList.add('show');
setTimeout(() => t.classList.remove('show'), 1800);
}
function showResult(won) {
const panel = document.getElementById('result-panel');
const titles = won
? ['Genius!','Magnificent!','Impressive!','Splendid!','Great!','Phew!']
: ['Better luck next time.'];
document.getElementById('result-title').textContent = won
? titles[state.guesses.length - 1] || 'Great!'
: 'Better luck next time.';
document.getElementById('result-word-display').textContent = state.word;
document.getElementById('stat-played').textContent = state.stats.played;
document.getElementById('stat-wins').textContent = state.stats.wins;
document.getElementById('stat-streak').textContent = state.stats.streak;
panel.classList.add('show');
}
function newGame() {
state.word = WORDS[Math.floor(Math.random() * WORDS.length)];
state.guesses = [];
state.current = '';
state.gameOver = false;
document.getElementById('result-panel').classList.remove('show');
buildGrid();
buildKeyboard();
}
// Keyboard input
document.addEventListener('keydown', e => {
if (e.ctrlKey || e.altKey || e.metaKey) return;
if (e.key === 'Enter') handleKey('ENTER');
else if (e.key === 'Backspace') handleKey('BACKSPACE');
else if (/^[a-zA-Z]$/.test(e.key)) handleKey(e.key.toUpperCase());
});
newGame();
</script>
</body>
</html>

View File

@@ -58,15 +58,22 @@
<div id="onlineTraining"> <div id="onlineTraining">
<div id="trainingLevels" class="training-view"> <div id="trainingLevels" class="training-view">
<h3>Wählt einen Schwierigkeitsgrad:</h3> <h3 class="training-title">Wählt eine Trainingsart:</h3>
<button class="level-btn" data-level="leicht">🟢 Leicht</button>
<button class="level-btn" data-level="mittel">🟡 Mittel</button> <div class="buttons-row">
<button class="level-btn" data-level="schwer">🔴 Schwer</button> <button class="level-btn" data-level="flip">Karte umdrehen</button>
<button class="level-btn" data-level="multiple">Multiple Choice</button>
<button class="level-btn" data-level="matching">Zuordnen</button>
<button class="level-btn" data-level="hint">Mit Hinweis schreiben</button>
<button class="level-btn" data-level="write">Frei schreiben</button>
</div>
</div> </div>
<div id="trainingLeicht" class="training-view"></div> <div id="trainingFlip" class="training-view hidden"></div>
<div id="trainingMittel" class="training-view"></div> <div id="trainingMatching" class="training-view hidden"></div>
<div id="trainingSchwer" class="training-view"></div> <div id="trainingMultiple" class="training-view hidden"></div>
<div id="trainingHint" class="training-view hidden"></div>
<div id="trainingWrite" class="training-view hidden"></div>
<div class="button-wrapper"> <div class="button-wrapper">
<button id="checkBtn" style="display:none;" onclick="pruefeRunde()">Überprüfen</button> <button id="checkBtn" style="display:none;" onclick="pruefeRunde()">Überprüfen</button>

File diff suppressed because it is too large Load Diff

View File

@@ -281,24 +281,53 @@ h1 {
} }
} }
.training-card { #trainingFlip .training-card {
width: 300px;
margin: 10px auto;
perspective: 1000px;
cursor: pointer;
}
#trainingLeicht .training-card {
height: 180px; height: 180px;
} }
#trainingMittel .training-card { #trainingMatching .training-card {
height: 100px; height: 100px;
font-size: 0.9rem; font-size: 0.9rem;
margin: 0; margin: 0;
margin-top: 10px; margin-top: 10px;
} }
.training-card {
width: 300px;
margin: 10px auto;
perspective: 1000px;
cursor: pointer;
box-sizing: border-box;
}
#trainingMatching .drop-zone,
#trainingMatching .zieh-karte {
min-height: 120px;
max-height: 120px;
width: 300px;
background: #fff;
border: 2px solid #666;
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 0.9rem;
padding: 5px;
box-sizing: border-box;
text-align: center;
}
#trainingMatching .drop-zone h2,
#trainingMatching .zieh-karte h2,
#trainingMatching .drop-zone .ipa,
#trainingMatching .zieh-karte .ipa,
#trainingMatching .drop-zone .example,
#trainingMatching .zieh-karte .example {
margin: 2px 0;
overflow: hidden;
}
.training-card-inner { .training-card-inner {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -323,8 +352,42 @@ h1 {
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-start;
gap: 10px; align-items: stretch;
}
.card-top {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 2px;
}
.card-top h2 {
margin: 0;
line-height: 1.1;
}
.card-top h3 {
margin: 0;
line-height: 1.1;
}
.card-top .ipa {
margin: 0;
line-height: 1.1;
}
.card-example {
margin-top: auto;
text-align: center;
font-size: 15px;
line-height: 1.4;
}
.ipa {
font-size: 16px;
color: #555;
} }
.training-back { .training-back {
@@ -344,36 +407,12 @@ h1 {
cursor: pointer; cursor: pointer;
} }
.training-front h2 {
margin-bottom: 4px;
margin-top: -25px;
}
.training-front .ipa {
font-size: 16px;
color: #555;
margin-bottom: 34px;
margin-top: -12px;
}
.training-front .example {
font-size: 15px;
line-height: 1.4;
}
.training-back h2 {
margin-bottom: 54px;
margin-top: -28px;
}
#pdfPages, #pdfPages,
#onlineTraining, #onlineTraining {
#trainingMittel,
#trainingSchwer {
display: none; display: none;
} }
#trainingMittel { #trainingMatching {
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
@@ -425,3 +464,172 @@ h1 {
background-repeat: repeat; background-repeat: repeat;
background-size: 80px; background-size: 80px;
} }
#trainingMultiple {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 20px;
margin-top: 30px;
}
.multiple-frage {
text-align: center;
font-size: 28px;
font-weight: bold;
}
.multiple-optionen {
display: flex;
flex-direction: column;
gap: 10px;
width: 300px;
}
.multiple-option {
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f0f0f0;
text-align: center;
transition: background-color 0.2s, transform 0.1s;
}
.multiple-option:hover {
background-color: #e0e0e0;
transform: scale(1.03);
}
.multiple-option[disabled] {
text-decoration: line-through;
background-color: #f5a8a8;
color: #800;
}
#trainingHint {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
margin-top: 30px;
}
.hint-frage {
text-align: center;
font-size: 28px;
font-weight: bold;
}
.hint-input {
width: 300px;
font-size: 18px;
padding: 10px;
text-align: center;
border-radius: 6px;
}
.hint-button {
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
border-radius: 6px;
border: none;
background-color: #005b5b;
color: white;
transition: 0.2s;
}
.hint-button:hover {
background-color: #007070;
}
.hint-feedback {
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.hint-clue {
font-size: 20px;
letter-spacing: 2px;
margin-bottom: 10px;
color: #555;
text-align: center;
font-family: monospace;
}
#trainingWrite {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 20px;
margin-top: 30px;
}
#trainingWrite .schwer-frage {
text-align: center;
font-size: 28px;
font-weight: bold;
}
#trainingWrite input[type="text"] {
font-size: 18px;
border-radius: 6px;
}
#trainingWrite button {
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
border-radius: 6px;
border: none;
background-color: #005b5b;
color: white;
transition: 0.2s;
}
#trainingWrite button:hover {
background-color: #007070;
}
#trainingLevels {
display: flex;
flex-direction: column;
gap: 15px;
width: 100%;
}
.training-title {
margin: 0 0 10px 0;
font-size: 20px;
font-weight: 600;
text-align: left;
}
#trainingLevels .buttons-row {
display: flex;
gap: 10px;
width: 100%;
}
#trainingLevels .buttons-row .level-btn {
flex: 1;
padding: 12px 0;
font-size: 16px;
font-weight: 600;
border: none;
border-radius: 8px;
background-color: #f0f0f0;
cursor: pointer;
text-align: center;
transition: background-color 0.2s, transform 0.1s;
}
#trainingLevels .buttons-row .level-btn:hover {
background-color: #e0e0e0;
transform: scale(1.02);
}

View File

@@ -1,299 +1,370 @@
const SEG = { a:0, b:1, c:2, d:3, e:4, f:5, g:6 }; // Die Namen der 7 Segmente (a bis g)
const segNames = ["a","b","c","d","e","f","g"]; const SEGMENT_NAMEN = ["a", "b", "c", "d", "e", "f", "g"];
function maskFromSegments(list){ // Ein Mapping: Welches Segment hat welchen "Bit Wert"?
let m = 0; // a=1, b=2, c=4, d=8 ... das sind Zweierpotenzen.
for(const s of list) m |= (1 << SEG[s]); const SEGMENT_INDEX = { a:0, b:1, c:2, d:3, e:4, f:5, g:6 };
return m;
// Diese Funktion rechnet eine Liste von Segmenten (z.B. "a", "b") in eine Zahl um.
function erstelleMuster(listeVonSegmenten) {
let muster = 0;
for (const segmentBuchstabe of listeVonSegmenten) {
// 1 << X bedeutet: Schiebe die 1 um X Stellen nach links
// Das | (ODER) fügt das Bit hinzu.
muster = muster | (1 << SEGMENT_INDEX[segmentBuchstabe]);
}
return muster;
} }
// Hier speichern wir das Muster für jede Ziffer von 0 bis 9
const DIGIT_MASK = [ // bitmasking: Jede Ziffer ist eine Kombination von Segmenten die an sind
maskFromSegments(["a","b","c","d","e","f"]), const ZIFFERN_MUSTER = [
maskFromSegments(["b","c"]), erstelleMuster(["a","b","c","d","e","f"]), // 0
maskFromSegments(["a","b","d","e","g"]), erstelleMuster(["b","c"]), // 1
maskFromSegments(["a","b","c","d","g"]), erstelleMuster(["a","b","d","e","g"]), // 2
maskFromSegments(["b","c","f","g"]), erstelleMuster(["a","b","c","d","g"]), // 3
maskFromSegments(["a","c","d","f","g"]), erstelleMuster(["b","c","f","g"]), // 4
maskFromSegments(["a","c","d","e","f","g"]), erstelleMuster(["a","c","d","f","g"]), // 5
maskFromSegments(["a","b","c"]), erstelleMuster(["a","c","d","e","f","g"]), // 6
maskFromSegments(["a","b","c","d","e","f","g"]), erstelleMuster(["a","b","c"]), // 7
maskFromSegments(["a","b","c","d","f","g"]) erstelleMuster(["a","b","c","d","e","f","g"]), // 8
erstelleMuster(["a","b","c","d","f","g"]) // 9
]; ];
// Eine Rückwärts Suche: Welches Muster gehört zu welcher Zahl?
const MASK_TO_DIGIT = new Map(DIGIT_MASK.map((m,d)=>[m,d])); // Wir bauen eine Map (Liste), um das schnell zu finden.
const MUSTER_ZU_ZAHL = new Map();
ZIFFERN_MUSTER.forEach((muster, zahl) => {
MUSTER_ZU_ZAHL.set(muster, zahl);
});
function removableTargetsFromDigit(d){
const start = DIGIT_MASK[d];
const res = [];
for(let t=0;t<=9;t++){
const target = DIGIT_MASK[t];
if((target & start) === target){
const removed = popcount(start ^ target);
res.push({to:t, removed}); // Zählt, wie viele Bits in einer Zahl auf 1 stehen.
// (Also: Wie viele Streichhölzer sind an?)
function zaehleStreichhoelzer(zahl) {
let anzahl = 0;
// Solange die Zahl nicht 0 ist
while (zahl > 0) {
// Ein kleiner Trick um das letzte Bit zu löschen und zu zählen
zahl = zahl & (zahl - 1);
anzahl++;
} }
} return anzahl;
return res;
} }
function popcount(x){ // Gibt eine zufällige Zahl zwischen min und max zurück
x = x >>> 0; function zufallsZahl(min, max) {
let c = 0;
while(x){ x &= (x-1); c++; }
return c;
}
function randInt(min, max){ // inclusive
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
function pick(arr){ return arr[randInt(0, arr.length-1)]; }
let level = 1; // Wählt ein zufälliges Element aus einer Liste
let targetRemove = 2; function wähleZufällig(liste) {
let current = null; return liste[zufallsZahl(0, liste.length - 1)];
let solution = null; }
let removedSoFar = 0;
// Findet alle Zahlen, aus denen man 'basisZahl' machen kann, indem man Hölzer entfernt.
// Beispiel: Aus einer 8 kann man eine 0 machen (Mitte wegnehmen).
// Aber aus einer 1 kann man keine 8 machen (man müsste hinzufügen).
function findeMoeglicheUrsprungsZiffern(basisZahl) {
const basisMuster = ZIFFERN_MUSTER[basisZahl];
const moegliche = [];
for (let z = 0; z <= 9; z++) {
const vergleichsMuster = ZIFFERN_MUSTER[z];
// Wenn das vergleichsMuster ALLE Striche vom basisMuster hat:
if ((vergleichsMuster & basisMuster) === basisMuster) {
moegliche.push(z);
}
}
return moegliche;
}
let removedSet = new Set();
const elEq = document.getElementById("equation");
const elRemovedGrid = document.getElementById("removedGrid");
const elRemovedCount = document.getElementById("removedCount");
const elPileCount = document.getElementById("pileCount");
const elLvl = document.getElementById("lvl");
const elTarget = document.getElementById("target");
const elGoalN = document.getElementById("goalN");
const elTruthDot = document.getElementById("truthDot");
const elTruthText = document.getElementById("truthText");
const elHint = document.getElementById("hint");
let aktuellesLevel = 1;
let zielAnzahlLoeschen = 2; // Wie viele muss man löschen?
let anzahlGeloescht = 0; // Wie viele hat der Spieler schon gelöscht?
// Hier speichern wir die aktuellen Zahlen auf dem Bildschirm
let aktuelleGleichung = { A: 0, B: 0, C: 0 };
// Hier merken wir uns, welche Striche der Spieler angeklickt hat.
// Format: "Index-Segment", z.B. "0-a" (Erste Ziffer, Segment a)
let geloeschteStreichhoelzer = new Set();
const elGleichung = document.getElementById("equation");
const elGeloeschtGrid = document.getElementById("removedGrid");
const elZaehlerGeloescht = document.getElementById("removedCount");
const elStapelZaehler = document.getElementById("pileCount");
const elLevelAnzeige = document.getElementById("lvl");
const elZielAnzeige = document.getElementById("target");
const elZielText = document.getElementById("goalN");
const elWahrheitPunkt = document.getElementById("truthDot");
const elWahrheitText = document.getElementById("truthText");
const elHinweis = document.getElementById("hint");
// Buttons aktivieren
document.getElementById("btnNew").addEventListener("click", () => { document.getElementById("btnNew").addEventListener("click", () => {
level++; aktuellesLevel++;
generateLevel(); starteNeuesLevel();
}); });
document.getElementById("btnReset").addEventListener("click", () => { document.getElementById("btnReset").addEventListener("click", () => {
// Level neu starten (aber gleiches Level)
resetPlayState(); setzeSpielZurueck();
renderEquation(); zeichneGleichung();
updateTruthUI(); pruefeObWahr();
}); });
function segmentsFromMask(mask){
const set = new Set();
for(let i=0;i<7;i++){ function setzeSpielZurueck() {
if(mask & (1<<i)) set.add(segNames[i]); geloeschteStreichhoelzer.clear(); // Liste leeren
} anzahlGeloescht = 0;
return set; elGeloeschtGrid.innerHTML = ""; // Anzeige leeren
updateZaehlerAnzeige();
} }
function displayedMaskForDigit(digitValue, digitIndex){ function updateZaehlerAnzeige() {
let mask = DIGIT_MASK[digitValue]; elZaehlerGeloescht.textContent = anzahlGeloescht;
for(const s of segNames){ elStapelZaehler.textContent = anzahlGeloescht;
const key = digitIndex + "-" + s;
if(removedSet.has(key)){
mask &= ~(1 << SEG[s]);
}
}
return mask;
} }
function displayedDigitValue(digitValue, digitIndex){ // Berechnet, welche Zahl gerade angezeigt wird (basierend auf dem was gelöscht wurde)
const mask = displayedMaskForDigit(digitValue, digitIndex); function berechneAngezeigteZahl(originalZahl, positionIndex) {
return MASK_TO_DIGIT.has(mask) ? MASK_TO_DIGIT.get(mask) : null; let maske = ZIFFERN_MUSTER[originalZahl];
// Wir gehen alle 7 Segmente durch
for (const seg of SEGMENT_NAMEN) {
const schluessel = positionIndex + "-" + seg;
// Wenn dieses Segment gelöscht wurde...
if (geloeschteStreichhoelzer.has(schluessel)) {
// ... dann schalten wir das Bit in der Maske aus (mit & ~)
maske = maske & ~(1 << SEGMENT_INDEX[seg]);
}
}
// Schauen, ob das resultierende Muster eine gültige Zahl ist
if (MUSTER_ZU_ZAHL.has(maske)) {
return MUSTER_ZU_ZAHL.get(maske);
} else {
return null; // Keine gültige Zahl (Kaputt)
}
} }
function equationIsTrue(){ // Prüft: Ist A + B = C ?
function istGleichungWahr() {
const a = berechneAngezeigteZahl(aktuelleGleichung.A, 0);
const b = berechneAngezeigteZahl(aktuelleGleichung.B, 1);
const c = berechneAngezeigteZahl(aktuelleGleichung.C, 2);
// Wenn irgendeine Zahl ungültig ist, ist die Gleichung falsch
if (a === null || b === null || c === null) return false;
const a = displayedDigitValue(current.A, 0);
const b = displayedDigitValue(current.B, 1);
const c = displayedDigitValue(current.C, 2);
if(a === null || b === null || c === null) return false;
return (a + b) === c; return (a + b) === c;
} }
function updateTruthUI(){ function pruefeObWahr() {
const ok = equationIsTrue(); const istWahr = istGleichungWahr();
elTruthDot.classList.toggle("ok", ok);
elTruthText.textContent = ok ? "Equation is TRUE" : "Equation is FALSE"; if (istWahr) {
elWahrheitPunkt.classList.add("ok");
elWahrheitText.textContent = "Gleichung ist WAHR";
} else {
elWahrheitPunkt.classList.remove("ok");
elWahrheitText.textContent = "Gleichung ist FALSCH";
}
} }
function resetPlayState(){ // Erstellt das HTML für EINE Ziffer
removedSet.clear(); function erstelleZifferHTML(zahlenWert, positionIndex, farbe) {
removedSoFar = 0; const zifferContainer = document.createElement("div");
elRemovedGrid.innerHTML = ""; zifferContainer.className = "digit";
syncRemovedCounts();
}
function syncRemovedCounts(){ // Welche Segmente hat die Zahl ursprünglich?
elRemovedCount.textContent = String(removedSoFar); const maske = ZIFFERN_MUSTER[zahlenWert];
elPileCount.textContent = String(removedSoFar);
}
function renderDigit(digitValue, digitIndex, color){ for (let i = 0; i < 7; i++) {
const digit = document.createElement("div"); const segName = SEGMENT_NAMEN[i];
digit.className = "digit";
const baseMask = DIGIT_MASK[digitValue]; // Prüfen: Hat die Zahl dieses Segment? (Bit Test)
const baseSegs = segmentsFromMask(baseMask); const hatSegment = (maske & (1 << i)) !== 0;
for(const s of segNames){ if (hatSegment) {
if(!baseSegs.has(s)) continue; const segElement = document.createElement("div");
segElement.className = "seg " + segName;
segElement.style.background = farbe;
const seg = document.createElement("div"); // Eindeutige ID für dieses Segment (z.B. "0-a")
seg.className = "seg " + s; const id = positionIndex + "-" + segName;
seg.style.background = color;
const key = digitIndex + "-" + s; // Wenn schon gelöscht, Klasse hinzufügen
if(removedSet.has(key)) seg.classList.add("removed"); if (geloeschteStreichhoelzer.has(id)) {
segElement.classList.add("removed");
}
seg.addEventListener("click", () => { // Klick Event (Hier passiert die Action!)
if(removedSet.has(key)) return; segElement.addEventListener("click", () => {
if(removedSoFar >= targetRemove) return; // Abbruch wenn schon weg oder Limit erreicht
if (geloeschteStreichhoelzer.has(id)) return;
removedSet.add(key); if (anzahlGeloescht >= zielAnzahlLoeschen) return;
removedSoFar++;
seg.classList.add("removed");
// Löschen durchführen
geloeschteStreichhoelzer.add(id);
anzahlGeloescht++;
segElement.classList.add("removed");
// Kleines Streichholz in den Mülleimer animieren
const clone = document.createElement("div"); const clone = document.createElement("div");
clone.className = "removedSeg"; clone.className = "removedSeg";
clone.style.background = color; clone.style.background = farbe;
elRemovedGrid.appendChild(clone); elGeloeschtGrid.appendChild(clone);
syncRemovedCounts(); updateZaehlerAnzeige();
updateTruthUI(); pruefeObWahr();
if(removedSoFar === targetRemove){ // Gewinn Prüfung
if(equationIsTrue()){ if (anzahlGeloescht === zielAnzahlLoeschen) {
elHint.innerHTML = "<b>Solved!</b> You removed exactly the target and made the equation true. Click <b>New level</b>."; if (istGleichungWahr()) {
elHinweis.innerHTML = "<b>Gelöst!</b> Super gemacht. Klicke auf <b>Neu level</b>.";
} else { } else {
elHint.innerHTML = " <b>Not solved.</b> You used all removals but the equation isnt true. Click <b>Reset level</b> to try again."; elHinweis.innerHTML = "<b>Nicht gelöst.</b> Alle Züge verbraucht, aber Gleichung falsch. <b>Reset</b>?";
} }
} }
}); });
digit.appendChild(seg); zifferContainer.appendChild(segElement);
} }
return digit; }
return zifferContainer;
} }
function renderEquation(){ function zeichneGleichung() {
elEq.innerHTML = ""; elGleichung.innerHTML = ""; // Alles löschen
const colors = [ const farben = [
"linear-gradient(180deg,#ff6b6b,#d64545)", "linear-gradient(180deg,#ff6b6b,#d64545)", // Rot für A
"linear-gradient(180deg,#6bcBff,#3a7bd5)", "linear-gradient(180deg,#6bcBff,#3a7bd5)", // Blau für B
"linear-gradient(180deg,#6bffb3,#1fae63)" "linear-gradient(180deg,#6bffb3,#1fae63)" // Grün für C
]; ];
// Gruppe A bauen
const g1 = document.createElement("div"); const g1 = document.createElement("div");
g1.className = "group"; g1.className = "group";
g1.appendChild(renderDigit(current.A, 0, colors[0])); g1.appendChild(erstelleZifferHTML(aktuelleGleichung.A, 0, farben[0]));
// Plus Zeichen
const plus = document.createElement("div"); const plus = document.createElement("div");
plus.className = "symbol"; plus.className = "symbol";
plus.textContent = "+"; plus.textContent = "+";
// Gruppe B bauen
const g2 = document.createElement("div"); const g2 = document.createElement("div");
g2.className = "group"; g2.className = "group";
g2.appendChild(renderDigit(current.B, 1, colors[1])); g2.appendChild(erstelleZifferHTML(aktuelleGleichung.B, 1, farben[1]));
// Ist Gleich Zeichen
const eq = document.createElement("div"); const eq = document.createElement("div");
eq.className = "symbol"; eq.className = "symbol";
eq.textContent = "="; eq.textContent = "=";
// Gruppe C bauen
const g3 = document.createElement("div"); const g3 = document.createElement("div");
g3.className = "group"; g3.className = "group";
g3.appendChild(renderDigit(current.C, 2, colors[2])); g3.appendChild(erstelleZifferHTML(aktuelleGleichung.C, 2, farben[2]));
elEq.appendChild(g1); // Alles zusammenfügen
elEq.appendChild(plus); elGleichung.appendChild(g1);
elEq.appendChild(g2); elGleichung.appendChild(plus);
elEq.appendChild(eq); elGleichung.appendChild(g2);
elEq.appendChild(g3); elGleichung.appendChild(eq);
elGleichung.appendChild(g3);
updateTruthUI(); pruefeObWahr();
} }
function generateLevel(){ // 7. LEVEL GENERATOR (Das Gehirn)
resetPlayState(); // Hier wird ein Level gebaut, das garantiert lösbar ist.
targetRemove = Math.min(2 + Math.floor(Math.log2(level + 1)), 6); function starteNeuesLevel() {
setzeSpielZurueck();
// Ziel berechnen: Level 1-2 -> 2 löschen, danach evtl mehr. Max 6.
zielAnzahlLoeschen = Math.min(2 + Math.floor(Math.log2(aktuellesLevel + 1)), 6);
let tries = 0; let versuche = 0;
while(true){
tries++; // Endlosschleife, bis wir ein passendes Level finden
if(tries > 5000){ while (true) {
targetRemove = Math.max(2, targetRemove - 1); versuche++;
tries = 0; // Sicherheitsnetz: Wenn es zu lange dauert, Ziel senken
if (versuche > 5000) {
zielAnzahlLoeschen = Math.max(2, zielAnzahlLoeschen - 1);
versuche = 0;
} }
const As = randInt(0, 9); // 1. Wir denken uns eine KORREKTE Lösung aus (z.B. 3 + 5 = 8)
const Bs = randInt(0, 9); const lsgA = zufallsZahl(0, 9);
const Cs = As + Bs; const lsgB = zufallsZahl(0, 9);
if(Cs < 0 || Cs > 9) continue; const lsgC = lsgA + lsgB;
if (lsgC > 9) continue; // Ergebnis darf nur 1 stellig sein (0-9)
const Achoices = superDigits(As); // 2. Wir suchen Zahlen, die mehr Striche haben als unsere Lösung
const Bchoices = superDigits(Bs); // (Aus denen man die Lösung "schnitzen" kann)
const Cchoices = superDigits(Cs); const moeglicheA = findeMoeglicheUrsprungsZiffern(lsgA);
const moeglicheB = findeMoeglicheUrsprungsZiffern(lsgB);
const moeglicheC = findeMoeglicheUrsprungsZiffern(lsgC);
const Ashow = pick(Achoices); // Eine zufällige Auswahl treffen
const Bshow = pick(Bchoices); const startA = wähleZufällig(moeglicheA);
const Cshow = pick(Cchoices); const startB = wähleZufällig(moeglicheB);
const startC = wähleZufällig(moeglicheC);
const need = // 3. Berechnen: Wie viele Striche müssen weg, um zur Lösung zu kommen?
popcount(DIGIT_MASK[Ashow] ^ DIGIT_MASK[As]) + // XOR (^) zeigt den Unterschied an.
popcount(DIGIT_MASK[Bshow] ^ DIGIT_MASK[Bs]) + const diffA = zaehleStreichhoelzer(ZIFFERN_MUSTER[startA] ^ ZIFFERN_MUSTER[lsgA]);
popcount(DIGIT_MASK[Cshow] ^ DIGIT_MASK[Cs]); const diffB = zaehleStreichhoelzer(ZIFFERN_MUSTER[startB] ^ ZIFFERN_MUSTER[lsgB]);
const diffC = zaehleStreichhoelzer(ZIFFERN_MUSTER[startC] ^ ZIFFERN_MUSTER[lsgC]);
if(need !== targetRemove) continue; const gesamtWeg = diffA + diffB + diffC;
// Passt das zu unserem Ziel?
if (gesamtWeg !== zielAnzahlLoeschen) continue;
const shownTrue = (Ashow + Bshow) === Cshow; // 4. Wichtig: Die angezeigte Start Gleichung muss FALSCH sein.
if(shownTrue) continue; // Sonst gibt es ja nichts zu rätseln.
if ((startA + startB) === startC) continue;
solution = { A: As, B: Bs, C: Cs }; // Gefunden! Speichern.
current = { A: Ashow, B: Bshow, C: Cshow }; aktuelleGleichung = { A: startA, B: startB, C: startC };
break; break; // Schleife beenden
} }
elLvl.textContent = String(level); // UI Updates
elTarget.textContent = String(targetRemove); elLevelAnzeige.textContent = aktuellesLevel;
elGoalN.textContent = String(targetRemove); elZielAnzeige.textContent = zielAnzahlLoeschen;
elZielText.textContent = zielAnzahlLoeschen;
elHint.innerHTML = elHinweis.innerHTML =
`Level <b>${level}</b>: Make the equation true by removing <b>${targetRemove}</b> match(es). ` + `Level <b>${aktuellesLevel}</b>: Mache die Gleichung wahr, indem du <b>${zielAnzahlLoeschen}</b> Streichhölzer entfernst.`;
`You can only remove sticks (click them).`;
renderEquation(); zeichneGleichung();
syncRemovedCounts();
updateTruthUI();
} }
function superDigits(baseDigit){ // Spiel starten!
const base = DIGIT_MASK[baseDigit]; starteNeuesLevel();
const res = [];
for(let d=0; d<=9; d++){
const m = DIGIT_MASK[d];
if((m & base) === base){
res.push(d);
}
}
return res;
}
generateLevel();

23
Readme.md Normal file
View File

@@ -0,0 +1,23 @@
# Lernplattform Projekt
Dies ist unser Lernplattform-Projekt, entwickelt von:
- Abdelaziz Elouazzani
- Younes El Haddoury
- Ayman Alshian
- Stanislav Kharchenko
- Saad Akki
- Ismail Amara
---
## Projektbeschreibung
Dieses Projekt ist eine Lernplattform, die verschiedene Funktionen zum Üben und Lernen bietet.
---
## Abgabe & Download
- **Git-Repository:** [Zum Repository](https://git.bib.de/PBT3H24AKH/LerningCSW.git)
- **Projekt als ZIP herunterladen:** [Download ZIP](https://git.bib.de/PBT3H24AKH/LerningCSW/archive/refs/heads/main.zip)