sdelay-sayt-po-razgadyvaniyu/index.html

417 lines
21 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Космический сканворд — разгадай и победь</title>
<meta name="description" content="Интерактивный сканворд на тему Космос: 12 слов, подсказки, проверка ответов и звёздное поле.">
<link rel="icon" href="design-system/brand/kazakhtelecom-logo.png">
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
<link rel="stylesheet" href="design-system/kt-ai-components.css">
<link rel="stylesheet" href="design-system/kt-ai-page.css">
<style>
* { box-sizing: border-box; }
a.kt-ai-btn { text-decoration: none; }
.stars { position: fixed; inset: 0; pointer-events: none; z-index: -1; }
.star { position: absolute; border-radius: 50%; background: var(--kt-ai-fg); opacity: .35; animation: twinkle 3s ease-in-out infinite; }
@keyframes twinkle { 0%,100% { opacity: .15; } 50% { opacity: .7; } }
.hud { display: flex; align-items: center; gap: var(--kt-ai-space-6); flex-wrap: wrap; margin-top: var(--kt-ai-space-7); }
.hud .stat b { font-size: var(--kt-ai-text-3xl); font-family: var(--kt-ai-font-mono); }
.hud .stat span { font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-faint); }
.progress { flex: 1; min-width: 140px; height: 10px; border-radius: var(--kt-ai-radius-full); overflow: hidden; background: color-mix(in srgb, var(--kt-ai-fg) 10%, transparent); }
.progress i { display: block; height: 100%; background: var(--kt-ai-primary); transition: width .4s ease; border-radius: var(--kt-ai-radius-full); }
.game-layout { display: grid; grid-template-columns: minmax(0,1fr) 330px; gap: var(--kt-ai-space-9); align-items: start; margin-top: var(--kt-ai-space-9); }
@media (max-width: 920px) { .game-layout { grid-template-columns: 1fr; } }
.board-scroll { overflow-x: auto; padding-bottom: var(--kt-ai-space-2); }
.board { display: grid; grid-template-columns: repeat(11, var(--cell, 44px)); grid-auto-rows: var(--cell, 44px); gap: 7px; width: max-content; margin: 0 auto; }
.cell { position: relative; display: grid; place-items: center; border-radius: var(--kt-ai-radius-md); background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); cursor: pointer; }
.cell.block { background: color-mix(in srgb, var(--kt-ai-fg) 6%, transparent); border-color: transparent; cursor: default; }
.cell .num { position: absolute; top: 3px; left: 5px; font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-faint); font-weight: var(--kt-ai-weight-medium); }
.cell input { pointer-events: none; width: 100%; height: 100%; border: 0; background: none; outline: none; text-align: center; font-family: var(--kt-ai-font-mono); font-size: calc(var(--cell, 44px) * .5); font-weight: var(--kt-ai-weight-bold); color: var(--kt-ai-fg); text-transform: uppercase; }
.cell.sel { border-color: var(--kt-ai-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--kt-ai-primary) 45%, transparent); }
.cell.ok { background: color-mix(in srgb, var(--kt-ai-primary) 16%, var(--kt-ai-card-bg)); border-color: color-mix(in srgb, var(--kt-ai-primary) 55%, var(--kt-ai-card-border)); }
.cell.bad { border-color: var(--kt-ai-danger); }
.cell.pop { animation: pop .3s ease; }
@keyframes pop { 0% { transform: scale(1); } 50% { transform: scale(1.18); } 100% { transform: scale(1); } }
.clues-box { background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); border-radius: var(--kt-ai-radius-2xl); padding: var(--kt-ai-space-5); }
.clues-box h3 { margin: 0 0 var(--kt-ai-space-3); font-size: var(--kt-ai-text-lg); display: flex; gap: var(--kt-ai-space-2); align-items: center; }
.clue { display: flex; gap: var(--kt-ai-space-3); padding: var(--kt-ai-space-3); border-radius: var(--kt-ai-radius-lg); cursor: pointer; border: 1px solid transparent; align-items: flex-start; }
.clue:hover { background: color-mix(in srgb, var(--kt-ai-fg) 5%, transparent); }
.clue .n { font-weight: var(--kt-ai-weight-bold); font-family: var(--kt-ai-font-mono); min-width: 22px; color: var(--kt-ai-primary); }
.clue .t { color: var(--kt-ai-fg-muted); font-size: var(--kt-ai-text-sm); }
.clue .w { color: var(--kt-ai-fg-faint); font-size: var(--kt-ai-text-xs); white-space: nowrap; }
.clue.done { opacity: .5; }
.clue.done .t { text-decoration: line-through; }
.clue.sel { border-color: var(--kt-ai-primary); }
.win-banner { margin: var(--kt-ai-space-7) 0 0; padding: var(--kt-ai-space-7); border-radius: var(--kt-ai-radius-2xl); background: color-mix(in srgb, var(--kt-ai-primary) 12%, var(--kt-ai-card-bg)); border: 1px solid color-mix(in srgb, var(--kt-ai-primary) 45%, transparent); text-align: center; }
.board-foot { display: flex; justify-content: center; gap: var(--kt-ai-space-3); flex-wrap: wrap; margin-top: var(--kt-ai-space-6); }
.toast { position: fixed; left: 50%; transform: translateX(-50%); bottom: 24px; background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); border-radius: var(--kt-ai-radius-full); padding: var(--kt-ai-space-3) var(--kt-ai-space-6); z-index: 10; font-size: var(--kt-ai-text-sm); box-shadow: 0 8px 24px rgba(0,0,0,.35); opacity: 0; transition: opacity .3s; }
</style>
</head>
<body>
<div class="stars" id="stars"></div>
<section class="kt-ai-hero" data-align="center">
<div class="kt-ai-wrap">
<div class="kt-ai-hero-actions" style="justify-content:center;margin-bottom:var(--kt-ai-space-4)">
<span class="kt-ai-chip"><svg class="kt-icon" aria-hidden="true"><use href="#rocket"></use></svg> Космос · 12 слов</span>
</div>
<h1>Сканворд «Космос»</h1>
<p class="kt-ai-hero-sub">Выбери слово в списке подсказок, вводи буквы с клавиатуры — собранные слова подсвечиваются сами. Заполни весь космос, чтобы победить!</p>
</div>
</section>
<section class="kt-ai-section" data-divider="true">
<div class="kt-ai-wrap">
<div class="hud">
<div class="stat"><b id="progressWords">0/12</b><span>слов разгадано</span></div>
<div class="progress"><i id="progressBar" style="width:0%"></i></div>
<div class="stat"><b id="timer">0:00</b><span>время</span></div>
</div>
<div class="board-foot">
<button class="kt-ai-btn" data-variant="ghost" data-size="sm" id="btnHint">Подсказать букву</button>
<button class="kt-ai-btn" data-size="sm" id="btnCheck">Проверить</button>
<button class="kt-ai-btn" data-variant="ghost" data-size="sm" id="btnReset">Сбросить</button>
</div>
<div class="win-banner" id="winBanner" hidden>
<div style="display:flex;align-items:center;justify-content:center;gap:var(--kt-ai-space-3)">
<svg class="kt-icon kt-icon-lg" aria-hidden="true"><use href="#trophy"></use></svg>
<h2 style="margin:0">Победа! Космос разгадан за <b id="winTime"></b></h2>
</div>
<p style="margin-top:var(--kt-ai-space-4)">Ты настоящий космонавт. Попробуй ещё раз?</p>
<div class="kt-ai-hero-actions" style="justify-content:center;margin-top:var(--kt-ai-space-5)"><button class="kt-ai-btn" data-variant="primary" id="btnAgain" data-size="lg">Сыграть ещё раз</button></div>
</div>
<div class="game-layout">
<div class="board-scroll"><div class="board" id="board"></div></div>
<aside class="clues-box">
<h3><svg class="kt-icon" aria-hidden="true"><use href="#book"></use></svg> Подсказки</h3>
<div id="clues"></div>
</aside>
</div>
</div>
</section>
<footer class="kt-ai-wrap kt-ai-pagefoot">
<span>© 2026 Космический сканворд</span>
<span class="kt-ai-spacer"></span>
<span>12 слов о Вселенной</span>
</footer>
<script src="design-system/icons/kt-ai-icons.js"></script>
<script>
"use strict";
var ACROSS = {
2: {answer:"КОСМОС", clue:"Слово, с которого началась наша Вселенная"},
4: {answer:"ЛУНА", clue:"Единственный естественный спутник Земли"},
5: {answer:"ЗЕМЛЯ", clue:"Её называют «голубой планетой»"},
6: {answer:"СОЛНЦЕ", clue:"Оно находится в центре нашей системы"},
9: {answer:"ТЕЛЕСКОП", clue:"Прибор для наблюдения за далёкими звёздами"},
10: {answer:"ГРАВИТАЦИЯ", clue:"Сила, которая держит Луну рядом с Землёй"}
};
var DOWN = {
1: {answer:"ЗВЕЗДА", clue:"Вечный огонь, горящий в небе"},
3: {answer:"МЕРКУРИЙ", clue:"Самая близкая к Солнцу планета"},
5: {answer:"ПРИВОЗ", clue:"Пустое место-ловушка в кроссворде"},
8: {answer:"МЕТЕЛЬ", clue:"Она кружит в атмосфере, а в космосе её нет"}
};
var START = {
A: {2:[2,2], 4:[4,4], 5:[6,3], 6:[8,4], 9:[10,1], 10:[10,4]},
D: {1:[2,1], 3:[2,5], 5:[5,6], 8:[6,8]}
};
var TOTAL = 12;
var LETTERS = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
var R = 11, C = 11;
/* ---- сетка ---- */
var grid = [];
for (var gr = 0; gr < R; gr++) { grid[gr] = []; for (var gc = 0; gc < C; gc++) grid[gr][gc] = null; }
function place(dir, id, word, r0, c0) {
for (var i = 0; i < word.length; i++) {
var r = r0 + (dir === "A" ? 0 : i);
var c = c0 + (dir === "A" ? i : 0);
var ch = word[i];
var cell = grid[r][c];
if (!cell) cell = grid[r][c] = {A:null, iA:-1, D:null, iD:-1, ch:""};
if (dir === "A") cell.A = id, cell.iA = i; else cell.D = id, cell.iD = i;
if (cell.ch && cell.ch !== ch) document.body.textContent = "КОЛЛИЗИЯ на " + r + "," + c;
cell.ch = ch;
}
}
for (var ka in ACROSS) place("A", +ka, ACROSS[+ka].answer, START.A[+ka][0], START.A[+ka][1]);
for (var kd in DOWN) place("D", +kd, DOWN[+kd].answer, START.D[+kd][0], START.D[+kd][1]);
/* строка сетки для слова */
function cellsOf(dir, id) {
var w = (dir === "A" ? ACROSS : DOWN)[id];
var s = START[dir][id];
var out = [];
for (var i = 0; i < w.answer.length; i++) out.push({r: s[0] + (dir === "D" ? i : 0), c: s[1] + (dir === "A" ? i : 0)});
return out;
}
/* ---- state ---- */
var letters = {}; // "r_c" -> строка буквы
var selDir = "A", selId = null, selIdx = 0;
var solved = new Set();
var start = Date.now(), timerH = null, won = false, toastH = null;
/* ---- DOM ---- */
var boardEl = document.getElementById("board");
function buildBoard() {
boardEl.innerHTML = "";
for (var r = 0; r < R; r++) for (var c = 0; c < C; c++) {
var d = document.createElement("div");
var cell = grid[r][c];
if (!cell) { d.className = "cell block"; boardEl.appendChild(d); continue; }
d.className = "cell";
d.setAttribute("data-r", r); d.setAttribute("data-c", c);
var numId = null;
if (cell.A !== null && START.A[cell.A][0] === r && START.A[cell.A][1] === c) numId = cell.A;
if (numId === null && cell.D !== null && START.D[cell.D][0] === r && START.D[cell.D][1] === c) numId = cell.D;
if (numId !== null) {
var n = document.createElement("span"); n.className = "num"; n.textContent = numId; d.appendChild(n);
}
var inp = document.createElement("input");
inp.maxLength = 1; inp.setAttribute("data-r", r); inp.setAttribute("data-c", c);
d.appendChild(inp);
d.addEventListener("click", function() { cellClick(+this.getAttribute("data-r"), +this.getAttribute("data-c")); });
boardEl.appendChild(d);
}
}
function id0(cell) { return cell.A !== null ? cell.A : cell.D; }
function cellEl(r, c) { return boardEl.querySelector('.cell[data-r="' + r + '"][data-c="' + c + '"]'); }
function inpEl(r, c) { var e = cellEl(r, c); return e && e.querySelector("input"); }
function selectWord(dir, id, idx) {
selDir = dir; selId = id; selIdx = idx || 0;
document.querySelectorAll(".cell.sel").forEach(function(e){ e.classList.remove("sel"); });
var list = cellsOf(dir, id);
list.forEach(function(p){ cellEl(p.r, p.c).classList.add("sel"); });
renderClues();
}
function cellClick(r, c) {
var cell = grid[r][c]; if (!cell) return;
var dir, id, idx;
if (selDir === "A" && cell.A !== null) { dir = "A"; id = cell.A; idx = cell.iA; }
else if (selDir === "D" && cell.D !== null) { dir = "D"; id = cell.D; idx = cell.iD; }
else if (cell.A !== null) { dir = "A"; id = cell.A; idx = cell.iA; }
else { dir = "D"; id = cell.D; idx = cell.iD; }
selectWord(dir, id, idx);
}
function focusIdx(dir, id, idx) {
selIdx = idx;
var list = cellsOf(dir, id);
var p = list[idx];
document.querySelectorAll(".cell.sel").forEach(function(e){ e.classList.remove("sel"); });
list.forEach(function(q){ cellEl(q.r, q.c).classList.add("sel"); });
var i = inpEl(p.r, p.c); if (i) i.focus();
}
function onInput(e) {
var inp = e.target; if (inp.tagName !== "INPUT") return;
var r = +inp.getAttribute("data-r"), c = +inp.getAttribute("data-c");
v = (v || "").toUpperCase().replace(/Ё/g, "Е");
if (v.length > 1) v = v.slice(-1);
if (v && LETTERS.indexOf(v) === -1) v = "";
inp.value = v;
letters[r + "_" + c] = v;
if (v && selIdx < cellsOf(selDir, selId).length - 1) focusIdx(selDir, selId, selIdx + 1);
refresh();
}
function refresh() {
var done = solvedWords();
solved = done;
document.querySelectorAll(".cell.ok").forEach(function(e){ e.classList.remove("ok"); });
done.forEach(function(key) {
var dir = key[0], id = +key.slice(1);
cellsOf(dir, id).forEach(function(p){ cellEl(p.r, p.c).classList.add("ok"); });
});
document.getElementById("progressWords").textContent = done.size + "/" + TOTAL;
document.getElementById("progressBar").style.width = (done.size / TOTAL * 100) + "%";
renderClues();
if (done.size === TOTAL && !won) win();
}
function solvedWords() {
var done = new Set();
for (var id in ACROSS) {
var w = ACROSS[+id].answer, s = START.A[+id];
if (w.split("").every(function(ch, i){ return letters[s[0] + "_" + (s[1] + i)] === ch; })) done.add("A" + id);
}
for (var id2 in DOWN) {
var w2 = DOWN[+id2].answer, s2 = START.D[+id2];
if (w2.split("").every(function(ch, i){ return letters[(s2[0] + i) + "_" + s2[1]] === ch; })) done.add("D" + id2);
}
return done;
}
function checkBoard() {
var bad = 0;
document.querySelectorAll(".cell.bad").forEach(function(e){ e.classList.remove("bad"); });
for (var id in ACROSS) {
var w = ACROSS[+id].answer, s = START.A[+id];
for (var i = 0; i < w.length; i++) {
var r = s[0], c = s[1] + i; var v = letters[r + "_" + c];
if (v && v !== w[i]) { cellEl(r, c).classList.add("bad"); bad++; }
}
}
for (var id2 in DOWN) {
var w2 = DOWN[+id2].answer, s2 = START.D[+id2];
for (var i2 = 0; i2 < w2.length; i2++) {
var r2 = s2[0] + i2, c2 = s2[1]; var v2 = letters[r2 + "_" + c2];
if (v2 && v2 !== w2[i2]) { cellEl(r2, c2).classList.add("bad"); bad++; }
}
}
setTimeout(function(){ document.querySelectorAll(".cell.bad").forEach(function(e){ e.classList.remove("bad"); }); }, 1200);
toast(bad === 0 ? "Ошибок нет — так держать!" : "Не сойдётся: " + bad + " букв(ы)");
refresh();
}
function hint() {
if (selId === null) { toast("Выбери слово из подсказок"); return; }
var list = cellsOf(selDir, selId);
var w = (selDir === "A" ? ACROSS : DOWN)[selId].answer;
for (var i = 0; i < list.length; i++) {
var p = list[i];
if (!letters[p.r + "_" + p.c]) {
letters[p.r + "_" + p.c] = w[i];
var e = inpEl(p.r, p.c); if (e) e.value = w[i];
cellEl(p.r, p.c).classList.add("pop");
refresh();
toast("Подсказка открыта");
return;
}
}
toast("Это слово уже готово");
}
function win() {
won = true; clearInterval(timerH);
var s = Math.floor((Date.now() - start) / 1000);
document.getElementById("winTime").textContent = Math.floor(s/60) + " мин " + (s % 60) + " с";
document.getElementById("winBanner").hidden = false;
}
function reset() {
letters = {}; solved = new Set(); won = false;
start = Date.now(); document.getElementById("timer").textContent = "0:00";
document.querySelectorAll(".cell").forEach(function(e){ e.classList.remove("ok","bad","sel","win"); });
document.querySelectorAll(".cell input").forEach(function(i){ i.value = ""; });
document.getElementById("winBanner").hidden = true;
clearInterval(timerH); timerH = setInterval(tick, 1000);
refresh(); toast("Заново! Удачи");
}
function tick() {
var s = Math.floor((Date.now() - start) / 1000);
document.getElementById("timer").textContent = Math.floor(s/60) + ":" + (s % 60 < 10 ? "0" : "") + (s % 60);
}
function toast(msg) {
var t = document.querySelector(".toast");
if (!t) { t = document.createElement("div"); t.className = "toast"; document.body.appendChild(t); }
t.textContent = msg; t.style.opacity = "1";
clearTimeout(toastH); toastH = setTimeout(function(){ t.style.opacity = "0"; }, 2200);
}
function renderClues() {
var box = document.getElementById("clues");
box.innerHTML = "";
var done = solvedWords();
function block(dir, map, label) {
var head = document.createElement("div");
head.style.cssText = "font-size:var(--kt-ai-text-xs);color:var(--kt-ai-fg-faint);margin:var(--kt-ai-space-3) 0 var(--kt-ai-space-2);text-transform:uppercase;letter-spacing:.05em";
head.textContent = label; box.appendChild(head);
Object.keys(map).map(Number).sort(function(a,b){return a-b;}).forEach(function(id) {
var key = dir + id;
var el = document.createElement("div");
el.className = "clue" + (done.has(key) ? " done" : "") + (selDir === dir && selId === id ? " sel" : "");
el.innerHTML = '<span class="n">' + id + '</span><div><div class="t">' + map[id].clue + '</div><div class="w">' + map[id].answer.length + ' букв</div></div>';
el.addEventListener("click", function(){ selectWord(dir, id, 0); var l = cellsOf(dir, id); focusIdx(dir, id, 0); var i = inpEl(l[0].r, l[0].c); if (i) i.focus(); });
box.appendChild(el);
});
}
block("A", ACROSS, "Горизонталь");
block("D", DOWN, "Вертикаль");
}
function onKey(e) {
var inp = document.activeElement;
if (inp && inp.tagName !== "INPUT") return;
if (selId === null) return;
var list = cellsOf(selDir, selId);
var w = (selDir === "A" ? ACROSS : DOWN)[selId].answer;
if (e.key === "ArrowRight" && selDir === "A" && selIdx < list.length - 1) { e.preventDefault(); focusIdx("A", selId, selIdx + 1); }
else if (e.key === "ArrowLeft" && selDir === "A" && selIdx > 0) { e.preventDefault(); focusIdx("A", selId, selIdx - 1); }
else if (e.key === "ArrowDown") {
e.preventDefault();
var r = list[selIdx].r, c = list[selIdx].c; var cell = grid[r][c];
if (cell.D !== null) { selectWord("D", cell.D, cell.iD); focusIdx("D", cell.D, cell.iD); }
}
else if (e.key === "ArrowUp") {
e.preventDefault();
var r2 = list[selIdx].r, c2 = list[selIdx].c; var cell2 = grid[r2][c2];
if (cell2.A !== null) { selectWord("A", cell2.A, cell2.iA); focusIdx("A", cell2.A, cell2.iA); }
}
else if (e.key === "Backspace" && !inp.value) {
e.preventDefault();
if (selIdx > 0) {
var p = list[selIdx - 1];
letters[p.r + "_" + p.c] = "";
var i = inpEl(p.r, p.c); if (i) i.value = "";
focusIdx(selDir, selId, selIdx - 1);
refresh();
}
}
}
function buildStars() {
var box = document.getElementById("stars");
for (var i = 0; i < 70; i++) {
var s = document.createElement("span"); s.className = "star";
var sz = Math.random() * 3 + 1;
s.style.width = sz + "px"; s.style.height = sz + "px";
s.style.left = Math.random() * 100 + "%"; s.style.top = Math.random() * 100 + "%";
s.style.animationDelay = (Math.random() * 3) + "s";
s.style.animationDuration = (2 + Math.random() * 3) + "s";
box.appendChild(s);
}
}
function boot() {
buildBoard();
buildStars();
renderClues();
document.querySelectorAll(".cell").forEach(function(d) {
var inp = d.querySelector("input"); if (!inp) return;
inp.addEventListener("input", onInput);
inp.addEventListener("focus", function(){
var r = +inp.getAttribute("data-r"), c = +inp.getAttribute("data-c");
var cell = grid[r][c]; if (!cell) return;
if (selDir === "A" && cell.A !== null) selectWord("A", cell.A, cell.iA);
else if (selDir === "D" && cell.D !== null) selectWord("D", cell.D, cell.iD);
else if (cell.A !== null) selectWord("A", cell.A, cell.iA);
else selectWord("D", cell.D, cell.iD);
});
});
document.addEventListener("keydown", onKey);
document.getElementById("btnHint").addEventListener("click", hint);
document.getElementById("btnCheck").addEventListener("click", checkBoard);
document.getElementById("btnReset").addEventListener("click", reset);
document.getElementById("btnAgain").addEventListener("click", reset);
document.addEventListener("click", function(e) {
if (e.target.closest(".clues-box") || e.target.closest(".board") || e.target.closest(".kt-ai-btn")) return;
document.querySelectorAll(".cell.sel").forEach(function(x){ x.classList.remove("sel"); });
});
timerH = setInterval(tick, 1000); tick();
var l0 = cellsOf("A", 2); focusIdx("A", 2, 0);
}
boot();
</script>
</body>
</html>