Alexboom commited on
Commit
0e62232
·
verified ·
1 Parent(s): c7b11d4

Upload index (1).html

Browse files
Files changed (1) hide show
  1. index (1).html +681 -0
index (1).html ADDED
@@ -0,0 +1,681 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>🧠 Нейро-Змейка — Профессиональная версия</title>
7
+ <style>
8
+ :root {
9
+ --bg: #0f0f23;
10
+ --panel: #1a1a2e;
11
+ --text: #e6e6e6;
12
+ --primary: #4cc9f0;
13
+ --accent: #ff0;
14
+ --success: #0f0;
15
+ --danger: #f44;
16
+ --border: #2d2d44;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ padding: 0;
22
+ box-sizing: border-box;
23
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
24
+ }
25
+
26
+ body {
27
+ background: var(--bg);
28
+ color: var(--text);
29
+ padding: 20px;
30
+ line-height: 1.6;
31
+ }
32
+
33
+ .container {
34
+ max-width: 1400px;
35
+ margin: 0 auto;
36
+ }
37
+
38
+ header {
39
+ text-align: center;
40
+ margin-bottom: 30px;
41
+ padding: 20px;
42
+ background: rgba(26, 26, 46, 0.8);
43
+ border-radius: 15px;
44
+ border: 1px solid var(--primary);
45
+ box-shadow: 0 0 30px rgba(76, 201, 240, 0.2);
46
+ }
47
+
48
+ h1 {
49
+ color: var(--accent);
50
+ font-size: 2.5rem;
51
+ margin-bottom: 10px;
52
+ text-shadow: 0 0 10px var(--accent);
53
+ }
54
+
55
+ .subtitle {
56
+ color: var(--primary);
57
+ font-size: 1.1rem;
58
+ opacity: 0.8;
59
+ }
60
+
61
+ .main-grid {
62
+ display: grid;
63
+ grid-template-columns: 1fr 1fr;
64
+ gap: 25px;
65
+ margin-bottom: 25px;
66
+ }
67
+
68
+ @media (max-width: 1200px) {
69
+ .main-grid {
70
+ grid-template-columns: 1fr;
71
+ }
72
+ }
73
+
74
+ .panel {
75
+ background: var(--panel);
76
+ border-radius: 15px;
77
+ padding: 25px;
78
+ border: 1px solid var(--border);
79
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
80
+ }
81
+
82
+ .panel-title {
83
+ color: var(--primary);
84
+ margin-bottom: 20px;
85
+ padding-bottom: 10px;
86
+ border-bottom: 2px solid var(--border);
87
+ font-size: 1.4rem;
88
+ }
89
+
90
+ .input-group {
91
+ margin-bottom: 20px;
92
+ }
93
+
94
+ label {
95
+ display: block;
96
+ margin-bottom: 8px;
97
+ color: var(--primary);
98
+ font-weight: 600;
99
+ }
100
+
101
+ input, textarea {
102
+ width: 100%;
103
+ padding: 14px;
104
+ background: #0d0d1a;
105
+ border: 2px solid var(--primary);
106
+ color: var(--text);
107
+ border-radius: 8px;
108
+ font-size: 16px;
109
+ transition: border-color 0.3s;
110
+ }
111
+
112
+ input:focus, textarea:focus {
113
+ outline: none;
114
+ border-color: var(--accent);
115
+ box-shadow: 0 0 10px rgba(255, 255, 0, 0.3);
116
+ }
117
+
118
+ .controls {
119
+ display: flex;
120
+ flex-wrap: wrap;
121
+ gap: 15px;
122
+ margin-top: 20px;
123
+ }
124
+
125
+ button {
126
+ background: var(--primary);
127
+ color: #000;
128
+ border: none;
129
+ padding: 14px 28px;
130
+ border-radius: 8px;
131
+ cursor: pointer;
132
+ font-weight: bold;
133
+ font-size: 16px;
134
+ transition: all 0.3s;
135
+ border: 2px solid var(--primary);
136
+ }
137
+
138
+ button:hover {
139
+ background: var(--accent);
140
+ transform: translateY(-2px);
141
+ box-shadow: 0 5px 15px rgba(255, 255, 0, 0.4);
142
+ }
143
+
144
+ .btn-decrypt {
145
+ background: #4361ee;
146
+ border-color: #4361ee;
147
+ }
148
+
149
+ .btn-decrypt:hover {
150
+ background: #4cc9f0;
151
+ border-color: #4cc9f0;
152
+ }
153
+
154
+ .btn-reset {
155
+ background: #f44;
156
+ border-color: #f44;
157
+ }
158
+
159
+ .btn-reset:hover {
160
+ background: #ff0;
161
+ color: #000;
162
+ border-color: #ff0;
163
+ }
164
+
165
+ .result-area {
166
+ min-height: 120px;
167
+ background: #0d0d1a;
168
+ border: 2px solid var(--success);
169
+ border-radius: 8px;
170
+ padding: 20px;
171
+ font-family: 'Courier New', monospace;
172
+ font-size: 18px;
173
+ word-break: break-all;
174
+ }
175
+
176
+ .visualization {
177
+ margin-top: 25px;
178
+ }
179
+
180
+ .grid-container {
181
+ overflow-x: auto;
182
+ white-space: nowrap;
183
+ padding: 15px;
184
+ background: #0d0d1a;
185
+ border-radius: 10px;
186
+ margin-top: 15px;
187
+ }
188
+
189
+ .grid {
190
+ display: inline-block;
191
+ min-width: calc(26 * 36px);
192
+ }
193
+
194
+ .cell {
195
+ width: 36px;
196
+ height: 36px;
197
+ display: inline-block;
198
+ text-align: center;
199
+ line-height: 36px;
200
+ font-size: 14px;
201
+ border: 1px solid var(--border);
202
+ background: #16213e;
203
+ color: var(--text);
204
+ position: relative;
205
+ transition: all 0.2s;
206
+ }
207
+
208
+ .head {
209
+ background: var(--accent) !important;
210
+ color: #000 !important;
211
+ font-weight: bold;
212
+ box-shadow: 0 0 20px var(--accent);
213
+ transform: scale(1.15);
214
+ z-index: 10;
215
+ }
216
+
217
+ .body {
218
+ background: var(--primary) !important;
219
+ color: #000 !important;
220
+ box-shadow: 0 0 10px var(--primary);
221
+ }
222
+
223
+ .status-bar {
224
+ display: flex;
225
+ justify-content: space-around;
226
+ margin-top: 20px;
227
+ padding: 15px;
228
+ background: rgba(26, 26, 46, 0.6);
229
+ border-radius: 10px;
230
+ border: 1px solid var(--border);
231
+ }
232
+
233
+ .status-item {
234
+ text-align: center;
235
+ }
236
+
237
+ .status-value {
238
+ font-size: 1.2rem;
239
+ font-weight: bold;
240
+ color: var(--accent);
241
+ }
242
+
243
+ .status-label {
244
+ font-size: 0.9rem;
245
+ color: var(--primary);
246
+ opacity: 0.8;
247
+ }
248
+
249
+ .log {
250
+ background: #0d0d1a;
251
+ padding: 15px;
252
+ border-radius: 8px;
253
+ margin-top: 15px;
254
+ max-height: 150px;
255
+ overflow-y: auto;
256
+ font-family: monospace;
257
+ font-size: 14px;
258
+ border: 1px solid var(--border);
259
+ }
260
+ </style>
261
+ </head>
262
+ <body>
263
+ <div class="container">
264
+ <header>
265
+ <h1>🧠 Нейро-Змейка — Профессиональная версия</h1>
266
+ <p class="subtitle">Шифрование с лавинным эффектом и полной обратимостью</p>
267
+ </header>
268
+
269
+ <div class="main-grid">
270
+ <div class="panel">
271
+ <h2 class="panel-title">🔐 Настройки шифрования</h2>
272
+
273
+ <div class="input-group">
274
+ <label for="alphabet">🔤 Алфавит (26 букв):</label>
275
+ <input type="text" id="alphabet" value="ABCDEFGHIJKLMNOPQRSTUVWXYZ" readonly>
276
+ </div>
277
+
278
+ <div class="input-group">
279
+ <label for="password">🔑 Пароль:</label>
280
+ <input type="text" id="password" value="NEURAL_SNAKE_2026">
281
+ </div>
282
+
283
+ <div class="input-group">
284
+ <label for="inputText">📄 Исходный текст:</label>
285
+ <textarea id="inputText" rows="4">HELLO WORLD</textarea>
286
+ </div>
287
+
288
+ <div class="controls">
289
+ <button onclick="encrypt()">🔒 Зашифровать</button>
290
+ <button class="btn-reset" onclick="reset()">🔄 Сброс</button>
291
+ </div>
292
+ </div>
293
+
294
+ <div class="panel">
295
+ <h2 class="panel-title">🔓 Расшифровка</h2>
296
+
297
+ <div class="input-group">
298
+ <label for="encryptedText">📜 Зашифрованный текст:</label>
299
+ <textarea id="encryptedText" rows="4"></textarea>
300
+ </div>
301
+
302
+ <div class="input-group">
303
+ <label for="decryptedText">✅ Расшифрованный текст:</label>
304
+ <div class="result-area" id="decryptedText"></div>
305
+ </div>
306
+
307
+ <div class="controls">
308
+ <button class="btn-decrypt" onclick="decrypt()">🔓 Расшифровать</button>
309
+ <button class="btn-reset" onclick="corrupt()">💥 Повредить шифротекст</button>
310
+ </div>
311
+ </div>
312
+ </div>
313
+
314
+ <div class="panel visualization">
315
+ <h2 class="panel-title">🎮 Визуализация змеи</h2>
316
+ <p>Змейка движется по квадрату 26×26. Цвета: <span style="color:#ff0">🟡 Голова</span>, <span style="color:#4cc9f0">🔵 Тело</span></p>
317
+
318
+ <div class="grid-container">
319
+ <div class="grid" id="grid"></div>
320
+ </div>
321
+
322
+ <div class="status-bar">
323
+ <div class="status-item">
324
+ <div class="status-value" id="pathLength">0</div>
325
+ <div class="status-label">Длина пути</div>
326
+ </div>
327
+ <div class="status-item">
328
+ <div class="status-value" id="freeCells">676</div>
329
+ <div class="status-label">Свободных клеток</div>
330
+ </div>
331
+ <div class="status-item">
332
+ <div class="status-value" id="currentPos">0,0</div>
333
+ <div class="status-label">Текущая позиция</div>
334
+ </div>
335
+ </div>
336
+
337
+ <div class="log" id="log"></div>
338
+ </div>
339
+ </div>
340
+
341
+ <script>
342
+ // ==============================
343
+ // ХЕШ-ФУНКЦИЯ (простая, но детерминированная)
344
+ // ==============================
345
+ function simpleHash(str) {
346
+ let hash = 0;
347
+ for (let i = 0; i < str.length; i++) {
348
+ const char = str.charCodeAt(i);
349
+ hash = ((hash << 5) - hash) + char;
350
+ hash = hash & hash; // Преобразуем в 32-битное целое
351
+ }
352
+ return Math.abs(hash);
353
+ }
354
+
355
+ // ==============================
356
+ // ГЕНЕРАЦИЯ КВАДРАТА (Fisher-Yates)
357
+ // ==============================
358
+ function generateSquareFromPassword(alphabet, password) {
359
+ const N = 26;
360
+ const totalCells = N * N;
361
+ let cells = [];
362
+ for (let i = 0; i < totalCells; i++) {
363
+ cells.push(alphabet[i % alphabet.length]);
364
+ }
365
+
366
+ let seed = 0;
367
+ for (let c of password) {
368
+ seed = (seed * 31 + c.charCodeAt(0)) & 0x7FFFFFFF;
369
+ }
370
+
371
+ for (let i = totalCells - 1; i > 0; i--) {
372
+ seed = (seed * 1664525 + 1013904223) & 0x7FFFFFFF;
373
+ const j = Math.floor((seed / 0x80000000) * (i + 1));
374
+ [cells[i], cells[j]] = [cells[j], cells[i]];
375
+ }
376
+
377
+ let square = [];
378
+ for (let i = 0; i < N; i++) {
379
+ let row = '';
380
+ for (let j = 0; j < N; j++) {
381
+ row += cells[i * N + j];
382
+ }
383
+ square.push(row);
384
+ }
385
+ return square;
386
+ }
387
+
388
+ // ==============================
389
+ // ГЕНЕРАЦИЯ ВЕСОВ ИЗ ПАРОЛЯ
390
+ // ==============================
391
+ function generateWeightsFromPassword(password) {
392
+ let seed = 0;
393
+ for (let c of password) {
394
+ seed = (seed * 31 + c.charCodeAt(0)) & 0x7FFFFFFF;
395
+ }
396
+
397
+ const weights = [];
398
+ const totalWeights = 4*64 + 64*64 + 64*676;
399
+ for (let i = 0; i < totalWeights; i++) {
400
+ seed = (seed * 1664525 + 1013904223) & 0x7FFFFFFF;
401
+ weights.push((seed / 0x7FFFFFFF) * 2 - 1);
402
+ }
403
+ return weights;
404
+ }
405
+
406
+ // ==============================
407
+ // НЕЙРОСЕТЬ: ВЫБОР СЛЕДУЮЩЕЙ КЛЕТКИ
408
+ // ==============================
409
+ function neuralChooseNextCell(x, y, step, hashValue, weights, N) {
410
+ const inputs = [
411
+ x / N,
412
+ y / N,
413
+ (step % 1000) / 999,
414
+ (hashValue % 10000) / 9999
415
+ ];
416
+
417
+ // Layer 1: 4 → 64
418
+ const l1 = [];
419
+ for (let i = 0; i < 64; i++) {
420
+ let sum = 0;
421
+ for (let j = 0; j < 4; j++) {
422
+ sum += inputs[j] * weights[i * 4 + j];
423
+ }
424
+ l1.push(Math.tanh(sum));
425
+ }
426
+
427
+ // Layer 2: 64 → 64
428
+ const l2 = [];
429
+ const offset1 = 4 * 64;
430
+ for (let i = 0; i < 64; i++) {
431
+ let sum = 0;
432
+ for (let j = 0; j < 64; j++) {
433
+ sum += l1[j] * weights[offset1 + i * 64 + j];
434
+ }
435
+ l2.push(Math.tanh(sum));
436
+ }
437
+
438
+ // Output: 64 → 676 (рейтинги всех клеток)
439
+ const ratings = [];
440
+ const offset2 = offset1 + 64 * 64;
441
+ for (let i = 0; i < N * N; i++) {
442
+ let sum = 0;
443
+ for (let j = 0; j < 64; j++) {
444
+ sum += l2[j] * weights[offset2 + i * 64 + j];
445
+ }
446
+ ratings.push(sum);
447
+ }
448
+
449
+ return ratings;
450
+ }
451
+
452
+ // ==============================
453
+ // ЗМЕЙКА-ШИФРАТОР
454
+ // ==============================
455
+ class ProfessionalNeuralSnake {
456
+ constructor(alphabet, password) {
457
+ if (alphabet.length !== 26) {
458
+ throw new Error('Алфавит должен содержать ровно 26 символов');
459
+ }
460
+ this.alphabet = alphabet;
461
+ this.password = password;
462
+ this.N = 26;
463
+ this.square = generateSquareFromPassword(alphabet, password);
464
+ this.weights = generateWeightsFromPassword(password);
465
+ }
466
+
467
+ encrypt(text) {
468
+ let x = 0, y = 0;
469
+ let occupied = new Set(["0,0"]);
470
+ let result = '';
471
+ let path = [{x, y}];
472
+
473
+ for (let step = 0; step < text.length; step++) {
474
+ const c = text[step].toUpperCase();
475
+ const idx = this.alphabet.indexOf(c);
476
+
477
+ if (idx !== -1) {
478
+ const keyChar = this.square[y][x];
479
+ const keyIdx = this.alphabet.indexOf(keyChar);
480
+
481
+ // Простое шифрование (можно усилить)
482
+ const cipherIdx = (idx + keyIdx) % this.N;
483
+ const cipherChar = this.alphabet[cipherIdx];
484
+ result += cipherChar;
485
+
486
+ // Хеш всего предыдущего шифротекста
487
+ const prevCipher = result.slice(0, -1);
488
+ const hashValue = simpleHash(prevCipher);
489
+
490
+ // Выбираем следующую клетку
491
+ const ratings = neuralChooseNextCell(x, y, step, hashValue, this.weights, this.N);
492
+ let bestCell = null;
493
+ let bestRating = -Infinity;
494
+
495
+ for (let ny = 0; ny < this.N; ny++) {
496
+ for (let nx = 0; nx < this.N; nx++) {
497
+ if (!occupied.has(`${nx},${ny}`)) {
498
+ const cellIndex = ny * this.N + nx;
499
+ if (ratings[cellIndex] > bestRating) {
500
+ bestRating = ratings[cellIndex];
501
+ bestCell = {x: nx, y: ny};
502
+ }
503
+ }
504
+ }
505
+ }
506
+
507
+ if (bestCell === null) {
508
+ throw new Error(`Нет свободных клеток на шаге ${step}`);
509
+ }
510
+
511
+ x = bestCell.x;
512
+ y = bestCell.y;
513
+ occupied.add(`${x},${y}`);
514
+ path.push({x, y});
515
+ } else {
516
+ result += c;
517
+ path.push({x, y});
518
+ }
519
+ }
520
+
521
+ return { ciphertext: result, path };
522
+ }
523
+
524
+ decrypt(ciphertext) {
525
+ let x = 0, y = 0;
526
+ let occupied = new Set(["0,0"]);
527
+ let result = '';
528
+
529
+ for (let step = 0; step < ciphertext.length; step++) {
530
+ const c = ciphertext[step];
531
+ const idx = this.alphabet.indexOf(c);
532
+
533
+ if (idx !== -1) {
534
+ const keyChar = this.square[y][x];
535
+ const keyIdx = this.alphabet.indexOf(keyChar);
536
+
537
+ const plainIdx = (idx - keyIdx + this.N) % this.N;
538
+ const plainChar = this.alphabet[plainIdx];
539
+ result += plainChar;
540
+
541
+ // Хеш всего предыдущего ШИФРОТЕКСТА (не расшифрованного!)
542
+ const prevCipher = ciphertext.slice(0, step);
543
+ const hashValue = simpleHash(prevCipher);
544
+
545
+ const ratings = neuralChooseNextCell(x, y, step, hashValue, this.weights, this.N);
546
+ let bestCell = null;
547
+ let bestRating = -Infinity;
548
+
549
+ for (let ny = 0; ny < this.N; ny++) {
550
+ for (let nx = 0; nx < this.N; nx++) {
551
+ if (!occupied.has(`${nx},${ny}`)) {
552
+ const cellIndex = ny * this.N + nx;
553
+ if (ratings[cellIndex] > bestRating) {
554
+ bestRating = ratings[cellIndex];
555
+ bestCell = {x: nx, y: ny};
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ if (bestCell === null) break;
562
+
563
+ x = bestCell.x;
564
+ y = bestCell.y;
565
+ occupied.add(`${x},${y}`);
566
+ } else {
567
+ result += c;
568
+ }
569
+ }
570
+
571
+ return result;
572
+ }
573
+
574
+ render(path) {
575
+ let occupied = new Set();
576
+ for (let p of path) {
577
+ occupied.add(`${p.x},${p.y}`);
578
+ }
579
+
580
+ let html = '';
581
+ for (let y = 0; y < this.N; y++) {
582
+ for (let x = 0; x < this.N; x++) {
583
+ let cls = 'cell';
584
+ if (occupied.has(`${x},${y}`)) cls += ' body';
585
+ html += `<div class="${cls}">${this.square[y][x]}</div>`;
586
+ }
587
+ html += '<br>';
588
+ }
589
+ return html;
590
+ }
591
+ }
592
+
593
+ // ==============================
594
+ // ГЛОБАЛЬНЫЕ ФУНКЦИИ
595
+ // ==============================
596
+ let currentPath = [];
597
+
598
+ function encrypt() {
599
+ try {
600
+ const alphabet = document.getElementById('alphabet').value;
601
+ const password = document.getElementById('password').value;
602
+ const text = document.getElementById('inputText').value;
603
+ const cipher = new ProfessionalNeuralSnake(alphabet, password);
604
+ const { ciphertext, path } = cipher.encrypt(text);
605
+ currentPath = path;
606
+ document.getElementById('encryptedText').value = ciphertext;
607
+ document.getElementById('decryptedText').textContent = '';
608
+ document.getElementById('log').textContent = `✅ Зашифровано: "${text}" → "${ciphertext}"`;
609
+ updateVisualization(cipher, path);
610
+ } catch (e) {
611
+ document.getElementById('log').textContent = `❌ Ошибка шифрования: ${e.message}`;
612
+ }
613
+ }
614
+
615
+ function decrypt() {
616
+ try {
617
+ const alphabet = document.getElementById('alphabet').value;
618
+ const password = document.getElementById('password').value;
619
+ const ciphertext = document.getElementById('encryptedText').value;
620
+ if (!ciphertext) {
621
+ throw new Error('Введите зашифрованный текст');
622
+ }
623
+ const cipher = new ProfessionalNeuralSnake(alphabet, password);
624
+ const plaintext = cipher.decrypt(ciphertext);
625
+ document.getElementById('decryptedText').textContent = plaintext;
626
+ document.getElementById('log').textContent = `✅ Расшифровано: "${ciphertext}" → "${plaintext}"`;
627
+ updateVisualization(cipher, currentPath);
628
+ } catch (e) {
629
+ document.getElementById('log').textContent = `❌ Ошибка расшифровки: ${e.message}`;
630
+ }
631
+ }
632
+
633
+ function corrupt() {
634
+ const encrypted = document.getElementById('encryptedText').value;
635
+ if (!encrypted) return;
636
+
637
+ // Изменяем случайный символ
638
+ const chars = encrypted.split('');
639
+ const pos = Math.floor(Math.random() * chars.length);
640
+ const original = chars[pos];
641
+ let replacement;
642
+ do {
643
+ replacement = String.fromCharCode(Math.floor(Math.random() * 26) + 65);
644
+ } while (replacement === original);
645
+ chars[pos] = replacement;
646
+
647
+ document.getElementById('encryptedText').value = chars.join('');
648
+ document.getElementById('log').textContent = `💥 Шифротекст повреждён в позиции ${pos}: ${original} → ${replacement}`;
649
+ }
650
+
651
+ function reset() {
652
+ document.getElementById('inputText').value = 'HELLO WORLD';
653
+ document.getElementById('encryptedText').value = '';
654
+ document.getElementById('decryptedText').textContent = '';
655
+ document.getElementById('log').textContent = 'Система сброшена';
656
+ document.getElementById('grid').innerHTML = '';
657
+ currentPath = [];
658
+ updateStatus(0, 676, '0,0');
659
+ }
660
+
661
+ function updateVisualization(cipher, path) {
662
+ document.getElementById('grid').innerHTML = cipher.render(path);
663
+ updateStatus(
664
+ path.length,
665
+ 676 - path.length,
666
+ path.length > 0 ? `${path[path.length-1].x},${path[path.length-1].y}` : '0,0'
667
+ );
668
+ }
669
+
670
+ function updateStatus(pathLength, freeCells, currentPos) {
671
+ document.getElementById('pathLength').textContent = pathLength;
672
+ document.getElementById('freeCells').textContent = freeCells;
673
+ document.getElementById('currentPos').textContent = currentPos;
674
+ }
675
+
676
+ window.onload = () => {
677
+ reset();
678
+ };
679
+ </script>
680
+ </body>
681
+ </html>