Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vitor Carlet | Lucas Magalhães | melhorias e funcionalidades adicionais em comparação ao primeiro código. #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 194 additions & 82 deletions puzzle8.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>8-Puzzle</title>
<style>
body {
Expand Down Expand Up @@ -42,6 +41,7 @@
cursor: pointer;
user-select: none;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
transition: background-color 0.3s;
}

.tile.empty {
Expand All @@ -50,40 +50,28 @@
box-shadow: none;
}

.board-state {
margin-top: 20px;
font-size: 18px;
font-weight: bold;
color: #333;
}

.inversions {
.shuffle-button, .solve-button {
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;
background-color: #B0C4DE;
border: none;
border-radius: 5px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
transition: background-color 0.3s;
margin-right: 5px;
}

.shuffle-button:hover {
.shuffle-button:hover, .solve-button:hover {
background-color: #45a049;
color: white;
}

.move-count {
.board-state, .inversions, .move-count, .solution-info {
margin-top: 10px;
font-size: 16px;
color: #555;
color: #333;
}
</style>
</head>
Expand All @@ -101,7 +89,10 @@
<div class="tile empty" data-value="0"></div>
</div>
</div>
<button class="shuffle-button" id="shuffleButton">Sortear Estado Inicial</button>
<button class="shuffle-button" id="easyButton">Fácil</button>
<button class="shuffle-button" id="mediumButton">Médio</button>
<button class="shuffle-button" id="hardButton">Difícil</button>
<button class="solve-button" id="solveButton">Resolver Automaticamente</button>
<div class="board-state" id="boardState">
Estado atual: [1, 2, 3, 4, 5, 6, 7, 8, 0]
</div>
Expand All @@ -111,20 +102,25 @@
<div class="move-count" id="moveCount">
Número de jogadas: 0
</div>
<div class="solution-info" id="solutionInfo">
Jogada atual: 0 / Total: 0
</div>
<script>
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 solutionInfoDisplay = document.getElementById('solutionInfo');
const easyButton = document.getElementById('easyButton');
const mediumButton = document.getElementById('mediumButton');
const hardButton = document.getElementById('hardButton');
const solveButton = document.getElementById('solveButton');

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 emptyTileIndex = boardState.indexOf(0);

function calculateInversions(state) {
let inversions = 0;
Expand All @@ -139,65 +135,26 @@
}

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}`;
}

function checkGoalState() {
if (boardState.join(',') === goalState.join(',')) {
alert(`Você resolveu o puzzle em ${moveCount} jogadas!`);
}
}

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
function updateTiles() {
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');
}
});

// Atualiza as exibições
updateDisplay();
}

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)
function canMove(tileIndex) {
const validMoves = {
0: [1, 3],
1: [0, 2, 4],
Expand All @@ -209,29 +166,184 @@
7: [4, 6, 8],
8: [5, 7]
};
return validMoves[emptyTileIndex].includes(tileIndex);
}

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]];
function moveTile(tileIndex) {
[boardState[emptyTileIndex], boardState[tileIndex]] = [boardState[tileIndex], boardState[emptyTileIndex]];
emptyTileIndex = tileIndex;
moveCount++;
updateTiles();
updateDisplay();
checkWin();
}

// Atualiza o conteúdo visual
tile.textContent = boardState[tileIndex] === 0 ? "" : boardState[tileIndex];
emptyTile.textContent = boardState[emptyTileIndex] === 0 ? "" : boardState[emptyTileIndex];
function checkWin() {
if (boardState.join(',') === goalState.join(',')) {
alert('Parabéns! Você resolveu o quebra-cabeça!');
}
}

// Troca as classes para manter a peça vazia correta
tile.classList.add('empty');
emptyTile.classList.remove('empty');
tiles.forEach((tile, index) => {
tile.addEventListener('click', () => {
if (canMove(index)) {
moveTile(index);
}
});
});

function shuffleBoard(moves) {
boardState = goalState.slice();
emptyTileIndex = boardState.indexOf(0);

for (let i = 0; i < moves; i++) {
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]
};

const possibleMoves = validMoves[emptyTileIndex];
const randomMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
[boardState[emptyTileIndex], boardState[randomMove]] = [boardState[randomMove], boardState[emptyTileIndex]];
emptyTileIndex = randomMove;
}

moveCount = 0;
updateTiles();
updateDisplay();
updateSolutionInfo(0, 0);
}

easyButton.addEventListener('click', () => shuffleBoard(10));
mediumButton.addEventListener('click', () => shuffleBoard(20));
hardButton.addEventListener('click', () => shuffleBoard(30));

solveButton.addEventListener('click', () => {
const solution = solvePuzzleAStar(boardState);
if (solution) {
alert("Solução encontrada! Executando os movimentos...");
animateSolution(solution);
} else {
alert("Não foi possível encontrar uma solução.");
}
});

function animateSolution(solution) {
let step = 0;
const totalSteps = solution.length;
const interval = setInterval(() => {
if (step < totalSteps) {
boardState = solution[step];
emptyTileIndex = boardState.indexOf(0);
updateTiles();
updateDisplay();
step++;
updateSolutionInfo(step, totalSteps);
} else {
clearInterval(interval);
alert("Puzzle resolvido automaticamente!");
}
}, 500);
}

function updateSolutionInfo(currentStep, totalSteps) {
solutionInfoDisplay.textContent = `Jogada atual: ${currentStep} / Total: ${totalSteps}`;
}

// Incrementa o contador de jogadas
moveCount++;
function solvePuzzleAStar(initialState) {
const goalState = [1, 2, 3, 4, 5, 6, 7, 8, 0];

function clone(state) { return state.slice(); }

function getNeighbors(state) {
const emptyIndex = state.indexOf(0);
const neighbors = [];
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]
};
for (const move of validMoves[emptyIndex]) {
const newState = clone(state);
[newState[emptyIndex], newState[move]] = [newState[move], newState[emptyIndex]];
neighbors.push(newState);
}
return neighbors;
}

class Node {
constructor(state, parent = null, g = 0, h = calculateManhattanDistance(state)) {
this.state = state;
this.parent = parent;
this.g = g;
this.h = h;
this.f = g + h;
}
}

// Atualiza as exibições
updateDisplay();
const openList = [];
const closedSet = new Set();
openList.push(new Node(initialState));

while (openList.length > 0) {
openList.sort((a, b) => a.f - b.f);
const currentNode = openList.shift();

if (currentNode.state.join(',') === goalState.join(',')) {
const solution = [];
let node = currentNode;
while (node !== null) {
solution.unshift(node.state);
node = node.parent;
}
return solution;
}

// Verifica se o estado meta foi alcançado
checkGoalState();
closedSet.add(currentNode.state.join(','));

const neighbors = getNeighbors(currentNode.state);
for (const neighborState of neighbors) {
if (closedSet.has(neighborState.join(','))) continue;
const g = currentNode.g + 1;
const h = calculateManhattanDistance(neighborState);
const neighborNode = new Node(neighborState, currentNode, g, h);
openList.push(neighborNode);
}
}

return null;
}

function calculateManhattanDistance(state) {
let distance = 0;
state.forEach((value, index) => {
if (value !== 0) {
const goalIndex = goalState.indexOf(value);
const currentRow = Math.floor(index / 3);
const currentCol = index % 3;
const goalRow = Math.floor(goalIndex / 3);
const goalCol = goalIndex % 3;
distance += Math.abs(currentRow - goalRow) + Math.abs(currentCol - goalCol);
}
});
return distance;
}

// Atualize a exibição inicial
updateDisplay();
});
</script>
</body>
Expand Down
Loading