So here is my javascript part of Sliding puzzle project. It doesn’t seem to be checking if tiles are adjacent to empty tile before swapping. I changed code several times and now can’t see the problem. I’d appreciate any help.
let count = 0;
const body = document.body;
const puzzleOverlay = document.getElementById('puzzle-overlay'); //Create overlay when puzzle modal is open
const menuOverlay = document.getElementById('menu-overlay'); //Create overlay when menu modal is open
const modal = document.getElementById('modal'); //Get menu modal
const menuButton = document.getElementById('menu-button'); //Get the button to open menu modal
const close = document.getElementsByClassName('close-button')[0]; //Get the element that closes modal
const imgModal = document.getElementById('imgModal'); //Get complete puzzle modal
const imgButton = document.getElementById('show-img'); //Get the button to open image modal
const newGame = document.getElementById('new-game'); //Get a new game button
let movesCounter = document.querySelector('#moves'); //Get moves counter button
//Initial puzzle array
const initialPuzzle = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 0] //0 for the empty tile
];
//Check if puzzle is solved
function isPuzzleSolved() {
let tileNumbers = [];
//Collect the numbers of tiles
for (let row = 1; row <= 3; row++) {
for (let column = 1; column <= 3; column++) {
const tile = document.getElementById('tile' + row + column);
tileNumbers.push(parseInt(tile.textContent));
}
}
//Check if tiles are in sequence
for (let i = 0; i < tileNumbers.length - 1; i++) {
if (tileNumbers[i] !== i + 1) {
return false;
}
}
//The last tile is an empty one
return tileNumbers[tileNumbers - 1] === '9';
}
//Change puzzle to array
function isSolvable(puzzle) {
const flatPuzzle = puzzle.flat();
const size = flatPuzzle.length;
let inversions = 0;
for (let i = 0; i < size - 1; i++) {
for (let j = 0; j < size; j++) {
if (flatPuzzle[i] !== 0 && flatPuzzle[j] !== 0 && flatPuzzle[i] > flatPuzzle[j]) {
inversions++;
}
}
}
return inversions % 2 === 0;
}
//Atach event listeners to tiles
document.addEventListener('DOMContentLoaded', function() {
newGame.addEventListener('click', function() {
shufflePuzzle();
count = 0;
movesCounter.innerHTML = 'Moves: ' + count;
});
for (let row = 1; row <= 3; row++) {
for (let column = 1; column <= 3; column++) {
const tile = document.getElementById('tile' + row + column);
tile.addEventListener('click', (function(currentRow, currentColumn) {
return function() {
chooseTile(currentRow, currentColumn);
moveTiles('tile' + currentRow + currentColumn, 'tile33');
//Check if puzzle is solved
if (isPuzzleSolved()) {
alert('Congratulations! You solved the puzzle!');
}
};
})(row, column));
}
}
});
function moveTiles(tile1, tile2) {
const tile1Element = document.getElementById(tile1);
const tile2Element = document.getElementById(tile2);
// Swap the src attribute of the two tiles
const tempSrc = tile1Element.src;
tile1Element.src = tile2Element.src;
tile2Element.src = tempSrc;
// Swap data attributes to update tile positions
[tile1Element.dataset.row, tile2Element.dataset.row] = [tile2Element.dataset.row, tile1Element.dataset.row];
[tile1Element.dataset.column, tile2Element.dataset.column] = [tile2Element.dataset.column, tile1Element.dataset.column];
//Count moves
count++;
movesCounter.innerHTML = 'Moves: ' + count;
}
//Nested loops for each cell of the table
function shufflePuzzle() {
if (!isSolvable(initialPuzzle)) {
alert('Puzzle is not solvable! Please start new game!');
return;
}
document.getElementById('moves').innerHTML = 'Moves: 0';
for (let row = 1; row <= 3; row++) {
for (let column = 1; column <= 3; column++) {
let secondRow = Math.floor(Math.random() * 3 + 1);
let secondCol = Math.floor(Math.random() * 3 + 1);
if (row !== secondRow || column !== secondCol) {
const tile1 = "tile" + row + column;
const tile2 = "tile" + secondRow + secondCol;
moveTiles(tile1, tile2);
}
}
}
}
newGame.addEventListener('click', shufflePuzzle);
function chooseTile(row, column) {
const tile = document.getElementById("tile" + row + column);
const tileClass = tile.className;
// Get the positions of the adjacent tiles
const leftTile = document.getElementById("tile" + row + (column - 1));
const rightTile = document.getElementById("tile" + row + (column + 1));
const topTile = document.getElementById("tile" + (row - 1) + column);
const bottomTile = document.getElementById("tile" + (row + 1) + column);
// Check if any adjacent tile is the empty tile
const isLeftEmpty = leftTile && leftTile.className.includes("tile9");
const isRightEmpty = rightTile && rightTile.className.includes("tile9");
const isTopEmpty = topTile && topTile.className.includes("tile9");
const isBottomEmpty = bottomTile && bottomTile.className.includes("tile9");
// Check if the current tile can be moved
if (tileClass.includes("tile9") && (isLeftEmpty || isRightEmpty || isTopEmpty || isBottomEmpty)) {
if (isLeftEmpty) {
moveTiles("tile" + row + column, "tile" + row + (column - 1));
} else if (isRightEmpty) {
moveTiles("tile" + row + column, "tile" + row + (column + 1));
} else if (isTopEmpty) {
moveTiles("tile" + row + column, "tile" + (row - 1) + column);
} else if (isBottomEmpty) {
moveTiles("tile" + row + column, "tile" + (row + 1) + column);
}
} else {
console.log(`No adjacent empty tile found for (${row}, ${column})`);
}
}
//Open menu modal if button is clicked
menuButton.onclick = function() {
modal.style.display = 'block';
// Disable the body
body.style.overflow = 'hidden';
menuOverlay.style.display = 'block';
};
//Close menu modal when close (x) element is clicked
close.onclick = function(event) {
modal.style.display = 'none';
// Enable the body
body.style.overflow = 'auto';
menuOverlay.style.display = 'none';
};
//Open image modal if button is clicked
imgButton.onclick = function() {
imgModal.style.display = 'block';
// Disable the body
body.style.overflow = 'hidden';
puzzleOverlay.style.display = 'block';
};
//Close image modal when user clicks on image
imgModal.onclick = function(event) {
imgModal.style.display = 'none';
// Enable the body
body.style.overflow = 'auto';
puzzleOverlay.style.display = 'none';
};
movesCounter.addEventListener('click', function() {
count += 1;
movesCounter.innerHTML = 'Moves: ' + count;
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Sliding 3x3 puzzle game with objective is to rearrange the tiles to make a complete image in as little moves as possible." />
<link rel="stylesheet" href="assets/css/style.css" />
<title>Sliding Puzzle</title>
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<div class="container">
<h1>Sliding Puzzle</h1>
<!--Menu Modal-->
<div class="menu-modal" id="modal">
<h2 class="menu-title">Main Menu</h2>
<span class="close-button">
<a href="#" id="close"
><i
class="fa-sharp fa-regular fa-rectangle-xmark fa-2xl"
style="color: #2f97a0"
></i
></a>
</span>
<div class="sub-menu">
<div class="menu-subtitle">Objective</div>
<div class="menu-text">
<p>
Solve a puzzle by rearranging tiles in correct order to make a complete image.
</p>
</div>
<div class="menu-subtitle">Rules</div>
<div class="menu-text">
<p>
<span class="bold">New Game:</span> At the beginning of the game click "New Game" to shuffle the tiles.
</p>
<p>
<span class="bold">Tile Movement:</span> The game is played on a grid with square tiles. There is one empty space that allows tiles to slide into it.
</p>
<p>
<span class="bold">Tile Sliding:</span> Tiles can be moved horizontally or vertically into the empty space. Only one tile can occupy the empty space at a time, and tiles cannot jump over one another.
</p>
<p>
<span class="bold">Winning:</span> The game is considered solved or won when the tiles are in the correct order to make a complete image.
</p>
<p>
<span class="bold">Reset and Shuffle:</span> To reset the puzzle to its initial state click on "New Game" to shuffle the tiles to start over.
</p>
<p>
<span class="bold">Show/ close complete puzzle:</span> To see complete puzzle image click on "Show image", to close - click on image
</p>
</div>
</div>
</div>
<div id="menu-overlay"></div>
<!--End of modal-->
<div class="game-container">
<div class="buttons">
<!--A button to open modal-->
<button id="menu-button">Menu</button>
<!--New game button-->
<button id="new-game">New Game</button>
<!--A button to show complete puzzle image-->
<button id="show-img">Show image</button>
<!--Moves counter-->
<div id="moves">Moves: 0</div>
</div>
<!--Complete puzzle modal-->
<div class="complete-puzzle" id="imgModal">
<img src="assets/images/coast-of-galway360.jpg" alt="Photo of Galway coast on a sunny day" />
</div>
<div id="puzzle-overlay"></div>
<div id="puzzle-container">
<img id="tile11" class="tile tile1" data-row="1" data-column="1" src="assets/images/1.jpg" alt="Puzzle tile with clouds" />
<img id="tile12" class="tile tile2" data-row="1" data-column="2" src="assets/images/2.jpg" alt="Puzzle tile with clouds" />
<img id="tile13" class="tile tile3" data-row="1" data-column="3" src="assets/images/3.jpg" alt="Puzzle tile with clouds" />
<img id="tile21" class="tile tile4" data-row="2" data-column="1" src="assets/images/4.jpg" alt="Puzzle tile with clouds and ocean" />
<img id="tile22" class="tile tile5" data-row="2" data-column="2" src="assets/images/5.jpg" alt="Puzzle tile with clouds and ocean" />
<img id="tile23" class="tile tile6" data-row="2" data-column="3" src="assets/images/6.jpg" alt="Puzzle tile with clouds and ocean" />
<img id="tile31" class="tile tile7" data-row="3" data-column="1" src="assets/images/7.jpg" alt="Puzzle tile with beach sand and rocks" />
<img id="tile32" class="tile tile8" data-row="3" data-column="2" src="assets/images/8.jpg" alt="Puzzle tile with beach sand and rocks" />
<img id="tile33" class="tile tile9" data-row="3" data-column="3" src="assets/images/empty-tile9.jpg" alt="Empty, white puzzle tile" />
</div>
</div>
<!--Footer-->
<footer class="footer">
<ul class="footer-icons">
<li>
<a href="https://github.com/violaberg" target="_blank" rel="noopener" aria-label="Visit my GitHub page (opens in a new tab)"><i class="fa-brands fa-github fa-xl" style="color: #000000"></i
></a>
</li>
<li>
<a href="https://www.instagram.com/photos_by_vb/" target="_blank" rel="noopener" aria-label="Visit my Instagram page (opens in a new tab)"><i
class="fa-brands fa-instagram fa-xl"
style="color: #000000"
></i
></a>
</li>
<li>
<a href="https://www.linkedin.com/in/viola-bergere-5a668699/" target="_blank" rel="noopener" aria-label="Visit my LinkedIn page (opens in a new tab)"><i class="fa-brands fa-linkedin fa-xl" style="color: #000000"></i
></a>
</li>
</ul>
<p class="copyright">©reated by violaberg</p>
</footer>
<!--End of footer-->
</div>
<script src="https://kit.fontawesome.com/284fde1047.js" crossorigin="anonymous"></script>
<script src="assets/js/script.js"></script>
</body>
</html>
I had working puzzle but it kept giving me console error I couldn’t fix for some reason so I change the code entirely which wasn’t very smart as know I got stuck at this error for all tiles: No adjacent empty tile found for (1, 2) I tried to change up moveTiles and ChooseTile functions but nothing seems to fix the issue.