Wasghington commited on
Commit
c7f90e2
·
verified ·
1 Parent(s): d2684e7

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +337 -1380
  2. prompts.txt +4 -1
index.html CHANGED
@@ -1,1426 +1,383 @@
1
  <!DOCTYPE html>
2
- <html lang="pt-br">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Xadrez Interativo</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- .chess-board {
11
- width: min(90vw, 90vh);
12
- height: min(90vw, 90vh);
13
- display: grid;
14
- grid-template-columns: repeat(8, 1fr);
15
- grid-template-rows: repeat(8, 1fr);
16
- border: 2px solid #333;
17
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
18
  }
19
-
20
- .square {
21
- display: flex;
22
- justify-content: center;
23
- align-items: center;
24
- position: relative;
25
- cursor: pointer;
26
- transition: all 0.2s ease;
27
  }
28
-
29
- .square.light {
30
- background-color: #f0d9b5;
31
  }
32
-
33
- .square.dark {
34
- background-color: #b58863;
35
  }
36
-
37
- .square.highlight {
38
- background-color: rgba(20, 85, 30, 0.5);
 
 
 
 
39
  }
40
-
41
- .square.capture {
42
- background-color: rgba(255, 0, 0, 0.5);
43
- }
44
-
45
- .piece {
46
- font-size: 4.5vw;
47
- width: 100%;
48
- height: 100%;
49
- display: flex;
50
- justify-content: center;
51
- align-items: center;
52
- cursor: grab;
53
- user-select: none;
54
- transition: transform 0.2s ease;
55
- }
56
-
57
- .piece:active {
58
- cursor: grabbing;
59
- transform: scale(1.1);
60
- }
61
-
62
- .piece.white {
63
- color: #fff;
64
- text-shadow: 1px 1px 2px #000;
65
- }
66
-
67
- .piece.black {
68
- color: #000;
69
- text-shadow: 1px 1px 2px #fff;
70
- }
71
-
72
- .promotion-modal {
73
- position: fixed;
74
- top: 0;
75
- left: 0;
76
- width: 100%;
77
- height: 100%;
78
- background-color: rgba(0, 0, 0, 0.7);
79
- display: flex;
80
- justify-content: center;
81
- align-items: center;
82
- z-index: 100;
83
- }
84
-
85
- .promotion-options {
86
- background-color: white;
87
- padding: 2rem;
88
- border-radius: 10px;
89
- display: flex;
90
- gap: 1rem;
91
- }
92
-
93
- .promotion-option {
94
- font-size: 3rem;
95
- cursor: pointer;
96
- padding: 0.5rem;
97
- border-radius: 5px;
98
- transition: all 0.2s ease;
99
- }
100
-
101
- .promotion-option:hover {
102
- background-color: #f0f0f0;
103
- transform: scale(1.1);
104
- }
105
-
106
- .move-history {
107
- max-height: 300px;
108
- overflow-y: auto;
109
- border: 1px solid #ddd;
110
- padding: 1rem;
111
- background-color: #f9f9f9;
112
- }
113
-
114
- .move-entry {
115
- padding: 0.3rem 0;
116
- border-bottom: 1px solid #eee;
117
- }
118
-
119
- .move-entry:hover {
120
- background-color: #f0f0f0;
121
- }
122
-
123
- @media (min-width: 768px) {
124
- .piece {
125
- font-size: 2.5vw;
126
  }
127
  }
 
 
 
 
 
 
 
128
  </style>
129
  </head>
130
- <body class="bg-gray-100 min-h-screen flex flex-col items-center py-8">
131
- <div class="container mx-auto px-4">
132
- <h1 class="text-4xl font-bold text-center mb-6 text-gray-800">Xadrez Interativo</h1>
133
-
134
- <div class="flex flex-col lg:flex-row gap-8 items-center lg:items-start justify-center">
135
- <div class="chess-board" id="chessBoard"></div>
136
-
137
- <div class="w-full lg:w-64 mt-6 lg:mt-0">
138
- <div class="bg-white rounded-lg shadow-md p-4">
139
- <h2 class="text-xl font-semibold mb-4 text-gray-800">Informações do Jogo</h2>
140
-
141
- <div class="flex items-center justify-between mb-4">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  <div class="flex items-center">
143
- <div id="currentTurn" class="w-6 h-6 rounded-full mr-2"></div>
144
- <span id="turnText" class="font-medium">Vez das Brancas</span>
145
- </div>
146
- <button id="flipBoard" class="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded text-sm">
147
- <i class="fas fa-sync-alt"></i> Girar
148
- </button>
149
- </div>
150
-
151
- <div class="mb-4">
152
- <div class="flex justify-between mb-1">
153
- <span class="text-sm font-medium">Tempo Brancas</span>
154
- <span id="whiteTime" class="text-sm">10:00</span>
155
- </div>
156
- <div class="w-full bg-gray-200 rounded-full h-2">
157
- <div id="whiteTimeBar" class="bg-white h-2 rounded-full" style="width: 100%"></div>
158
- </div>
159
- </div>
160
-
161
- <div class="mb-4">
162
- <div class="flex justify-between mb-1">
163
- <span class="text-sm font-medium">Tempo Pretas</span>
164
- <span id="blackTime" class="text-sm">10:00</span>
165
- </div>
166
- <div class="w-full bg-gray-200 rounded-full h-2">
167
- <div id="blackTimeBar" class="bg-black h-2 rounded-full" style="width: 100%"></div>
168
  </div>
 
169
  </div>
170
 
171
- <div class="mb-4">
172
- <div class="flex flex-col gap-2">
173
- <button id="newGame" class="w-full bg-green-500 hover:bg-green-600 text-white py-2 rounded">
174
- <i class="fas fa-plus"></i> Novo Jogo
175
- </button>
176
- <button id="undoMove" class="w-full bg-yellow-500 hover:bg-yellow-600 text-white py-2 rounded">
177
- <i class="fas fa-undo"></i> Desfazer
178
- </button>
179
- <div class="flex gap-2">
180
- <button id="playHuman" class="flex-1 bg-blue-500 hover:bg-blue-600 text-white py-2 rounded">
181
- <i class="fas fa-user"></i> Humano
182
- </button>
183
- <button id="playAI" class="flex-1 bg-purple-500 hover:bg-purple-600 text-white py-2 rounded">
184
- <i class="fas fa-robot"></i> IA
185
- </button>
186
  </div>
 
187
  </div>
 
 
 
 
 
 
 
 
 
 
 
188
  </div>
189
-
190
- <h3 class="text-lg font-medium mb-2 text-gray-800">Histórico de Jogadas</h3>
191
- <div class="move-history" id="moveHistory"></div>
 
 
 
 
 
 
 
 
192
  </div>
193
  </div>
194
  </div>
195
- </div>
196
-
197
- <div id="promotionModal" class="promotion-modal hidden">
198
- <div class="promotion-options">
199
- <div class="promotion-option queen" data-piece="queen"><i class="fas fa-chess-queen"></i></div>
200
- <div class="promotion-option rook" data-piece="rook"><i class="fas fa-chess-rook"></i></div>
201
- <div class="promotion-option bishop" data-piece="bishop"><i class="fas fa-chess-bishop"></i></div>
202
- <div class="promotion-option knight" data-piece="knight"><i class="fas fa-chess-knight"></i></div>
203
- </div>
204
- </div>
205
-
206
- <div id="gameOverModal" class="promotion-modal hidden">
207
- <div class="bg-white rounded-lg p-6 max-w-sm w-full text-center">
208
- <h2 class="text-2xl font-bold mb-4" id="gameOverTitle">Xeque-Mate!</h2>
209
- <p class="mb-6" id="gameOverMessage">As brancas venceram!</p>
210
- <button id="newGameModal" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded">
211
- Novo Jogo
212
- </button>
213
  </div>
214
  </div>
215
 
216
  <script>
