Compare commits
7 Commits
678e4d5089
...
db73585839
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db73585839 | ||
|
|
5d1549e90e | ||
|
|
b1ffd825db | ||
|
|
02940021e2 | ||
|
|
63298248c7 | ||
|
|
1cb51dd802 | ||
|
|
3b100eaf11 |
@@ -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>
|
||||
353
MainPage/Abdelaziz/kreuzwortratsel.html
Normal file
353
MainPage/Abdelaziz/kreuzwortratsel.html
Normal file
@@ -0,0 +1,353 @@
|
||||
<!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; cursor: pointer; padding: 1px 3px; }
|
||||
.h:hover { background: #eef3fb; }
|
||||
.h.aktiv { background: #c5ddf7; }
|
||||
.h.erledigt { color: #aaa; text-decoration: line-through; }
|
||||
.hnum { min-width: 20px; flex-shrink: 0; font-weight: bold; color: #666; }
|
||||
|
||||
#toast {
|
||||
position: fixed; top: 12px; left: 50%;
|
||||
transform: translateX(-50%) translateY(-50px);
|
||||
background: #222; color: #fff;
|
||||
font-size: 11px; padding: 5px 14px;
|
||||
opacity: 0; transition: transform .2s, opacity .2s;
|
||||
pointer-events: none; z-index: 99;
|
||||
}
|
||||
#toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
|
||||
|
||||
@keyframes fja { 0%, 60% { background: #27ae60 } 100% { background: #b8f0c8 } }
|
||||
@keyframes fnein { 0%, 60% { background: #c0392b } 100% { background: #f0b8b8 } }
|
||||
.fja { animation: fja .6s ease forwards; }
|
||||
.fnein { animation: fnein .6s ease forwards; }
|
||||
|
||||
</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>
|
||||
<div id="toast"><span id="tw"></span><span id="tm"></span></div>
|
||||
|
||||
<script>
|
||||
let richtung='across', ar=-1, ac=-1;
|
||||
let felder=[], nummern={across:{},down:{}};
|
||||
let lsg, ha, hd, gelo={across:new Set(),down:new Set()};
|
||||
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: {}};
|
||||
gelo = {across: new Set(), down: new Set()};
|
||||
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>`;
|
||||
row.addEventListener('click', () => springZu(d, num));
|
||||
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');
|
||||
document.querySelectorAll('.h').forEach(e => e.classList.remove('aktiv'));
|
||||
if (!wc.length) return;
|
||||
const [sr,sc] = wc[0], map = richtung==='across' ? nummern.across : nummern.down;
|
||||
for (const [num, pos] of Object.entries(map)) {
|
||||
if (pos.r===sr && pos.c===sc) {
|
||||
const el = document.getElementById(`h${richtung[0]}${num}`);
|
||||
if (el) { el.classList.add('aktiv'); el.scrollIntoView({block:'nearest', behavior:'smooth'}); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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','fja','fnein');
|
||||
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();
|
||||
setTimeout(() => wortCheck(r,c), 50);
|
||||
}
|
||||
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);
|
||||
springZu(richtung, keys[((keys.indexOf(cur)+delta)+keys.length) % keys.length]);
|
||||
}
|
||||
function springZu(d, num) {
|
||||
setRichtung(d);
|
||||
const map = d==='across' ? nummern.across : nummern.down;
|
||||
if (map[num]) felder[map[num].r][map[num].c].inp.focus();
|
||||
}
|
||||
|
||||
let tt = null;
|
||||
function toast(word, ok) {
|
||||
const t = document.getElementById('toast');
|
||||
t.innerHTML = `<span style="color:${ok?'#7df0a0':'#f07070'};font-weight:bold;margin-right:3px">${word}</span>${ok?' ✓ Richtig!':' ✗ Falsch'}`;
|
||||
t.classList.add('show');
|
||||
if (tt) clearTimeout(tt);
|
||||
tt = setTimeout(() => t.classList.remove('show'), 1800);
|
||||
}
|
||||
|
||||
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 wortCheck(r, c) {
|
||||
['across','down'].forEach(d => {
|
||||
const wc = wort(r,c,d); if (wc.length < 2) return;
|
||||
if (!wc.every(([wr,wc2]) => felder[wr]?.[wc2]?.inp?.value?.trim())) return;
|
||||
const map = d==='across' ? nummern.across : nummern.down;
|
||||
const [sr,sc] = wc[0]; let num = null;
|
||||
for (const [n,pos] of Object.entries(map)) if (pos.r===sr && pos.c===sc) { num=+n; break; }
|
||||
if (num === null) return;
|
||||
const ist = wc.map(([wr,wc2]) => felder[wr][wc2].inp.value.toUpperCase()).join('');
|
||||
const soll = wc.map(([wr,wc2]) => lsg[`${wr},${wc2}`]||'').join('');
|
||||
const ok = ist === soll;
|
||||
wc.forEach(([wr,wc2]) => { const cel=felder[wr][wc2].el; cel.classList.remove('fja','fnein','richtig','falsch'); void cel.offsetWidth; });
|
||||
if (ok) {
|
||||
wc.forEach(([wr,wc2]) => felder[wr][wc2].el.classList.add('fja','richtig'));
|
||||
document.getElementById(`h${d[0]}${num}`)?.classList.add('erledigt');
|
||||
gelo[d].add(num); toast(ist, true);
|
||||
} else if (!gelo[d].has(num)) {
|
||||
wc.forEach(([wr,wc2]) => felder[wr][wc2].el.classList.add('fnein','falsch'));
|
||||
toast(ist, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
function pruefen() {
|
||||
let ok=0, ng=0, em=0;
|
||||
alleFelder((d,r,c) => {
|
||||
d.el.classList.remove('richtig','falsch','fja','fnein');
|
||||
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','fnein'); 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','fja','fnein'); });
|
||||
gelo = {across: new Set(), down: new Set()};
|
||||
document.getElementById('info').textContent='';
|
||||
document.querySelectorAll('.h.erledigt').forEach(e => e.classList.remove('erledigt'));
|
||||
}
|
||||
lade(0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,299 +1,370 @@
|
||||
|
||||
|
||||
|
||||
const SEG = { a:0, b:1, c:2, d:3, e:4, f:5, g:6 };
|
||||
const segNames = ["a","b","c","d","e","f","g"];
|
||||
// Die Namen der 7 Segmente (a bis g)
|
||||
const SEGMENT_NAMEN = ["a", "b", "c", "d", "e", "f", "g"];
|
||||
|
||||
function maskFromSegments(list){
|
||||
let m = 0;
|
||||
for(const s of list) m |= (1 << SEG[s]);
|
||||
return m;
|
||||
// Ein Mapping: Welches Segment hat welchen "Bit Wert"?
|
||||
// a=1, b=2, c=4, d=8 ... das sind Zweierpotenzen.
|
||||
const SEGMENT_INDEX = { a:0, b:1, c:2, d:3, e:4, f:5, g:6 };
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
const DIGIT_MASK = [
|
||||
maskFromSegments(["a","b","c","d","e","f"]),
|
||||
maskFromSegments(["b","c"]),
|
||||
maskFromSegments(["a","b","d","e","g"]),
|
||||
maskFromSegments(["a","b","c","d","g"]),
|
||||
maskFromSegments(["b","c","f","g"]),
|
||||
maskFromSegments(["a","c","d","f","g"]),
|
||||
maskFromSegments(["a","c","d","e","f","g"]),
|
||||
maskFromSegments(["a","b","c"]),
|
||||
maskFromSegments(["a","b","c","d","e","f","g"]),
|
||||
maskFromSegments(["a","b","c","d","f","g"])
|
||||
// Hier speichern wir das Muster für jede Ziffer von 0 bis 9
|
||||
// bitmasking: Jede Ziffer ist eine Kombination von Segmenten die an sind
|
||||
const ZIFFERN_MUSTER = [
|
||||
erstelleMuster(["a","b","c","d","e","f"]), // 0
|
||||
erstelleMuster(["b","c"]), // 1
|
||||
erstelleMuster(["a","b","d","e","g"]), // 2
|
||||
erstelleMuster(["a","b","c","d","g"]), // 3
|
||||
erstelleMuster(["b","c","f","g"]), // 4
|
||||
erstelleMuster(["a","c","d","f","g"]), // 5
|
||||
erstelleMuster(["a","c","d","e","f","g"]), // 6
|
||||
erstelleMuster(["a","b","c"]), // 7
|
||||
erstelleMuster(["a","b","c","d","e","f","g"]), // 8
|
||||
erstelleMuster(["a","b","c","d","f","g"]) // 9
|
||||
];
|
||||
|
||||
|
||||
const MASK_TO_DIGIT = new Map(DIGIT_MASK.map((m,d)=>[m,d]));
|
||||
// Eine Rückwärts Suche: Welches Muster gehört zu welcher Zahl?
|
||||
// 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 res;
|
||||
return anzahl;
|
||||
}
|
||||
|
||||
function popcount(x){
|
||||
x = x >>> 0;
|
||||
let c = 0;
|
||||
while(x){ x &= (x-1); c++; }
|
||||
return c;
|
||||
}
|
||||
|
||||
function randInt(min, max){ // inclusive
|
||||
// Gibt eine zufällige Zahl zwischen min und max zurück
|
||||
function zufallsZahl(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
function pick(arr){ return arr[randInt(0, arr.length-1)]; }
|
||||
|
||||
let level = 1;
|
||||
let targetRemove = 2;
|
||||
let current = null;
|
||||
let solution = null;
|
||||
let removedSoFar = 0;
|
||||
|
||||
|
||||
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");
|
||||
|
||||
document.getElementById("btnNew").addEventListener("click", () => {
|
||||
level++;
|
||||
generateLevel();
|
||||
});
|
||||
document.getElementById("btnReset").addEventListener("click", () => {
|
||||
|
||||
resetPlayState();
|
||||
renderEquation();
|
||||
updateTruthUI();
|
||||
});
|
||||
|
||||
function segmentsFromMask(mask){
|
||||
const set = new Set();
|
||||
for(let i=0;i<7;i++){
|
||||
if(mask & (1<<i)) set.add(segNames[i]);
|
||||
}
|
||||
return set;
|
||||
// Wählt ein zufälliges Element aus einer Liste
|
||||
function wähleZufällig(liste) {
|
||||
return liste[zufallsZahl(0, liste.length - 1)];
|
||||
}
|
||||
|
||||
function displayedMaskForDigit(digitValue, digitIndex){
|
||||
let mask = DIGIT_MASK[digitValue];
|
||||
for(const s of segNames){
|
||||
const key = digitIndex + "-" + s;
|
||||
if(removedSet.has(key)){
|
||||
mask &= ~(1 << SEG[s]);
|
||||
// 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 mask;
|
||||
return moegliche;
|
||||
}
|
||||
|
||||
function displayedDigitValue(digitValue, digitIndex){
|
||||
const mask = displayedMaskForDigit(digitValue, digitIndex);
|
||||
return MASK_TO_DIGIT.has(mask) ? MASK_TO_DIGIT.get(mask) : null;
|
||||
|
||||
|
||||
|
||||
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", () => {
|
||||
aktuellesLevel++;
|
||||
starteNeuesLevel();
|
||||
});
|
||||
|
||||
document.getElementById("btnReset").addEventListener("click", () => {
|
||||
// Level neu starten (aber gleiches Level)
|
||||
setzeSpielZurueck();
|
||||
zeichneGleichung();
|
||||
pruefeObWahr();
|
||||
});
|
||||
|
||||
|
||||
|
||||
function setzeSpielZurueck() {
|
||||
geloeschteStreichhoelzer.clear(); // Liste leeren
|
||||
anzahlGeloescht = 0;
|
||||
elGeloeschtGrid.innerHTML = ""; // Anzeige leeren
|
||||
updateZaehlerAnzeige();
|
||||
}
|
||||
|
||||
function equationIsTrue(){
|
||||
function updateZaehlerAnzeige() {
|
||||
elZaehlerGeloescht.textContent = anzahlGeloescht;
|
||||
elStapelZaehler.textContent = anzahlGeloescht;
|
||||
}
|
||||
|
||||
// Berechnet, welche Zahl gerade angezeigt wird (basierend auf dem was gelöscht wurde)
|
||||
function berechneAngezeigteZahl(originalZahl, positionIndex) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
function updateTruthUI(){
|
||||
const ok = equationIsTrue();
|
||||
elTruthDot.classList.toggle("ok", ok);
|
||||
elTruthText.textContent = ok ? "Equation is TRUE" : "Equation is FALSE";
|
||||
}
|
||||
function pruefeObWahr() {
|
||||
const istWahr = istGleichungWahr();
|
||||
|
||||
|
||||
function resetPlayState(){
|
||||
removedSet.clear();
|
||||
removedSoFar = 0;
|
||||
elRemovedGrid.innerHTML = "";
|
||||
syncRemovedCounts();
|
||||
}
|
||||
|
||||
function syncRemovedCounts(){
|
||||
elRemovedCount.textContent = String(removedSoFar);
|
||||
elPileCount.textContent = String(removedSoFar);
|
||||
}
|
||||
|
||||
function renderDigit(digitValue, digitIndex, color){
|
||||
const digit = document.createElement("div");
|
||||
digit.className = "digit";
|
||||
|
||||
const baseMask = DIGIT_MASK[digitValue];
|
||||
const baseSegs = segmentsFromMask(baseMask);
|
||||
|
||||
for(const s of segNames){
|
||||
if(!baseSegs.has(s)) continue;
|
||||
|
||||
const seg = document.createElement("div");
|
||||
seg.className = "seg " + s;
|
||||
seg.style.background = color;
|
||||
|
||||
const key = digitIndex + "-" + s;
|
||||
if(removedSet.has(key)) seg.classList.add("removed");
|
||||
|
||||
seg.addEventListener("click", () => {
|
||||
if(removedSet.has(key)) return;
|
||||
if(removedSoFar >= targetRemove) return;
|
||||
|
||||
removedSet.add(key);
|
||||
removedSoFar++;
|
||||
|
||||
|
||||
seg.classList.add("removed");
|
||||
|
||||
|
||||
const clone = document.createElement("div");
|
||||
clone.className = "removedSeg";
|
||||
clone.style.background = color;
|
||||
elRemovedGrid.appendChild(clone);
|
||||
|
||||
syncRemovedCounts();
|
||||
updateTruthUI();
|
||||
|
||||
if(removedSoFar === targetRemove){
|
||||
if(equationIsTrue()){
|
||||
elHint.innerHTML = "<b>Solved!</b> You removed exactly the target and made the equation true. Click <b>New level</b>.";
|
||||
} else {
|
||||
elHint.innerHTML = " <b>Not solved.</b> You used all removals but the equation isn’t true. Click <b>Reset level</b> to try again.";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
digit.appendChild(seg);
|
||||
if (istWahr) {
|
||||
elWahrheitPunkt.classList.add("ok");
|
||||
elWahrheitText.textContent = "Gleichung ist WAHR";
|
||||
} else {
|
||||
elWahrheitPunkt.classList.remove("ok");
|
||||
elWahrheitText.textContent = "Gleichung ist FALSCH";
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
|
||||
function renderEquation(){
|
||||
elEq.innerHTML = "";
|
||||
|
||||
const colors = [
|
||||
"linear-gradient(180deg,#ff6b6b,#d64545)",
|
||||
"linear-gradient(180deg,#6bcBff,#3a7bd5)",
|
||||
"linear-gradient(180deg,#6bffb3,#1fae63)"
|
||||
// Erstellt das HTML für EINE Ziffer
|
||||
function erstelleZifferHTML(zahlenWert, positionIndex, farbe) {
|
||||
const zifferContainer = document.createElement("div");
|
||||
zifferContainer.className = "digit";
|
||||
|
||||
// Welche Segmente hat die Zahl ursprünglich?
|
||||
const maske = ZIFFERN_MUSTER[zahlenWert];
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const segName = SEGMENT_NAMEN[i];
|
||||
|
||||
// Prüfen: Hat die Zahl dieses Segment? (Bit Test)
|
||||
const hatSegment = (maske & (1 << i)) !== 0;
|
||||
|
||||
if (hatSegment) {
|
||||
const segElement = document.createElement("div");
|
||||
segElement.className = "seg " + segName;
|
||||
segElement.style.background = farbe;
|
||||
|
||||
// Eindeutige ID für dieses Segment (z.B. "0-a")
|
||||
const id = positionIndex + "-" + segName;
|
||||
|
||||
// Wenn schon gelöscht, Klasse hinzufügen
|
||||
if (geloeschteStreichhoelzer.has(id)) {
|
||||
segElement.classList.add("removed");
|
||||
}
|
||||
|
||||
// Klick Event (Hier passiert die Action!)
|
||||
segElement.addEventListener("click", () => {
|
||||
// Abbruch wenn schon weg oder Limit erreicht
|
||||
if (geloeschteStreichhoelzer.has(id)) return;
|
||||
if (anzahlGeloescht >= zielAnzahlLoeschen) return;
|
||||
|
||||
// Löschen durchführen
|
||||
geloeschteStreichhoelzer.add(id);
|
||||
anzahlGeloescht++;
|
||||
segElement.classList.add("removed");
|
||||
|
||||
// Kleines Streichholz in den Mülleimer animieren
|
||||
const clone = document.createElement("div");
|
||||
clone.className = "removedSeg";
|
||||
clone.style.background = farbe;
|
||||
elGeloeschtGrid.appendChild(clone);
|
||||
|
||||
updateZaehlerAnzeige();
|
||||
pruefeObWahr();
|
||||
|
||||
// Gewinn Prüfung
|
||||
if (anzahlGeloescht === zielAnzahlLoeschen) {
|
||||
if (istGleichungWahr()) {
|
||||
elHinweis.innerHTML = "<b>Gelöst!</b> Super gemacht. Klicke auf <b>Neu level</b>.";
|
||||
} else {
|
||||
elHinweis.innerHTML = "<b>Nicht gelöst.</b> Alle Züge verbraucht, aber Gleichung falsch. <b>Reset</b>?";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
zifferContainer.appendChild(segElement);
|
||||
}
|
||||
}
|
||||
return zifferContainer;
|
||||
}
|
||||
|
||||
function zeichneGleichung() {
|
||||
elGleichung.innerHTML = ""; // Alles löschen
|
||||
|
||||
const farben = [
|
||||
"linear-gradient(180deg,#ff6b6b,#d64545)", // Rot für A
|
||||
"linear-gradient(180deg,#6bcBff,#3a7bd5)", // Blau für B
|
||||
"linear-gradient(180deg,#6bffb3,#1fae63)" // Grün für C
|
||||
];
|
||||
|
||||
// Gruppe A bauen
|
||||
const g1 = document.createElement("div");
|
||||
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");
|
||||
plus.className = "symbol";
|
||||
plus.textContent = "+";
|
||||
|
||||
// Gruppe B bauen
|
||||
const g2 = document.createElement("div");
|
||||
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");
|
||||
eq.className = "symbol";
|
||||
eq.textContent = "=";
|
||||
|
||||
// Gruppe C bauen
|
||||
const g3 = document.createElement("div");
|
||||
g3.className = "group";
|
||||
g3.appendChild(renderDigit(current.C, 2, colors[2]));
|
||||
g3.appendChild(erstelleZifferHTML(aktuelleGleichung.C, 2, farben[2]));
|
||||
|
||||
elEq.appendChild(g1);
|
||||
elEq.appendChild(plus);
|
||||
elEq.appendChild(g2);
|
||||
elEq.appendChild(eq);
|
||||
elEq.appendChild(g3);
|
||||
// Alles zusammenfügen
|
||||
elGleichung.appendChild(g1);
|
||||
elGleichung.appendChild(plus);
|
||||
elGleichung.appendChild(g2);
|
||||
elGleichung.appendChild(eq);
|
||||
elGleichung.appendChild(g3);
|
||||
|
||||
updateTruthUI();
|
||||
pruefeObWahr();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function generateLevel(){
|
||||
resetPlayState();
|
||||
// 7. LEVEL GENERATOR (Das Gehirn)
|
||||
// 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;
|
||||
while(true){
|
||||
tries++;
|
||||
if(tries > 5000){
|
||||
targetRemove = Math.max(2, targetRemove - 1);
|
||||
tries = 0;
|
||||
let versuche = 0;
|
||||
|
||||
// Endlosschleife, bis wir ein passendes Level finden
|
||||
while (true) {
|
||||
versuche++;
|
||||
// Sicherheitsnetz: Wenn es zu lange dauert, Ziel senken
|
||||
if (versuche > 5000) {
|
||||
zielAnzahlLoeschen = Math.max(2, zielAnzahlLoeschen - 1);
|
||||
versuche = 0;
|
||||
}
|
||||
|
||||
const As = randInt(0, 9);
|
||||
const Bs = randInt(0, 9);
|
||||
const Cs = As + Bs;
|
||||
if(Cs < 0 || Cs > 9) continue;
|
||||
// 1. Wir denken uns eine KORREKTE Lösung aus (z.B. 3 + 5 = 8)
|
||||
const lsgA = zufallsZahl(0, 9);
|
||||
const lsgB = zufallsZahl(0, 9);
|
||||
const lsgC = lsgA + lsgB;
|
||||
|
||||
if (lsgC > 9) continue; // Ergebnis darf nur 1 stellig sein (0-9)
|
||||
|
||||
const Achoices = superDigits(As);
|
||||
const Bchoices = superDigits(Bs);
|
||||
const Cchoices = superDigits(Cs);
|
||||
// 2. Wir suchen Zahlen, die mehr Striche haben als unsere Lösung
|
||||
// (Aus denen man die Lösung "schnitzen" kann)
|
||||
const moeglicheA = findeMoeglicheUrsprungsZiffern(lsgA);
|
||||
const moeglicheB = findeMoeglicheUrsprungsZiffern(lsgB);
|
||||
const moeglicheC = findeMoeglicheUrsprungsZiffern(lsgC);
|
||||
|
||||
const Ashow = pick(Achoices);
|
||||
const Bshow = pick(Bchoices);
|
||||
const Cshow = pick(Cchoices);
|
||||
// Eine zufällige Auswahl treffen
|
||||
const startA = wähleZufällig(moeglicheA);
|
||||
const startB = wähleZufällig(moeglicheB);
|
||||
const startC = wähleZufällig(moeglicheC);
|
||||
|
||||
const need =
|
||||
popcount(DIGIT_MASK[Ashow] ^ DIGIT_MASK[As]) +
|
||||
popcount(DIGIT_MASK[Bshow] ^ DIGIT_MASK[Bs]) +
|
||||
popcount(DIGIT_MASK[Cshow] ^ DIGIT_MASK[Cs]);
|
||||
// 3. Berechnen: Wie viele Striche müssen weg, um zur Lösung zu kommen?
|
||||
// XOR (^) zeigt den Unterschied an.
|
||||
const diffA = zaehleStreichhoelzer(ZIFFERN_MUSTER[startA] ^ ZIFFERN_MUSTER[lsgA]);
|
||||
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;
|
||||
if(shownTrue) continue;
|
||||
// 4. Wichtig: Die angezeigte Start Gleichung muss FALSCH sein.
|
||||
// Sonst gibt es ja nichts zu rätseln.
|
||||
if ((startA + startB) === startC) continue;
|
||||
|
||||
solution = { A: As, B: Bs, C: Cs };
|
||||
current = { A: Ashow, B: Bshow, C: Cshow };
|
||||
break;
|
||||
// Gefunden! Speichern.
|
||||
aktuelleGleichung = { A: startA, B: startB, C: startC };
|
||||
break; // Schleife beenden
|
||||
}
|
||||
|
||||
elLvl.textContent = String(level);
|
||||
elTarget.textContent = String(targetRemove);
|
||||
elGoalN.textContent = String(targetRemove);
|
||||
// UI Updates
|
||||
elLevelAnzeige.textContent = aktuellesLevel;
|
||||
elZielAnzeige.textContent = zielAnzahlLoeschen;
|
||||
elZielText.textContent = zielAnzahlLoeschen;
|
||||
|
||||
elHint.innerHTML =
|
||||
`Level <b>${level}</b>: Make the equation true by removing <b>${targetRemove}</b> match(es). ` +
|
||||
`You can only remove sticks (click them).`;
|
||||
elHinweis.innerHTML =
|
||||
`Level <b>${aktuellesLevel}</b>: Mache die Gleichung wahr, indem du <b>${zielAnzahlLoeschen}</b> Streichhölzer entfernst.`;
|
||||
|
||||
renderEquation();
|
||||
syncRemovedCounts();
|
||||
updateTruthUI();
|
||||
zeichneGleichung();
|
||||
}
|
||||
|
||||
function superDigits(baseDigit){
|
||||
const base = DIGIT_MASK[baseDigit];
|
||||
const res = [];
|
||||
for(let d=0; d<=9; d++){
|
||||
const m = DIGIT_MASK[d];
|
||||
if((m & base) === base){
|
||||
res.push(d);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
generateLevel();
|
||||
// Spiel starten!
|
||||
starteNeuesLevel();
|
||||
Reference in New Issue
Block a user