diff --git a/jogo/puzzle8.html b/jogo/puzzle8.html new file mode 100644 index 0000000..dac40cd --- /dev/null +++ b/jogo/puzzle8.html @@ -0,0 +1,66 @@ + + + + + + + + 8-Puzzle + + + + +
+
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
+
+
+ +
+ Estado atual: [1, 2, 3, 4, 5, 6, 7, 8, 0] +
+
+ + + + +
+ + + +
+ Inversões: 0 (Paridade: par) +
+ +
+
+ Número de jogadas: 0 +
+
TIME: 0m 00s
+
+ +
+ Distância Manhattan: 0 +
+
+ Peças fora do lugar: 0 +
+
+ + + +
+
+ + + + + \ No newline at end of file diff --git a/jogo/script.js b/jogo/script.js new file mode 100644 index 0000000..3ae9a71 --- /dev/null +++ b/jogo/script.js @@ -0,0 +1,313 @@ +let timerInterval; // Variável que vai armazenar o intervalo do tempo +let startTime; // Tempo inicial quando o jogo começa +let timeLimit; // Limite de tempo escolhido pelo jogador (em segundos) +let remainingTime; // Tempo restante para o jogo +let timeElapsed = 0; + +document.addEventListener("DOMContentLoaded", () => { + const tiles = document.querySelectorAll(".tile"); + const grid = document.querySelector(".grid"); + const boardStateDisplay = document.getElementById("boardState"); + const inversionsDisplay = document.getElementById("inversionsCount"); + const moveCountDisplay = document.getElementById("moveCount"); + const shuffleButton = document.getElementById("shuffleButton"); + const timerDisplay = document.getElementById("gameTimer"); + const timeLimitInput = document.getElementById("timeLimit"); + const startGameButton = document.getElementById("startGameButton"); + const pauseResumeButton = document.getElementById("pauseResumeButton"); + + + startGameButton.addEventListener("click", startGame); + + const goalState = [1, 2, 3, 4, 5, 6, 7, 8, 0]; + let moveCount = 0; + + // Inicializa o estado do tabuleiro + let boardState = Array.from(tiles).map((tile) => + parseInt(tile.dataset.value) + ); + + let isPaused = false; // Variável para controlar se o jogo está pausado + // Event listener para o botão de pausa/retomar + pauseResumeButton.addEventListener("click", () => { + if (isPaused) { + resumeGame(); + } else { + pauseGame(); + } + }); + + function pauseGame() { + clearInterval(timerInterval); // Para o temporizador + isPaused = true; + pauseResumeButton.textContent = "Retomar"; // Altera o texto do botão para "Retomar" + grid.classList.add("paused"); // Adiciona uma classe para indicar que o jogo está pausado (opcional) + } + + function resumeGame() { + // Calcula o novo tempo de início com base no tempo restante (se houver limite de tempo) + startTime = Date.now() - timeElapsed * 1000; + + // Reinicia o temporizador + startTimer(); + + isPaused = false; + pauseResumeButton.textContent = "Pausar"; // Altera o texto do botão para "Pausar" + grid.classList.remove("paused"); // Remove a classe de pausa (opcional) + } + + function startTimer() { + timerInterval = setInterval(() => { + if (isPaused) return; // Verifica se o jogo está pausado + + // Calcula o tempo decorrido + timeElapsed = Math.floor((Date.now() - startTime) / 1000); + + if (timeLimit) { + remainingTime = timeLimit - timeElapsed; + + if (remainingTime <= 0) { + remainingTime = 0; + clearInterval(timerInterval); + timerDisplay.textContent = "TIME: 0s"; + checkGoalState(true); + stopTimer(); + return; + } + + // Formata o tempo em minutos e segundos + const minutes = Math.floor(remainingTime / 60); + const seconds = remainingTime % 60; + timerDisplay.textContent = `TIME: ${minutes}m ${ + seconds < 10 ? "0" : "" + }${seconds}s`; + } else { + // Se não houver limite de tempo, mostra o tempo decorrido corretamente + const minutes = Math.floor(timeElapsed / 60); + const seconds = timeElapsed % 60; + timerDisplay.textContent = `TIME: ${minutes}m ${ + seconds < 10 ? "0" : "" + }${seconds}s`; + } + }, 1000); + } + + function stopTimer() { + clearInterval(timerInterval); + } + + function resetTimer() { + stopTimer(); + timeElapsed = 0; + timerDisplay.textContent = "Tempo: 0s"; + } + + function startGame() { + const selectedTimeLimit = timeLimitInput.value.trim(); + if (selectedTimeLimit && parseInt(selectedTimeLimit) > 0) { + timeLimit = parseInt(selectedTimeLimit) * 60; // Limite de tempo em segundos + } else { + timeLimit = null; // Sem limite de tempo + } + // Inicializa o tempo decorrido e o tempo inicial + timeElapsed = 0; + startTime = Date.now(); + remainingTime = timeLimit; + moveCount = 0; + + //shuffleBoard(); + + if (timeLimit !== null) { + startTimer(); // Inicia com o limite de tempo + } else { + resetTimer(); // Sem limite, reseta e começa sem temporizador + startTimer(); // Começa apenas mostrando o tempo decorrido + } + updateDisplay(); // Atualiza a exibição após iniciar o jogo + } + + document.getElementById("calculateParityButton").addEventListener("click", () => { + const input = document.getElementById("customBoard").value.split(",").map(Number); + + // Verifique se o input tem exatamente 9 valores e contém números de 0 a 8 + if ( + input.length !== 9 ||!input.every((val) => val >= 0 && val <= 8 && + input.indexOf(val) === input.lastIndexOf(val) + ) + ) { + document.getElementById("customBoardResult").textContent = + "Por favor, insira um tabuleiro válido (números de 0 a 8 sem repetir)."; + return; + } + + const inversions = calculateInversions(input); + const parity = inversions % 2 === 0 ? "par" : "ímpar"; + + document.getElementById( + "customBoardResult" + ).textContent = `Inversões: ${inversions}, Paridade: ${parity}`; + }); + + function calculateInversions(state) { + let inversions = 0; + for (let i = 0; i < state.length - 1; i++) { + for (let j = i + 1; j < state.length; j++) { + if (state[i] > state[j] && state[i] !== 0 && state[j] !== 0) { + inversions++; + } + } + } + return inversions; + } + + function updateDisplay() { + // Exibe o estado do tabuleiro na página + boardStateDisplay.textContent = `Estado atual: [${boardState.join(", ")}]`; + + // Calcula e exibe o número de inversões e a paridade + const inversions = calculateInversions(boardState); + const parity = inversions % 2 === 0 ? "par" : "ímpar"; + inversionsDisplay.textContent = `Inversões: ${inversions} (Paridade: ${parity})`; + + // Exibe o número de jogadas + moveCountDisplay.textContent = `Número de jogadas: ${moveCount}`; + + // Calcula e exibe a distância Manhattan + const manhattanDistance = calculateManhattan(boardState); + document.getElementById("manhattanDistance" ).textContent = `Distância Manhattan: ${manhattanDistance}`; + + // Calcula e exibe o número de peças fora do lugar + const misplacedCount = countMisplacedTiles(boardState, goalState);document.getElementById( + "misplacedCount" + ).textContent = `Peças fora do lugar: ${misplacedCount}`; + } + + function shuffleBoard() { + // Embaralha o estado do tabuleiro + do { + boardState = boardState.sort(() => Math.random() - 0.5); + } while (calculateInversions(boardState) % 2 !== 0); // Garante que o estado seja resolvível + + moveCount = 0; // Reseta o contador de jogadas + + // Atualiza o conteúdo visual + tiles.forEach((tile, index) => { + tile.textContent = boardState[index] === 0 ? "" : boardState[index]; + tile.dataset.value = boardState[index]; + + if (boardState[index] === 0) { + tile.classList.add("empty"); + } else { + tile.classList.remove("empty"); + } + }); + resetTimer(); // Reseta o timer ao embaralhar + updateDisplay(); // Atualiza as exibições + } + + updateDisplay(); // Atualiza a exibição inicialmente + + grid.addEventListener("click", (e) => { + const tile = e.target; + if (tile.classList.contains("tile")) { + moveTile(tile); + } + }); + + shuffleButton.addEventListener("click", shuffleBoard); + + function moveTile(tile) { + const emptyTile = document.querySelector(".tile.empty"); + const tileIndex = Array.from(tiles).indexOf(tile); + const emptyTileIndex = Array.from(tiles).indexOf(emptyTile); + + // Define movimentos válidos (esquerda, direita, cima, baixo) + const validMoves = { + 0: [1, 3], + 1: [0, 2, 4], + 2: [1, 5], + 3: [0, 4, 6], + 4: [1, 3, 5, 7], + 5: [2, 4, 8], + 6: [3, 7], + 7: [4, 6, 8], + 8: [5, 7], + }; + + if (validMoves[emptyTileIndex].includes(tileIndex)) { + // Troca de posição entre a peça clicada e a peça vazia + [boardState[tileIndex], boardState[emptyTileIndex]] = [ + boardState[emptyTileIndex], + boardState[tileIndex], + ]; + + // Atualiza o conteúdo visual + tile.textContent = + boardState[tileIndex] === 0 ? "" : boardState[tileIndex]; + emptyTile.textContent = + boardState[emptyTileIndex] === 0 ? "" : boardState[emptyTileIndex]; + + // Troca as classes para manter a peça vazia correta + tile.classList.add("empty"); + emptyTile.classList.remove("empty"); + + // Incrementa o contador de jogadas + moveCount++; + + // Atualiza as exibições + updateDisplay(); + + // Verifica se o estado atual do tabuleiro é o estado de objetivo + checkGoalState(); + } + } + + function checkGoalState(timeOver = false) { + if (JSON.stringify(boardState) === JSON.stringify(goalState)) { + stopTimer(); + + // Calcula o tempo formatado + const minutes = Math.floor(timeElapsed / 60); + const seconds = timeElapsed % 60; + const formattedTime = `${minutes}m ${seconds < 10 ? "0" : ""}${seconds}s`; + + // Exibe a mensagem com o número de jogadas e o tempo gasto + alert( + `Parabéns! Você completou o puzzle em ${moveCount} jogadas e ${formattedTime}!` + ); + } else if (timeOver) { + alert("O tempo acabou! Você não conseguiu resolver o puzzle a tempo."); + } + } + + function calculateManhattan(state) { + let distance = 0; + const goalPositions = [ + [0, 0],[0, 1],[0, 2], // Posições corretas para 1, 2, 3 + [1, 0],[1, 1],[1, 2], // Posições corretas para 4, 5, 6 + [2, 0], [2, 1], [2, 2], // Posições corretas para 7, 8, 0 + ]; + + state.forEach((value, index) => { + if (value !== 0) { + const currentRow = Math.floor(index / 3); + const currentCol = index % 3; + const goalRow = goalPositions[value - 1][0]; + const goalCol = goalPositions[value - 1][1]; + distance += + Math.abs(currentRow - goalRow) + Math.abs(currentCol - goalCol); + } + }); + return distance; + } + + function countMisplacedTiles(state, goal) { + let count = 0; + for (let i = 0; i < state.length; i++) { + if (state[i] !== goal[i] && state[i] !== 0) { + count++; + } + } + return count; + } +}); diff --git a/jogo/styles.css b/jogo/styles.css new file mode 100644 index 0000000..f63d0aa --- /dev/null +++ b/jogo/styles.css @@ -0,0 +1,173 @@ +body { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + font-family: Arial, sans-serif; + background-color: #f0f0f0; +} + +.container { + display: flex; + justify-content: center; + align-items: center; + padding: 10px; +} + +.grid { + display: grid; + grid-template-columns: repeat(3, 100px); + grid-template-rows: repeat(3, 100px); + gap: 5px; +} + +.tile { + display: flex; + justify-content: center; + align-items: center; + width: 100px; + height: 100px; + background-color: #2196f3; + color: white; + font-size: 24px; + cursor: pointer; + user-select: none; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); +} + +.tile.empty { + background-color: #f0f0f0; + cursor: default; + box-shadow: none; +} + +.board-state { + margin-top: 20px; + font-size: 18px; + font-weight: bold; + color: #333; +} + +.inversions { + margin-top: 10px; + font-size: 16px; + color: #555; +} + +.shuffle-button { + margin-top: 20px; + padding: 10px 20px; + font-size: 16px; + cursor: pointer; + background-color: #4CAF50; + color: white; + border: none; + border-radius: 5px; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); + transition: background-color 0.3s; +} + +.shuffle-button:hover { + background-color: #45a049; +} + +.move-count { + margin-top: 10px; + font-size: 16px; + color: #555; +} + +.timer { + margin-top: 10px; + font-size: 16px; + color: #555; +} + +#calculateParityButton { + padding: 10px 20px; + font-size: 16px; + font-weight: bold; + color: white; + background-color: #4CAF50; + border: none; + border-radius: 5px; + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.2); + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; +} + +#calculateParityButton:hover { + background-color: #45a049; +} + +#calculateParityButton:active { + transform: scale(0.98); + background-color: #3e8e41; +} + +#calculateParityButton:focus { + outline: none; + box-shadow: 0 0 10px rgba(72, 184, 72, 0.8); +} +/* Alinha os botões lado a lado e adiciona espaçamento */ +div>button { + margin-right: 10px; + /* Ajuste o valor conforme necessário */ +} + +div { + display: flex; + align-items: center; +} + +button { + background-color: #FF4C61; + /* Cor dos botões */ + border: none; + color: white; + padding: 5px 10px; + text-align: center; + font-size: 16px; + cursor: pointer; + border-radius: 5px; +} + +button:hover { + background-color: #ff6878; + /* Efeito ao passar o mouse */ +} + +#gameTimer, +#moveCount { + background-color: #2196f3; + color: white; + padding: 5px; + border-radius: 5px; + font-size: 18px; +} + +#gameTimer { + margin-left: 5px; +} + +#moveCount { + margin-right: 10px; +} +.move-time-container { + display: flex; + align-items: center; +} + +.move-count { + margin-right: 10px; + /* Espaçamento entre o número de jogadas e o temporizador */ +} +div>label, +div>input, +div>button { + margin-right: 10px; + /* Ajuste o valor conforme necessário */ +} +