217
- document.addEventListener('DOMContentLoaded', () => {
218
- // Configuração inicial do jogo
219
- const board = document.getElementById('chessBoard');
220
- const moveHistory = document.getElementById('moveHistory');
221
- const currentTurn = document.getElementById('currentTurn');
222
- const turnText = document.getElementById('turnText');
223
- const flipBoard = document.getElementById('flipBoard');
224
- const newGameBtn = document.getElementById('newGame');
225
- const undoMoveBtn = document.getElementById('undoMove');
226
- const playHumanBtn = document.getElementById('playHuman');
227
- const playAIBtn = document.getElementById('playAI');
228
- const promotionModal = document.getElementById('promotionModal');
229
- const promotionOptions = document.querySelectorAll('.promotion-option');
230
- const gameOverModal = document.getElementById('gameOverModal');
231
- const gameOverTitle = document.getElementById('gameOverTitle');
232
- const gameOverMessage = document.getElementById('gameOverMessage');
233
- const newGameModalBtn = document.getElementById('newGameModal');
234
-
235
- // Elementos de tempo
236
- const whiteTimeDisplay = document.getElementById('whiteTime');
237
- const blackTimeDisplay = document.getElementById('blackTime');
238
- const whiteTimeBar = document.getElementById('whiteTimeBar');
239
- const blackTimeBar = document.getElementById('blackTimeBar');
240
-
241
- // Estado do jogo
242
- let gameState = {
243
- board: Array(8).fill().map(() => Array(8).fill(null)),
244
- turn: 'white',
245
- selectedSquare: null,
246
- possibleMoves: [],
247
- moveHistory: [],
248
- capturedPieces: { white: [], black: [] },
249
- whiteKingPos: { row: 7, col: 4 },
250
- blackKingPos: { row: 0, col: 4 },
251
- whiteCanCastle: { kingside: true, queenside: true },
252
- blackCanCastle: { kingside: true, queenside: true },
253
- enPassantTarget: null,
254
- halfmoveClock: 0,
255
- fullmoveNumber: 1,
256
- flipped: false,
257
- whiteTime: 600, // 10 minutos em segundos
258
- blackTime: 600,
259
- timerInterval: null,
260
- gameOver: false,
261
- vsAI: false,
262
- playerColor: 'white' // O jogador sempre começa como branco contra a IA
263
- };
264
-
265
- // Inicializa o tabuleiro
266
- function initializeBoard() {
267
- // Limpa o tabuleiro
268
- board.innerHTML = '';
269
-
270
- // Cria as casas do tabuleiro
271
- for (let row = 0; row < 8; row++) {
272
- for (let col = 0; col < 8; col++) {
273
- const square = document.createElement('div');
274
- square.className = `square ${(row + col) % 2 === 0 ? 'light' : 'dark'}`;
275
- square.dataset.row = gameState.flipped ? 7 - row : row;
276
- square.dataset.col = gameState.flipped ? 7 - col : col;
277
-
278
- // Adiciona rótulos de coordenadas nas bordas
279
- if ((gameState.flipped && row === 7) || (!gameState.flipped && row === 0)) {
280
- const colLabel = document.createElement('div');
281
- colLabel.className = 'absolute bottom-0 right-0 text-xs p-1';
282
- colLabel.textContent = String.fromCharCode(97 + (gameState.flipped ? 7 - col : col));
283
- square.appendChild(colLabel);
284
- }
285
-
286
- if ((gameState.flipped && col === 0) || (!gameState.flipped && col === 7)) {
287
- const rowLabel = document.createElement('div');
288
- rowLabel.className = 'absolute top-0 left-0 text-xs p-1';
289
- rowLabel.textContent = 8 - (gameState.flipped ? 7 - row : row);
290
- square.appendChild(rowLabel);
291
- }
292
-
293
- board.appendChild(square);
294
- }
295
- }
296
-
297
- updateBoardView();
298
- }
299
-
300
- // Atualiza a visualização do tabuleiro com base no estado do jogo
301
- function updateBoardView() {
302
- // Remove todas as peças do tabuleiro visual
303
- document.querySelectorAll('.piece').forEach(p => p.remove());
304
-
305
- // Remove todos os destaques
306
- document.querySelectorAll('.square').forEach(sq => {
307
- sq.classList.remove('highlight', 'capture');
308
- });
309
-
310
- // Adiciona as peças ao tabuleiro visual
311
- for (let row = 0; row < 8; row++) {
312
- for (let col = 0; col < 8; col++) {
313
- const piece = gameState.board[row][col];
314
- if (piece) {
315
- const square = document.querySelector(`.square[data-row="${row}"][data-col="${col}"]`);
316
- const pieceElement = document.createElement('div');
317
- pieceElement.className = `piece ${piece.color}`;
318
- pieceElement.innerHTML = getPieceIcon(piece.type);
319
- pieceElement.dataset.row = row;
320
- pieceElement.dataset.col = col;
321
- square.appendChild(pieceElement);
322
- }
323
- }
324
- }
325
-
326
- // Destaca a casa selecionada e movimentos possíveis
327
- if (gameState.selectedSquare) {
328
- const { row, col } = gameState.selectedSquare;
329
- const selectedSquare = document.querySelector(`.square[data-row="${row}"][data-col="${col}"]`);
330
- selectedSquare.classList.add('highlight');
331
-
332
- gameState.possibleMoves.forEach(move => {
333
- const targetSquare = document.querySelector(`.square[data-row="${move.row}"][data-col="${move.col}"]`);
334
- if (gameState.board[move.row][move.col]) {
335
- targetSquare.classList.add('capture');
336
- } else {
337
- targetSquare.classList.add('highlight');
338
- }
339
- });
340
- }
341
-
342
- // Atualiza a vez atual
343
- currentTurn.className = `w-6 h-6 rounded-full mr-2 ${gameState.turn === 'white' ? 'bg-white' : 'bg-black'}`;
344
- turnText.textContent = gameState.turn === 'white' ? 'Vez das Brancas' : 'Vez das Pretas';
345
-
346
- // Atualiza o histórico de jogadas
347
- updateMoveHistory();
348
-
349
- // Atualiza os tempos
350
- updateTimeDisplays();
351
-
352
- // Se for a vez da IA e estiver jogando contra ela, faz a jogada
353
- if (gameState.vsAI && gameState.turn !== gameState.playerColor && !gameState.gameOver) {
354
- setTimeout(makeAIMove, 500); // Pequeno atraso para melhor experiência
355
- }
356
- }
357
-
358
- // Retorna o ícone da peça
359
- function getPieceIcon(type) {
360
- const icons = {
361
- pawn: '<i class="fas fa-chess-pawn"></i>',
362
- rook: '<i class="fas fa-chess-rook"></i>',
363
- knight: '<i class="fas fa-chess-knight"></i>',
364
- bishop: '<i class="fas fa-chess-bishop"></i>',
365
- queen: '<i class="fas fa-chess-queen"></i>',
366
- king: '<i class="fas fa-chess-king"></i>'
367
- };
368
- return icons[type];
369
- }
370
-
371
- // Inicializa o estado do tabuleiro
372
- function initializeGameState() {
373
- // Posições iniciais das peças
374
- const initialSetup = [
375
- ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'],
376
- ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'],
377
- [null, null, null, null, null, null, null, null],
378
- [null, null, null, null, null, null, null, null],
379
- [null, null, null, null, null, null, null, null],
380
- [null, null, null, null, null, null, null, null],
381
- ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'],
382
- ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook']
383
- ];
384
-
385
- // Preenche o tabuleiro
386
- for (let row = 0; row < 8; row++) {
387
- for (let col = 0; col < 8; col++) {
388
- const pieceType = initialSetup[row][col];
389
- if (pieceType) {
390
- gameState.board[row][col] = {
391
- type: pieceType,
392
- color: row < 2 ? 'black' : 'white',
393
- hasMoved: false
394
- };
395
- } else {
396
- gameState.board[row][col] = null;
397
- }
398
- }
399
- }
400
-
401
- // Reinicia outras variáveis de estado
402
- gameState.turn = 'white';
403
- gameState.selectedSquare = null;
404
- gameState.possibleMoves = [];
405
- gameState.moveHistory = [];
406
- gameState.capturedPieces = { white: [], black: [] };
407
- gameState.whiteKingPos = { row: 7, col: 4 };
408
- gameState.blackKingPos = { row: 0, col: 4 };
409
- gameState.whiteCanCastle = { kingside: true, queenside: true };
410
- gameState.blackCanCastle = { kingside: true, queenside: true };
411
- gameState.enPassantTarget = null;
412
- gameState.halfmoveClock = 0;
413
- gameState.fullmoveNumber = 1;
414
- gameState.gameOver = false;
415
- gameState.playerColor = 'white'; // Reset para branco
416
-
417
- // Reinicia o timer
418
- if (gameState.timerInterval) {
419
- clearInterval(gameState.timerInterval);
420
- }
421
- gameState.whiteTime = 600;
422
- gameState.blackTime = 600;
423
- startTimer();
424
-
425
- initializeBoard();
426
- }
427
-
428
- // Atualiza o histórico de jogadas
429
- function updateMoveHistory() {
430
- moveHistory.innerHTML = '';
431
-
432
- // Agrupa as jogadas em pares (brancas e pretas)
433
- for (let i = 0; i < gameState.moveHistory.length; i += 2) {
434
- const moveEntry = document.createElement('div');
435
- moveEntry.className = 'move-entry flex';
436
-
437
- const moveNumber = document.createElement('span');
438
- moveNumber.className = 'mr-2 font-medium';
439
- moveNumber.textContent = `${Math.floor(i / 2) + 1}.`;
440
- moveEntry.appendChild(moveNumber);
441
-
442
- // Jogada das brancas
443
- const whiteMove = document.createElement('span');
444
- whiteMove.className = 'mr-2';
445
- whiteMove.textContent = gameState.moveHistory[i].notation;
446
- moveEntry.appendChild(whiteMove);
447
-
448
- // Jogada das pretas (se existir)
449
- if (i + 1 < gameState.moveHistory.length) {
450
- const blackMove = document.createElement('span');
451
- blackMove.textContent = gameState.moveHistory[i + 1].notation;
452
- moveEntry.appendChild(blackMove);
453
- }
454
-
455
- moveHistory.appendChild(moveEntry);
456
- }
457
-
458
- // Rolagem automática para o final
459
- moveHistory.scrollTop = moveHistory.scrollHeight;
460
- }
461
-
462
- // Manipulador de evento para selecionar uma peça
463
- function handleSquareClick(e) {
464
- if (gameState.gameOver || (gameState.vsAI && gameState.turn !== gameState.playerColor)) return;
465
-
466
- const square = e.target.closest('.square');
467
- if (!square) return;
468
-
469
- const row = parseInt(square.dataset.row);
470
- const col = parseInt(square.dataset.col);
471
-
472
- // Se já tiver uma peça selecionada, tenta mover
473
- if (gameState.selectedSquare) {
474
- const move = gameState.possibleMoves.find(m => m.row === row && m.col === col);
475
- if (move) {
476
- makeMove(move);
477
- } else {
478
- // Desseleciona se clicar em outro lugar
479
- gameState.selectedSquare = null;
480
- gameState.possibleMoves = [];
481
- updateBoardView();
482
- }
483
- } else {
484
- // Seleciona uma peça se for do jogador atual
485
- const piece = gameState.board[row][col];
486
- if (piece && piece.color === gameState.turn) {
487
- gameState.selectedSquare = { row, col };
488
- gameState.possibleMoves = getPossibleMoves(row, col);
489
- updateBoardView();
490
- }
491
- }
492
- }
493
-
494
- // Obtém todos os movimentos possíveis para uma peça
495
- function getPossibleMoves(row, col) {
496
- const piece = gameState.board[row][col];
497
- if (!piece || piece.color !== gameState.turn) return [];
498
-
499
- const moves = [];
500
-
501
- switch (piece.type) {
502
- case 'pawn':
503
- getPawnMoves(row, col, piece.color, moves);
504
- break;
505
- case 'rook':
506
- getRookMoves(row, col, piece.color, moves);
507
- break;
508
- case 'knight':
509
- getKnightMoves(row, col, piece.color, moves);
510
- break;
511
- case 'bishop':
512
- getBishopMoves(row, col, piece.color, moves);
513
- break;
514
- case 'queen':
515
- getRookMoves(row, col, piece.color, moves);
516
- getBishopMoves(row, col, piece.color, moves);
517
- break;
518
- case 'king':
519
- getKingMoves(row, col, piece.color, moves);
520
- break;
521
- }
522
-
523
- // Filtra movimentos que deixariam o rei em xeque
524
- return moves.filter(move => {
525
- // Faz o movimento temporariamente
526
- const originalPiece = gameState.board[move.row][move.col];
527
- gameState.board[move.row][move.col] = gameState.board[row][col];
528
- gameState.board[row][col] = null;
529
-
530
- // Atualiza posição do rei se necessário
531
- let kingPosChanged = false;
532
- let originalKingPos;
533
- if (piece.type === 'king') {
534
- originalKingPos = piece.color === 'white' ? { ...gameState.whiteKingPos } : { ...gameState.blackKingPos };
535
- if (piece.color === 'white') {
536
- gameState.whiteKingPos = { row: move.row, col: move.col };
537
- } else {
538
- gameState.blackKingPos = { row: move.row, col: move.col };
539
- }
540
- kingPosChanged = true;
541
- }
542
-
543
- // Verifica se o rei está em xeque
544
- const inCheck = isKingInCheck(piece.color);
545
-
546
- // Desfaz o movimento temporário
547
- gameState.board[row][col] = gameState.board[move.row][move.col];
548
- gameState.board[move.row][move.col] = originalPiece;
549
-
550
- if (kingPosChanged) {
551
- if (piece.color === 'white') {
552
- gameState.whiteKingPos = originalKingPos;
553
- } else {
554
- gameState.blackKingPos = originalKingPos;
555
- }
556
- }
557
-
558
- return !inCheck;
559
- });
560
- }
561
-
562
- // Movimentos do peão
563
- function getPawnMoves(row, col, color, moves) {
564
- const direction = color === 'white' ? -1 : 1;
565
- const startRow = color === 'white' ? 6 : 1;
566
-
567
- // Movimento para frente
568
- if (isValidSquare(row + direction, col) && !gameState.board[row + direction][col]) {
569
- moves.push({ row: row + direction, col });
570
-
571
- // Movimento duplo do início
572
- if (row === startRow && !gameState.board[row + 2 * direction][col]) {
573
- moves.push({ row: row + 2 * direction, col });
574
- }
575
- }
576
-
577
- // Capturas
578
- for (const dc of [-1, 1]) {
579
- if (isValidSquare(row + direction, col + dc)) {
580
- // Captura normal
581
- const targetPiece = gameState.board[row + direction][col + dc];
582
- if (targetPiece && targetPiece.color !== color) {
583
- moves.push({ row: row + direction, col: col + dc });
584
- }
585
-
586
- // En passant
587
- if (gameState.enPassantTarget &&
588
- gameState.enPassantTarget.row === row + direction &&
589
- gameState.enPassantTarget.col === col + dc) {
590
- moves.push({ row: row + direction, col: col + dc, isEnPassant: true });
591
- }
592
- }
593
- }
594
- }
595
-
596
- // Movimentos da torre
597
- function getRookMoves(row, col, color, moves) {
598
- const directions = [
599
- { dr: -1, dc: 0 }, // cima
600
- { dr: 1, dc: 0 }, // baixo
601
- { dr: 0, dc: -1 }, // esquerda
602
- { dr: 0, dc: 1 } // direita
603
- ];
604
-
605
- getSlidingMoves(row, col, color, directions, moves);
606
- }
607
-
608
- // Movimentos do cavalo
609
- function getKnightMoves(row, col, color, moves) {
610
- const knightMoves = [
611
- { dr: -2, dc: -1 }, { dr: -2, dc: 1 },
612
- { dr: -1, dc: -2 }, { dr: -1, dc: 2 },
613
- { dr: 1, dc: -2 }, { dr: 1, dc: 2 },
614
- { dr: 2, dc: -1 }, { dr: 2, dc: 1 }
615
- ];
616
-
617
- for (const move of knightMoves) {
618
- const newRow = row + move.dr;
619
- const newCol = col + move.dc;
620
-
621
- if (isValidSquare(newRow, newCol)) {
622
- const targetPiece = gameState.board[newRow][newCol];
623
- if (!targetPiece || targetPiece.color !== color) {
624
- moves.push({ row: newRow, col: newCol });
625
- }
626
- }
627
- }
628
- }
629
-
630
- // Movimentos do bispo
631
- function getBishopMoves(row, col, color, moves) {
632
- const directions = [
633
- { dr: -1, dc: -1 }, // diagonal superior esquerda
634
- { dr: -1, dc: 1 }, // diagonal superior direita
635
- { dr: 1, dc: -1 }, // diagonal inferior esquerda
636
- { dr: 1, dc: 1 } // diagonal inferior direita
637
- ];
638
-
639
- getSlidingMoves(row, col, color, directions, moves);
640
- }
641
-
642
- // Movimentos do rei
643
- function getKingMoves(row, col, color, moves) {
644
- for (let dr = -1; dr <= 1; dr++) {
645
- for (let dc = -1; dc <= 1; dc++) {
646
- if (dr === 0 && dc === 0) continue;
647
-
648
- const newRow = row + dr;
649
- const newCol = col + dc;
650
-
651
- if (isValidSquare(newRow, newCol)) {
652
- const targetPiece = gameState.board[newRow][newCol];
653
- if (!targetPiece || targetPiece.color !== color) {
654
- moves.push({ row: newRow, col: newCol });
655
- }
656
- }
657
- }
658
- }
659
-
660
- // Roque
661
- const canCastle = color === 'white' ? gameState.whiteCanCastle : gameState.blackCanCastle;
662
- const kingPos = color === 'white' ? gameState.whiteKingPos : gameState.blackKingPos;
663
-
664
- // Roque pequeno (kingside)
665
- if (canCastle.kingside) {
666
- const pathClear = !gameState.board[kingPos.row][5] &&
667
- !gameState.board[kingPos.row][6] &&
668
- gameState.board[kingPos.row][7]?.type === 'rook';
669
-
670
- if (pathClear && !isSquareAttacked(kingPos.row, 5, color) &&
671
- !isSquareAttacked(kingPos.row, 6, color)) {
672
- moves.push({
673
- row: kingPos.row,
674
- col: 6,
675
- isCastle: true,
676
- rookFrom: { row: kingPos.row, col: 7 },
677
- rookTo: { row: kingPos.row, col: 5 }
678
- });
679
- }
680
- }
681
-
682
- // Roque grande (queenside)
683
- if (canCastle.queenside) {
684
- const pathClear = !gameState.board[kingPos.row][3] &&
685
- !gameState.board[kingPos.row][2] &&
686
- !gameState.board[kingPos.row][1] &&
687
- gameState.board[kingPos.row][0]?.type === 'rook';
688
-
689
- if (pathClear && !isSquareAttacked(kingPos.row, 3, color) &&
690
- !isSquareAttacked(kingPos.row, 2, color)) {
691
- moves.push({
692
- row: kingPos.row,
693
- col: 2,
694
- isCastle: true,
695
- rookFrom: { row: kingPos.row, col: 0 },
696
- rookTo: { row: kingPos.row, col: 3 }
697
- });
698
- }
699
- }
700
  }
701
-
702
- // Função auxiliar para movimentos deslizantes (torre, bispo, rainha)
703
- function getSlidingMoves(row, col, color, directions, moves) {
704
- for (const dir of directions) {
705
- let newRow = row + dir.dr;
706
- let newCol = col + dir.dc;
707
-
708
- while (isValidSquare(newRow, newCol)) {
709
- const targetPiece = gameState.board[newRow][newCol];
710
-
711
- if (!targetPiece) {
712
- moves.push({ row: newRow, col: newCol });
713
- } else {
714
- if (targetPiece.color !== color) {
715
- moves.push({ row: newRow, col: newCol });
716
- }
717
- break;
718
- }
719
-
720
- newRow += dir.dr;
721
- newCol += dir.dc;
722
- }
723
  }
724
  }
725
-
726
- // Verifica se uma casa está dentro do tabuleiro
727
- function isValidSquare(row, col) {
728
- return row >= 0 && row < 8 && col >= 0 && col < 8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
729
  }
730
-
731
- // Executa um movimento
732
- function makeMove(move) {
733
- const { row: fromRow, col: fromCol } = gameState.selectedSquare;
734
- const { row: toRow, col: toCol } = move;
735
- const piece = gameState.board[fromRow][fromCol];
736
-
737
- // Cria uma cópia do estado atual para o histórico
738
- const moveCopy = {
739
- from: { row: fromRow, col: fromCol },
740
- to: { row: toRow, col: toCol },
741
- piece: { ...piece },
742
- captured: gameState.board[toRow][toCol] ? { ...gameState.board[toRow][toCol] } : null,
743
- whiteCanCastle: { ...gameState.whiteCanCastle },
744
- blackCanCastle: { ...gameState.blackCanCastle },
745
- enPassantTarget: gameState.enPassantTarget,
746
- halfmoveClock: gameState.halfmoveClock,
747
- fullmoveNumber: gameState.fullmoveNumber
748
- };
749
-
750
- // Atualiza o relógio de meio movimento
751
- if (piece.type === 'pawn' || moveCopy.captured) {
752
- gameState.halfmoveClock = 0;
753
  } else {
754
- gameState.halfmoveClock++;
755
- }
756
-
757
- // Movimento especial: Roque
758
- if (move.isCastle) {
759
- // Move a torre
760
- const rook = gameState.board[move.rookFrom.row][move.rookFrom.col];
761
- gameState.board[move.rookFrom.row][move.rookFrom.col] = null;
762
- gameState.board[move.rookTo.row][move.rookTo.col] = rook;
763
- rook.hasMoved = true;
764
-
765
- moveCopy.isCastle = true;
766
- moveCopy.rookFrom = move.rookFrom;
767
- moveCopy.rookTo = move.rookTo;
768
- }
769
-
770
- // Movimento especial: En passant
771
- if (move.isEnPassant) {
772
- const capturedPawnRow = piece.color === 'white' ? toRow + 1 : toRow - 1;
773
- moveCopy.captured = { ...gameState.board[capturedPawnRow][toCol] };
774
- gameState.board[capturedPawnRow][toCol] = null;
775
-
776
- moveCopy.isEnPassant = true;
777
- moveCopy.capturedAt = { row: capturedPawnRow, col: toCol };
778
- }
779
-
780
- // Move a peça
781
- gameState.board[toRow][toCol] = piece;
782
- gameState.board[fromRow][fromCol] = null;
783
- piece.hasMoved = true;
784
-
785
- // Atualiza posição do rei se necessário
786
- if (piece.type === 'king') {
787
- if (piece.color === 'white') {
788
- gameState.whiteKingPos = { row: toRow, col: toCol };
789
- } else {
790
- gameState.blackKingPos = { row: toRow, col: toCol };
791
- }
792
-
793
- // Perde direito ao roque
794
- if (piece.color === 'white') {
795
- gameState.whiteCanCastle = { kingside: false, queenside: false };
796
- } else {
797
- gameState.blackCanCastle = { kingside: false, queenside: false };
798
- }
799
- }
800
-
801
- // Atualiza direito ao roque se torre for movida
802
- if (piece.type === 'rook') {
803
- if (piece.color === 'white') {
804
- if (fromRow === 7 && fromCol === 0) gameState.whiteCanCastle.queenside = false;
805
- if (fromRow === 7 && fromCol === 7) gameState.whiteCanCastle.kingside = false;
806
- } else {
807
- if (fromRow === 0 && fromCol === 0) gameState.blackCanCastle.queenside = false;
808
- if (fromRow === 0 && fromCol === 7) gameState.blackCanCastle.kingside = false;
809
- }
810
- }
811
-
812
- // Se torre for capturada, atualiza direito ao roque
813
- if (moveCopy.captured?.type === 'rook') {
814
- if (moveCopy.captured.color === 'white') {
815
- if (toRow === 7 && toCol === 0) gameState.whiteCanCastle.queenside = false;
816
- if (toRow === 7 && toCol === 7) gameState.whiteCanCastle.kingside = false;
817
- } else {
818
- if (toRow === 0 && toCol === 0) gameState.blackCanCastle.queenside = false;
819
- if (toRow === 0 && toCol === 7) gameState.blackCanCastle.kingside = false;
820
- }
821
- }
822
-
823
- // Define alvo en passant se peão avançar duas casas
824
- gameState.enPassantTarget = null;
825
- if (piece.type === 'pawn' && Math.abs(toRow - fromRow) === 2) {
826
- gameState.enPassantTarget = {
827
- row: fromRow + (toRow - fromRow) / 2,
828
- col: fromCol
829
- };
830
- }
831
-
832
- // Promoção de peão
833
- if (piece.type === 'pawn' && (toRow === 0 || toRow === 7)) {
834
- showPromotionModal(toRow, toCol, piece.color);
835
- moveCopy.promotionPending = true;
836
- }
837
-
838
- // Adiciona peça capturada à lista
839
- if (moveCopy.captured) {
840
- gameState.capturedPieces[piece.color].push(moveCopy.captured);
841
- }
842
-
843
- // Incrementa o número de movimento completo se for a vez das pretas
844
- if (gameState.turn === 'black') {
845
- gameState.fullmoveNumber++;
846
- }
847
-
848
- // Alterna o turno
849
- gameState.turn = gameState.turn === 'white' ? 'black' : 'white';
850
-
851
- // Adiciona ao histórico
852
- moveCopy.notation = getMoveNotation(moveCopy);
853
- gameState.moveHistory.push(moveCopy);
854
-
855
- // Verifica xeque-mate ou afogamento
856
- checkGameEnd();
857
-
858
- // Limpa seleção e atualiza tabuleiro
859
- gameState.selectedSquare = null;
860
- gameState.possibleMoves = [];
861
- updateBoardView();
862
- }
863
-
864
- // Mostra modal de promoção de peão
865
- function showPromotionModal(row, col, color) {
866
- gameState.gameOver = true; // Pausa o jogo até a promoção ser feita
867
- promotionModal.classList.remove('hidden');
868
-
869
- // Configura os ícones de acordo com a cor
870
- promotionOptions.forEach(option => {
871
- option.className = `promotion-option ${option.dataset.piece} ${color}`;
872
- option.innerHTML = getPieceIcon(option.dataset.piece);
873
- });
874
-
875
- // Armazena informações da promoção
876
- promotionModal.dataset.row = row;
877
- promotionModal.dataset.col = col;
878
- promotionModal.dataset.color = color;
879
- }
880
-
881
- // Completa a promoção de peão
882
- function completePromotion(pieceType) {
883
- const row = parseInt(promotionModal.dataset.row);
884
- const col = parseInt(promotionModal.dataset.col);
885
- const color = promotionModal.dataset.color;
886
-
887
- // Atualiza a peça
888
- gameState.board[row][col].type = pieceType;
889
-
890
- // Atualiza o último movimento no histórico
891
- const lastMove = gameState.moveHistory[gameState.moveHistory.length - 1];
892
- lastMove.promotion = pieceType;
893
- lastMove.notation = getMoveNotation(lastMove);
894
-
895
- promotionModal.classList.add('hidden');
896
- gameState.gameOver = false;
897
- updateBoardView();
898
- checkGameEnd(); // Verifica novamente o fim do jogo após promoção
899
- }
900
-
901
- // Verifica se o jogo terminou (xeque-mate ou afogamento)
902
- function checkGameEnd() {
903
- // Verifica se o rei atual está em xeque
904
- const inCheck = isKingInCheck(gameState.turn);
905
-
906
- // Verifica se há movimentos legais disponíveis
907
- const hasLegalMoves = hasAnyLegalMove(gameState.turn);
908
-
909
- if (inCheck && !hasLegalMoves) {
910
- // Xeque-mate
911
- endGame('mate', gameState.turn === 'white' ? 'black' : 'white');
912
- } else if (!inCheck && !hasLegalMoves) {
913
- // Afogamento
914
- endGame('stalemate');
915
- } else if (isDrawByMaterial()) {
916
- // Empate por material insuficiente
917
- endGame('insufficient');
918
- } else if (gameState.halfmoveClock >= 50) {
919
- // Regra dos 50 movimentos
920
- endGame('50move');
921
- }
922
- }
923
-
924
- // Verifica se o rei está em xeque
925
- function isKingInCheck(color) {
926
- const kingPos = color === 'white' ? gameState.whiteKingPos : gameState.blackKingPos;
927
- return isSquareAttacked(kingPos.row, kingPos.col, color);
928
- }
929
-
930
- // Verifica se uma casa está sendo atacada
931
- function isSquareAttacked(row, col, defenderColor) {
932
- for (let r = 0; r < 8; r++) {
933
- for (let c = 0; c < 8; c++) {
934
- const piece = gameState.board[r][c];
935
- if (piece && piece.color !== defenderColor) {
936
- const moves = getRawMoves(r, c, piece.color);
937
- if (moves.some(m => m.row === row && m.col === col)) {
938
- return true;
939
- }
940
- }
941
- }
942
- }
943
- return false;
944
- }
945
-
946
- // Obtém movimentos sem verificar xeque (para verificação de ataques)
947
- function getRawMoves(row, col, color) {
948
- const piece = gameState.board[row][col];
949
- if (!piece || piece.color !== color) return [];
950
-
951
- const moves = [];
952
-
953
- switch (piece.type) {
954
- case 'pawn':
955
- // Peões atacam de forma diferente do que se movem
956
- const direction = color === 'white' ? -1 : 1;
957
- for (const dc of [-1, 1]) {
958
- if (isValidSquare(row + direction, col + dc)) {
959
- moves.push({ row: row + direction, col: col + dc });
960
- }
961
- }
962
- break;
963
- case 'rook':
964
- getRookMoves(row, col, color, moves);
965
- break;
966
- case 'knight':
967
- getKnightMoves(row, col, color, moves);
968
- break;
969
- case 'bishop':
970
- getBishopMoves(row, col, color, moves);
971
- break;
972
- case 'queen':
973
- getRookMoves(row, col, color, moves);
974
- getBishopMoves(row, col, color, moves);
975
- break;
976
- case 'king':
977
- getKingMoves(row, col, color, moves);
978
- break;
979
- }
980
-
981
- return moves;
982
- }
983
-
984
- // Verifica se há algum movimento legal disponível
985
- function hasAnyLegalMove(color) {
986
- for (let row = 0; row < 8; row++) {
987
- for (let col = 0; col < 8; col++) {
988
- const piece = gameState.board[row][col];
989
- if (piece && piece.color === color) {
990
- const moves = getPossibleMoves(row, col);
991
- if (moves.length > 0) {
992
- return true;
993
- }
994
- }
995
- }
996
- }
997
- return false;
998
- }
999
-
1000
- // Verifica empate por material insuficiente
1001
- function isDrawByMaterial() {
1002
- let whitePieces = [];
1003
- let blackPieces = [];
1004
-
1005
- for (let row = 0; row < 8; row++) {
1006
- for (let col = 0; col < 8; col++) {
1007
- const piece = gameState.board[row][col];
1008
- if (piece) {
1009
- if (piece.color === 'white') {
1010
- whitePieces.push(piece.type);
1011
- } else {
1012
- blackPieces.push(piece.type);
1013
- }
1014
- }
1015
- }
1016
- }
1017
-
1018
- // Filtra peões, torres, rainhas e bispos/cavalos
1019
- whitePieces = whitePieces.filter(p => p !== 'king');
1020
- blackPieces = blackPieces.filter(p => p !== 'king');
1021
-
1022
- // Caso 1: Rei vs Rei
1023
- if (whitePieces.length === 0 && blackPieces.length === 0) {
1024
- return true;
1025
- }
1026
-
1027
- // Caso 2: Rei e bispo vs Rei
1028
- if ((whitePieces.length === 1 && whitePieces[0] === 'bishop' && blackPieces.length === 0) ||
1029
- (blackPieces.length === 1 && blackPieces[0] === 'bishop' && whitePieces.length === 0)) {
1030
- return true;
1031
- }
1032
-
1033
- // Caso 3: Rei e cavalo vs Rei
1034
- if ((whitePieces.length === 1 && whitePieces[0] === 'knight' && blackPieces.length === 0) ||
1035
- (blackPieces.length === 1 && blackPieces[0] === 'knight' && whitePieces.length === 0)) {
1036
- return true;
1037
- }
1038
-
1039
- // Caso 4: Rei e bispo vs Rei e bispo (mesma cor)
1040
- if (whitePieces.length === 1 && whitePieces[0] === 'bishop' &&
1041
- blackPieces.length === 1 && blackPieces[0] === 'bishop') {
1042
- // Verifica cor dos bispos (complexo, vamos simplificar)
1043
- return true;
1044
- }
1045
-
1046
- return false;
1047
- }
1048
-
1049
- // Finaliza o jogo
1050
- function endGame(reason, winner) {
1051
- gameState.gameOver = true;
1052
-
1053
- if (gameState.timerInterval) {
1054
- clearInterval(gameState.timerInterval);
1055
- gameState.timerInterval = null;
1056
- }
1057
-
1058
- let title, message;
1059
-
1060
- switch (reason) {
1061
- case 'mate':
1062
- title = 'Xeque-Mate!';
1063
- message = `As ${winner === 'white' ? 'brancas' : 'pretas'} venceram!`;
1064
- break;
1065
- case 'stalemate':
1066
- title = 'Afogamento!';
1067
- message = 'Empate por afogamento.';
1068
- break;
1069
- case 'insufficient':
1070
- title = 'Empate!';
1071
- message = 'Empate por material insuficiente.';
1072
- break;
1073
- case '50move':
1074
- title = 'Empate!';
1075
- message = 'Empate pela regra dos 50 movimentos.';
1076
- break;
1077
- case 'time':
1078
- title = 'Tempo Esgotado!';
1079
- message = `As ${winner === 'white' ? 'brancas' : 'pretas'} venceram por tempo!`;
1080
- break;
1081
- }
1082
-
1083
- gameOverTitle.textContent = title;
1084
- gameOverMessage.textContent = message;
1085
- gameOverModal.classList.remove('hidden');
1086
- }
1087
-
1088
- // Gera notação algébrica para o movimento
1089
- function getMoveNotation(move) {
1090
- const piece = move.piece;
1091
- const from = move.from;
1092
- const to = move.to;
1093
- const captured = move.captured;
1094
-
1095
- let notation = '';
1096
-
1097
- // Peões
1098
- if (piece.type === 'pawn') {
1099
- if (captured) {
1100
- notation += String.fromCharCode(97 + from.col) + 'x';
1101
- }
1102
- notation += String.fromCharCode(97 + to.col) + (8 - to.row);
1103
-
1104
- // Promoção
1105
- if (move.promotion) {
1106
- notation += '=' + move.promotion[0].toUpperCase();
1107
- }
1108
-
1109
- return notation;
1110
- }
1111
-
1112
- // Outras peças
1113
- notation += piece.type[0].toUpperCase();
1114
-
1115
- // Para peças que podem ter ambiguidade (duas torres/cavalos/bispos podem ir para mesma casa)
1116
- const ambiguousPieces = [];
1117
- for (let row = 0; row < 8; row++) {
1118
- for (let col = 0; col < 8; col++) {
1119
- const p = gameState.board[row][col];
1120
- if (p && p.type === piece.type && p.color === piece.color &&
1121
- !(row === from.row && col === from.col)) {
1122
- const moves = getPossibleMoves(row, col);
1123
- if (moves.some(m => m.row === to.row && m.col === to.col)) {
1124
- ambiguousPieces.push({ row, col });
1125
- }
1126
- }
1127
- }
1128
- }
1129
-
1130
- // Adiciona informação de desambiguação se necessário
1131
- if (ambiguousPieces.length > 0) {
1132
- const sameCol = ambiguousPieces.some(p => p.col === from.col);
1133
- const sameRow = ambiguousPieces.some(p => p.row === from.row);
1134
-
1135
- if (!sameCol) {
1136
- notation += String.fromCharCode(97 + from.col);
1137
- } else if (!sameRow) {
1138
- notation += (8 - from.row);
1139
- } else {
1140
- notation += String.fromCharCode(97 + from.col) + (8 - from.row);
1141
- }
1142
- }
1143
-
1144
- // Captura
1145
- if (captured) {
1146
- notation += 'x';
1147
- }
1148
-
1149
- // Casa de destino
1150
- notation += String.fromCharCode(97 + to.col) + (8 - to.row);
1151
-
1152
- // Roque
1153
- if (move.isCastle) {
1154
- if (to.col === 6) return 'O-O'; // Roque pequeno
1155
- if (to.col === 2) return 'O-O-O'; // Roque grande
1156
- }
1157
-
1158
- return notation;
1159
- }
1160
-
1161
- // Desfaz o último movimento
1162
- function undoLastMove() {
1163
- if (gameState.moveHistory.length === 0 || gameState.gameOver) return;
1164
-
1165
- const lastMove = gameState.moveHistory.pop();
1166
-
1167
- // Restaura a peça movida
1168
- gameState.board[lastMove.from.row][lastMove.from.col] = lastMove.piece;
1169
- gameState.board[lastMove.to.row][lastMove.to.col] = lastMove.captured;
1170
-
1171
- // Restaura posição do rei se necessário
1172
- if (lastMove.piece.type === 'king') {
1173
- if (lastMove.piece.color === 'white') {
1174
- gameState.whiteKingPos = { row: lastMove.from.row, col: lastMove.from.col };
1175
- } else {
1176
- gameState.blackKingPos = { row: lastMove.from.row, col: lastMove.from.col };
1177
- }
1178
- }
1179
-
1180
- // Restaura roque se necessário
1181
- if (lastMove.isCastle) {
1182
- const rook = gameState.board[lastMove.rookTo.row][lastMove.rookTo.col];
1183
- gameState.board[lastMove.rookTo.row][lastMove.rookTo.col] = null;
1184
- gameState.board[lastMove.rookFrom.row][lastMove.rookFrom.col] = rook;
1185
- rook.hasMoved = false;
1186
- }
1187
-
1188
- // Restaura en passant se necessário
1189
- if (lastMove.isEnPassant) {
1190
- gameState.board[lastMove.capturedAt.row][lastMove.capturedAt.col] = lastMove.captured;
1191
- }
1192
-
1193
- // Restaura direitos de roque
1194
- gameState.whiteCanCastle = lastMove.whiteCanCastle;
1195
- gameState.blackCanCastle = lastMove.blackCanCastle;
1196
-
1197
- // Restaura alvo en passant
1198
- gameState.enPassantTarget = lastMove.enPassantTarget;
1199
-
1200
- // Restaura relógios
1201
- gameState.halfmoveClock = lastMove.halfmoveClock;
1202
- gameState.fullmoveNumber = lastMove.fullmoveNumber;
1203
-
1204
- // Remove peça capturada da lista
1205
- if (lastMove.captured) {
1206
- gameState.capturedPieces[lastMove.piece.color].pop();
1207
  }
1208
-
1209
- // Alterna o turno de volta
1210
- gameState.turn = lastMove.piece.color;
1211
-
1212
- // Se estava em promoção, cancela
1213
- promotionModal.classList.add('hidden');
1214
- gameState.gameOver = false;
1215
-
1216
- // Atualiza a visualização
1217
- gameState.selectedSquare = null;
1218
- gameState.possibleMoves = [];
1219
- updateBoardView();
1220
- }
1221
-
1222
- // Inicia o timer
1223
- function startTimer() {
1224
- if (gameState.timerInterval) {
1225
- clearInterval(gameState.timerInterval);
1226
  }
1227
-
1228
- gameState.timerInterval = setInterval(() => {
1229
- if (gameState.gameOver) return;
1230
-
1231
- if (gameState.turn === 'white') {
1232
- gameState.whiteTime--;
1233
- if (gameState.whiteTime <= 0) {
1234
- endGame('time', 'black');
1235
- }
1236
- } else {
1237
- gameState.blackTime--;
1238
- if (gameState.blackTime <= 0) {
1239
- endGame('time', 'white');
1240
- }
1241
- }
1242
-
1243
- updateTimeDisplays();
1244
- }, 1000);
1245
  }
1246
-
1247
- // Atualiza os displays de tempo
1248
- function updateTimeDisplays() {
1249
- const whiteMinutes = Math.floor(gameState.whiteTime / 60);
1250
- const whiteSeconds = gameState.whiteTime % 60;
1251
- whiteTimeDisplay.textContent = `${whiteMinutes}:${whiteSeconds < 10 ? '0' : ''}${whiteSeconds}`;
1252
-
1253
- const blackMinutes = Math.floor(gameState.blackTime / 60);
1254
- const blackSeconds = gameState.blackTime % 60;
1255
- blackTimeDisplay.textContent = `${blackMinutes}:${blackSeconds < 10 ? '0' : ''}${blackSeconds}`;
1256
-
1257
- // Atualiza barras de progresso
1258
- const maxTime = 600; // 10 minutos
1259
- whiteTimeBar.style.width = `${(gameState.whiteTime / maxTime) * 100}%`;
1260
- blackTimeBar.style.width = `${(gameState.blackTime / maxTime) * 100}%`;
 
 
 
1261
  }
1262
-
1263
- // Função para a IA fazer uma jogada
1264
- function makeAIMove() {
1265
- if (gameState.gameOver || !gameState.vsAI || gameState.turn === gameState.playerColor) return;
1266
-
1267
- // Encontra todas as peças da IA
1268
- const aiPieces = [];
1269
- for (let row = 0; row < 8; row++) {
1270
- for (let col = 0; col < 8; col++) {
1271
- const piece = gameState.board[row][col];
1272
- if (piece && piece.color === gameState.turn) {
1273
- aiPieces.push({ row, col });
1274
- }
1275
- }
1276
- }
1277
-
1278
- // Coleta todos os movimentos possíveis
1279
- const allMoves = [];
1280
- for (const piece of aiPieces) {
1281
- const moves = getPossibleMoves(piece.row, piece.col);
1282
- for (const move of moves) {
1283
- allMoves.push({
1284
- from: { row: piece.row, col: piece.col },
1285
- to: { row: move.row, col: move.col },
1286
- moveData: move
1287
- });
1288
- }
1289
- }
1290
-
1291
- if (allMoves.length === 0) return;
1292
-
1293
- // Avalia os movimentos e escolhe o melhor
1294
- const evaluatedMoves = allMoves.map(move => {
1295
- return {
1296
- ...move,
1297
- score: evaluateMove(move)
1298
- };
1299
- });
1300
-
1301
- // Ordena os movimentos por pontuação (melhores primeiro)
1302
- evaluatedMoves.sort((a, b) => b.score - a.score);
1303
-
1304
- // Escolhe um movimento aleatório entre os melhores (para variar)
1305
- const topMoves = evaluatedMoves.slice(0, Math.max(3, Math.floor(evaluatedMoves.length / 2)));
1306
- const selectedMove = topMoves[Math.floor(Math.random() * topMoves.length)];
1307
-
1308
- // Faz o movimento selecionado
1309
- gameState.selectedSquare = selectedMove.from;
1310
- gameState.possibleMoves = [selectedMove.moveData];
1311
-
1312
- // Pequeno atraso para melhor experiência visual
1313
  setTimeout(() => {
1314
- makeMove(selectedMove.moveData);
1315
- }, 300);
1316
  }
1317
-
1318
- // Avalia um movimento para a IA
1319
- function evaluateMove(move) {
1320
- const from = move.from;
1321
- const to = move.to;
1322
- const piece = gameState.board[from.row][from.col];
1323
- const targetPiece = gameState.board[to.row][to.col];
1324
-
1325
- let score = 0;
1326
-
1327
- // Valor da peça capturada
1328
- if (targetPiece) {
1329
- score += getPieceValue(targetPiece.type) * 1.5;
1330
- }
1331
-
1332
- // Valor da peça que está se movendo (evitar perder peças valiosas)
1333
- score -= getPieceValue(piece.type) * 0.1;
1334
-
1335
- // Movimentos especiais
1336
- if (move.moveData.isEnPassant) {
1337
- score += getPieceValue('pawn') * 1.5;
1338
- }
1339
-
1340
- if (move.moveData.isCastle) {
1341
- score += 0.5; // Roque é geralmente bom
1342
- }
1343
-
1344
- // Promoção de peão
1345
- if (piece.type === 'pawn' && (to.row === 0 || to.row === 7)) {
1346
- score += getPieceValue('queen') - getPieceValue('pawn'); // Assume promoção para rainha
1347
- }
1348
-
1349
- // Controle do centro
1350
- const centerSquares = [[3, 3], [3, 4], [4, 3], [4, 4]];
1351
- if (centerSquares.some(sq => sq[0] === to.row && sq[1] === to.col)) {
1352
- score += 0.3;
1353
- }
1354
-
1355
- // Desenvolvimento de peças (movimentar peças no início do jogo)
1356
- if (!piece.hasMoved) {
1357
- score += 0.2;
1358
- }
1359
-
1360
- // Segurança do rei (evitar colocar o rei em xeque)
1361
- // Isso já é verificado em getPossibleMoves, então não precisamos verificar aqui
1362
-
1363
- return score;
1364
- }
1365
-
1366
- // Retorna o valor relativo de cada peça
1367
- function getPieceValue(type) {
1368
- const values = {
1369
- pawn: 1,
1370
- knight: 3,
1371
- bishop: 3,
1372
- rook: 5,
1373
- queen: 9,
1374
- king: 100 // O rei é muito valioso para ser capturado
1375
- };
1376
- return values[type];
1377
- }
1378
-
1379
- // Alterna entre jogar contra humano ou IA
1380
- function toggleAIMode(playAgainstAI) {
1381
- gameState.vsAI = playAgainstAI;
1382
-
1383
- // Atualiza botões
1384
- if (playAgainstAI) {
1385
- playHumanBtn.classList.remove('bg-blue-500', 'hover:bg-blue-600');
1386
- playHumanBtn.classList.add('bg-gray-400', 'hover:bg-gray-500');
1387
- playAIBtn.classList.remove('bg-gray-400', 'hover:bg-gray-500');
1388
- playAIBtn.classList.add('bg-purple-500', 'hover:bg-purple-600');
1389
  } else {
1390
- playHumanBtn.classList.remove('bg-gray-400', 'hover:bg-gray-500');
1391
- playHumanBtn.classList.add('bg-blue-500', 'hover:bg-blue-600');
1392
- playAIBtn.classList.remove('bg-purple-500', 'hover:bg-purple-600');
1393
- playAIBtn.classList.add('bg-gray-400', 'hover:bg-gray-500');
1394
- }
1395
-
1396
- // Se estiver jogando contra IA e for a vez dela, faz a jogada
1397
- if (gameState.vsAI && gameState.turn !== gameState.playerColor && !gameState.gameOver) {
1398
- setTimeout(makeAIMove, 500);
1399
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1400
  }
1401
-
1402
- // Event listeners
1403
- board.addEventListener('click', handleSquareClick);
1404
- flipBoard.addEventListener('click', () => {
1405
- gameState.flipped = !gameState.flipped;
1406
- initializeBoard();
1407
- });
1408
- newGameBtn.addEventListener('click', initializeGameState);
1409
- undoMoveBtn.addEventListener('click', undoLastMove);
1410
- playHumanBtn.addEventListener('click', () => toggleAIMode(false));
1411
- playAIBtn.addEventListener('click', () => toggleAIMode(true));
1412
- promotionOptions.forEach(option => {
1413
- option.addEventListener('click', () => {
1414
- completePromotion(option.dataset.piece);
1415
- });
1416
- });
1417
- newGameModalBtn.addEventListener('click', () => {
1418
- gameOverModal.classList.add('hidden');
1419
- initializeGameState();
1420
- });
1421
-
1422
- // Inicializa o jogo
1423
- initializeGameState();
1424
  });
1425
  </script>
1426
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Wasghington/kakttus-ai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
1
  <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Aprendendo a Ler - Jogo Infantil</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ @keyframes bounce {
11
+ 0%, 100% { transform: translateY(0); }
12
+ 50% { transform: translateY(-20px); }
 
 
 
 
 
13
  }
14
+ .bounce-animation {
15
+ animation: bounce 1s infinite;
 
 
 
 
 
 
16
  }
17
+ .word-card {
18
+ transition: all 0.3s ease;
 
19
  }
20
+ .word-card:hover {
21
+ transform: scale(1.05);
 
22
  }
23
+ .confetti {
24
+ position: absolute;
25
+ width: 10px;
26
+ height: 10px;
27
+ background-color: #f00;
28
+ border-radius: 50%;
29
+ animation: fall 3s linear forwards;
30
  }
31
+ @keyframes fall {
32
+ to {
33
+ transform: translateY(100vh) rotate(360deg);
34
+ opacity: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
  }
37
+ #wordImage {
38
+ background-size: contain;
39
+ background-repeat: no-repeat;
40
+ background-position: center;
41
+ width: 200px;
42
+ height: 200px;
43
+ }
44
  </style>
45
  </head>
46
+ <body class="bg-gradient-to-b from-blue-100 to-purple-100 min-h-screen">
47
+ <div class="container mx-auto px-4 py-8">
48
+ <!-- Header -->
49
+ <header class="text-center mb-8">
50
+ <h1 class="text-4xl font-bold text-purple-600 mb-2">Aprendendo a Ler</h1>
51
+ <p class="text-lg text-gray-600">Um jogo divertido para crianças aprenderem palavras novas!</p>
52
+ </header>
53
+
54
+ <!-- Game Mode Selection -->
55
+ <div class="bg-white rounded-xl shadow-lg p-6 mb-8 max-w-md mx-auto">
56
+ <h2 class="text-2xl font-semibold text-center mb-4 text-blue-600">Escolha como jogar</h2>
57
+ <div class="flex flex-col space-y-4">
58
+ <button id="singlePlayerBtn" class="bg-green-500 hover:bg-green-600 text-white py-3 px-6 rounded-lg text-lg font-medium transition flex items-center justify-center">
59
+ <i class="fas fa-child mr-2"></i> Jogar Sozinho
60
+ </button>
61
+ <button id="vsAiBtn" class="bg-purple-500 hover:bg-purple-600 text-white py-3 px-6 rounded-lg text-lg font-medium transition flex items-center justify-center">
62
+ <i class="fas fa-robot mr-2"></i> Jogar contra a IA
63
+ </button>
64
+ </div>
65
+ </div>
66
+
67
+ <!-- Game Area (initially hidden) -->
68
+ <div id="gameArea" class="hidden">
69
+ <!-- Word Display -->
70
+ <div class="bg-white rounded-xl shadow-lg p-6 mb-6 text-center">
71
+ <h2 id="currentWord" class="text-5xl font-bold text-blue-600 mb-4">PALAVRA</h2>
72
+ <div id="wordImage" class="mx-auto mb-4 w-48 h-48 bg-gray-100 rounded-lg flex items-center justify-center">
73
+ <i class="fas fa-image text-gray-300 text-6xl"></i>
74
+ </div>
75
+ <button id="speakBtn" class="bg-yellow-400 hover:bg-yellow-500 text-white py-2 px-6 rounded-full text-lg font-medium transition">
76
+ <i class="fas fa-volume-up mr-2"></i> Ouvir a Palavra
77
+ </button>
78
+ </div>
79
+
80
+ <!-- Options (for single player) -->
81
+ <div id="singlePlayerOptions" class="hidden grid grid-cols-2 gap-4 mb-8">
82
+ <!-- Options will be filled by JavaScript -->
83
+ </div>
84
+
85
+ <!-- VS AI Section -->
86
+ <div id="vsAiSection" class="hidden">
87
+ <div class="bg-white rounded-xl shadow-lg p-6 mb-6">
88
+ <div class="flex justify-between items-center mb-4">
89
  <div class="flex items-center">
90
+ <div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center mr-3">
91
+ <i class="fas fa-child text-purple-600 text-xl"></i>
92
+ </div>
93
+ <span class="font-medium">Você</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  </div>
95
+ <div class="text-2xl font-bold text-purple-600" id="playerScore">0</div>
96
  </div>
97
 
98
+ <div class="flex justify-between items-center">
99
+ <div class="flex items-center">
100
+ <div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mr-3">
101
+ <i class="fas fa-robot text-blue-600 text-xl"></i>
 
 
 
 
 
 
 
 
 
 
 
102
  </div>
103
+ <span class="font-medium">IA</span>
104
  </div>
105
+ <div class="text-2xl font-bold text-blue-600" id="aiScore">0</div>
106
+ </div>
107
+ </div>
108
+
109
+ <div class="bg-white rounded-xl shadow-lg p-6 mb-6">
110
+ <h3 class="text-xl font-semibold mb-4 text-center">Escreva a palavra que você ouvir:</h3>
111
+ <div class="flex flex-col items-center">
112
+ <input type="text" id="userInput" class="border-2 border-gray-300 rounded-lg px-4 py-3 w-full max-w-md text-center text-xl mb-4" placeholder="Digite aqui">
113
+ <button id="checkAnswerBtn" class="bg-green-500 hover:bg-green-600 text-white py-2 px-6 rounded-lg text-lg font-medium transition">
114
+ Verificar <i class="fas fa-check ml-2"></i>
115
+ </button>
116
  </div>
117
+ </div>
118
+ </div>
119
+
120
+ <!-- Feedback Messages -->
121
+ <div id="feedback" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
122
+ <div class="bg-white rounded-xl p-8 max-w-md mx-4 text-center">
123
+ <div id="feedbackIcon" class="text-6xl mb-4"></div>
124
+ <h3 id="feedbackMessage" class="text-2xl font-bold mb-4"></h3>
125
+ <button id="nextWordBtn" class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-6 rounded-lg text-lg font-medium transition">
126
+ Próxima Palavra <i class="fas fa-arrow-right ml-2"></i>
127
+ </button>
128
  </div>
129
  </div>
130
  </div>
131
+
132
+ <!-- Progress -->
133
+ <div id="progressSection" class="hidden bg-white rounded-xl shadow-lg p-6 mt-8">
134
+ <h3 class="text-xl font-semibold mb-4 text-center">Seu Progresso</h3>
135
+ <div class="flex justify-between items-center mb-2">
136
+ <span class="text-gray-600">Palavras aprendidas:</span>
137
+ <span id="wordsLearned" class="font-bold">0/10</span>
138
+ </div>
139
+ <div class="w-full bg-gray-200 rounded-full h-4">
140
+ <div id="progressBar" class="bg-green-500 h-4 rounded-full" style="width: 0%"></div>
141
+ </div>
 
 
 
 
 
 
 
142
  </div>
143
  </div>
144
 
145
  <script>
146
+ // Game data - CORRIGIDO: Imagens corretas para cada palavra
147
+ const words = [
148
+ { word: "CASA", image: "https://cdn-icons-png.flaticon.com/512/619/619153.png", sound: "casa" },
149
+ { word: "BOLA", image: "https://cdn-icons-png.flaticon.com/512/2826/2826184.png", sound: "bola" }, // Imagem corrigida para bola
150
+ { word: "GATO", image: "https://cdn-icons-png.flaticon.com/512/616/616408.png", sound: "gato" },
151
+ { word: "SOL", image: "https://cdn-icons-png.flaticon.com/512/172/172818.png", sound: "sol" },
152
+ { word: "ÁRVORE", image: "https://cdn-icons-png.flaticon.com/512/2824/2824906.png", sound: "arvore" },
153
+ { word: "FLOR", image: "https://cdn-icons-png.flaticon.com/512/2824/2824977.png", sound: "flor" },
154
+ { word: "LIVRO", image: "https://cdn-icons-png.flaticon.com/512/1573/1573711.png", sound: "livro" },
155
+ { word: "ÁGUA", image: "https://cdn-icons-png.flaticon.com/512/2824/2824996.png", sound: "agua" },
156
+ { word: "PÃO", image: "https://cdn-icons-png.flaticon.com/512/2276/2276931.png", sound: "pao" },
157
+ { word: "LUZ", image: "https://cdn-icons-png.flaticon.com/512/2489/2489076.png", sound: "luz" }
158
+ ];
159
+
160
+ // Game state
161
+ let currentWordIndex = 0;
162
+ let correctAnswers = 0;
163
+ let playerScore = 0;
164
+ let aiScore = 0;
165
+ let gameMode = null;
166
+ const speechSynthesis = window.speechSynthesis;
167
+
168
+ // DOM elements
169
+ const gameArea = document.getElementById('gameArea');
170
+ const singlePlayerOptions = document.getElementById('singlePlayerOptions');
171
+ const vsAiSection = document.getElementById('vsAiSection');
172
+ const currentWordElement = document.getElementById('currentWord');
173
+ const wordImageElement = document.getElementById('wordImage');
174
+ const speakBtn = document.getElementById('speakBtn');
175
+ const feedback = document.getElementById('feedback');
176
+ const feedbackIcon = document.getElementById('feedbackIcon');
177
+ const feedbackMessage = document.getElementById('feedbackMessage');
178
+ const nextWordBtn = document.getElementById('nextWordBtn');
179
+ const progressSection = document.getElementById('progressSection');
180
+ const wordsLearned = document.getElementById('wordsLearned');
181
+ const progressBar = document.getElementById('progressBar');
182
+ const playerScoreElement = document.getElementById('playerScore');
183
+ const aiScoreElement = document.getElementById('aiScore');
184
+ const userInput = document.getElementById('userInput');
185
+ const checkAnswerBtn = document.getElementById('checkAnswerBtn');
186
+
187
+ // Mode selection buttons
188
+ document.getElementById('singlePlayerBtn').addEventListener('click', () => {
189
+ gameMode = 'single';
190
+ startGame();
191
+ });
192
+
193
+ document.getElementById('vsAiBtn').addEventListener('click', () => {
194
+ gameMode = 'ai';
195
+ startGame();
196
+ });
197
+
198
+ // Start the game
199
+ function startGame() {
200
+ gameArea.classList.remove('hidden');
201
+ progressSection.classList.remove('hidden');
202
+
203
+ if (gameMode === 'single') {
204
+ singlePlayerOptions.classList.remove('hidden');
205
+ vsAiSection.classList.add('hidden');
206
+ loadWordWithOptions();
207
+ } else {
208
+ singlePlayerOptions.classList.add('hidden');
209
+ vsAiSection.classList.remove('hidden');
210
+ loadWordForAI();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
+ }
213
+
214
+ // Load word with multiple choice options (single player)
215
+ function loadWordWithOptions() {
216
+ const currentWord = words[currentWordIndex];
217
+ currentWordElement.textContent = currentWord.word;
218
+ wordImageElement.style.backgroundImage = `url(${currentWord.image})`;
219
+ wordImageElement.innerHTML = '';
220
+
221
+ // Generate options (1 correct + 3 random incorrect)
222
+ const options = [currentWord.word];
223
+ while (options.length < 4) {
224
+ const randomWord = words[Math.floor(Math.random() * words.length)].word;
225
+ if (!options.includes(randomWord)) {
226
+ options.push(randomWord);
 
 
 
 
 
 
 
227
  }
228
  }
229
+
230
+ // Shuffle options
231
+ options.sort(() => Math.random() - 0.5);
232
+
233
+ // Clear previous options
234
+ singlePlayerOptions.innerHTML = '';
235
+
236
+ // Create option buttons
237
+ options.forEach(option => {
238
+ const optionBtn = document.createElement('button');
239
+ optionBtn.className = 'word-card bg-blue-100 hover:bg-blue-200 text-blue-800 py-8 px-4 rounded-xl text-2xl font-bold transition';
240
+ optionBtn.textContent = option;
241
+ optionBtn.addEventListener('click', () => checkAnswer(option === currentWord.word));
242
+ singlePlayerOptions.appendChild(optionBtn);
243
+ });
244
+ }
245
+
246
+ // Load word for AI mode
247
+ function loadWordForAI() {
248
+ const currentWord = words[currentWordIndex];
249
+ currentWordElement.textContent = '?';
250
+ wordImageElement.style.backgroundImage = 'none';
251
+ wordImageElement.innerHTML = '<i class="fas fa-question text-gray-300 text-6xl"></i>';
252
+ userInput.value = '';
253
+
254
+ // Speak the word after a short delay
255
+ setTimeout(() => {
256
+ speakWord(currentWord.word);
257
+ }, 500);
258
+ }
259
+
260
+ // Speak the word
261
+ function speakWord(word) {
262
+ if (speechSynthesis) {
263
+ const utterance = new SpeechSynthesisUtterance(word);
264
+ utterance.lang = 'pt-BR';
265
+ utterance.rate = 0.8;
266
+ speechSynthesis.speak(utterance);
267
  }
268
+ }
269
+
270
+ // Check the answer
271
+ function checkAnswer(isCorrect) {
272
+ if (isCorrect) {
273
+ correctAnswers++;
274
+ playerScore++;
275
+ if (gameMode === 'single') {
276
+ showFeedback(true, 'Parabéns! Você acertou!');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  } else {
278
+ playerScoreElement.textContent = playerScore;
279
+ showFeedback(true, `Correto! A palavra era "${words[currentWordIndex].word}"`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  }
281
+ } else {
282
+ if (gameMode === 'ai') {
283
+ aiScore++;
284
+ aiScoreElement.textContent = aiScore;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  }
286
+ showFeedback(false, `Ops! A palavra correta era "${words[currentWordIndex].word}"`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
+
289
+ // Update progress
290
+ updateProgress();
291
+ }
292
+
293
+ // Show feedback
294
+ function showFeedback(isCorrect, message) {
295
+ feedback.classList.remove('hidden');
296
+
297
+ if (isCorrect) {
298
+ feedbackIcon.innerHTML = '<i class="fas fa-check-circle text-green-500"></i>';
299
+ feedbackMessage.textContent = message;
300
+ feedbackMessage.className = 'text-2xl font-bold mb-4 text-green-600';
301
+ createConfetti();
302
+ } else {
303
+ feedbackIcon.innerHTML = '<i class="fas fa-times-circle text-red-500"></i>';
304
+ feedbackMessage.textContent = message;
305
+ feedbackMessage.className = 'text-2xl font-bold mb-4 text-red-600';
306
  }
307
+ }
308
+
309
+ // Create confetti effect
310
+ function createConfetti() {
311
+ for (let i = 0; i < 50; i++) {
312
+ const confetti = document.createElement('div');
313
+ confetti.className = 'confetti';
314
+ confetti.style.left = Math.random() * 100 + 'vw';
315
+ confetti.style.backgroundColor = `hsl(${Math.random() * 360}, 100%, 50%)`;
316
+ confetti.style.width = Math.random() * 10 + 5 + 'px';
317
+ confetti.style.height = confetti.style.width;
318
+ document.body.appendChild(confetti);
319
+
320
+ // Remove confetti after animation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  setTimeout(() => {
322
+ confetti.remove();
323
+ }, 3000);
324
  }
325
+ }
326
+
327
+ // Update progress
328
+ function updateProgress() {
329
+ const progress = (correctAnswers / words.length) * 100;
330
+ wordsLearned.textContent = `${correctAnswers}/${words.length}`;
331
+ progressBar.style.width = `${progress}%`;
332
+ }
333
+
334
+ // Next word button
335
+ nextWordBtn.addEventListener('click', () => {
336
+ feedback.classList.add('hidden');
337
+ currentWordIndex++;
338
+
339
+ if (currentWordIndex < words.length) {
340
+ if (gameMode === 'single') {
341
+ loadWordWithOptions();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  } else {
343
+ loadWordForAI();
344
+ }
345
+ } else {
346
+ // Game over
347
+ gameArea.innerHTML = `
348
+ <div class="bg-white rounded-xl shadow-lg p-8 text-center">
349
+ <div class="text-6xl text-green-500 mb-4">
350
+ <i class="fas fa-trophy"></i>
351
+ </div>
352
+ <h2 class="text-3xl font-bold text-green-600 mb-4">Parabéns!</h2>
353
+ <p class="text-xl mb-6">Você completou todas as palavras!</p>
354
+ <p class="text-2xl font-bold mb-6">Pontuação: ${playerScore}/${words.length}</p>
355
+ ${gameMode === 'ai' ? `<p class="text-xl mb-6">IA: ${aiScore} pontos</p>` : ''}
356
+ <button onclick="location.reload()" class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-6 rounded-lg text-lg font-medium transition">
357
+ Jogar Novamente <i class="fas fa-redo ml-2"></i>
358
+ </button>
359
+ </div>
360
+ `;
361
+ }
362
+ });
363
+
364
+ // Speak button
365
+ speakBtn.addEventListener('click', () => {
366
+ speakWord(words[currentWordIndex].word);
367
+ });
368
+
369
+ // Check answer button (AI mode)
370
+ checkAnswerBtn.addEventListener('click', () => {
371
+ const userAnswer = userInput.value.trim().toUpperCase();
372
+ checkAnswer(userAnswer === words[currentWordIndex].word);
373
+ });
374
+
375
+ // Allow pressing Enter to submit in AI mode
376
+ userInput.addEventListener('keypress', (e) => {
377
+ if (e.key === 'Enter') {
378
+ const userAnswer = userInput.value.trim().toUpperCase();
379
+ checkAnswer(userAnswer === words[currentWordIndex].word);
380
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  });
382
  </script>
383
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Wasghington/kakttus-ai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
prompts.txt CHANGED
@@ -1,2 +1,5 @@
1
  monte um jogo de xadrez
2
- coloque um opção para jogar com a ia
 
 
 
 
1
  monte um jogo de xadrez
2
+ coloque um opção para jogar com a ia
3
+ crie o jogo para criança aprender a ler
4
+ a imagem não está aparecendo completa, corrija, por favor
5
+ agora aparece uma cenoura e a palavra é bola, corrija