File size: 14,998 Bytes
201ed39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sliding Puzzle Game</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        .tile {
            transition: all 0.3s ease;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
        }
        .tile:hover {
            transform: scale(1.02);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        .win-message {
            animation: fadeIn 0.5s ease-in-out;
        }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .puzzle-container {
            perspective: 1000px;
        }
    </style>
</head>
<body class="bg-gradient-to-br from-blue-50 to-purple-100 min-h-screen flex flex-col items-center justify-center p-4">
    <div class="max-w-4xl w-full">
        <h1 class="text-4xl font-bold text-center text-purple-800 mb-2">Sliding Puzzle Challenge</h1>
        <p class="text-center text-gray-600 mb-8">Slide the tiles to reconstruct the image. Click on adjacent tiles to swap with the empty space.</p>
        
        <div class="flex flex-col md:flex-row gap-8 items-center justify-center">
            <div class="puzzle-container bg-white rounded-xl p-4 shadow-xl">
                <div class="grid grid-cols-3 gap-2 mb-4" id="puzzle-grid">
                    <!-- Puzzle tiles will be inserted here by JavaScript -->
                </div>
                
                <div class="flex justify-between items-center mt-4">
                    <div class="text-lg font-semibold text-purple-700">
                        Moves: <span id="move-counter">0</span>
                    </div>
                    <div class="flex gap-2">
                        <button id="shuffle-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg transition flex items-center gap-2">
                            <i class="fas fa-random"></i> Shuffle
                        </button>
                        <button id="new-game-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition flex items-center gap-2">
                            <i class="fas fa-redo"></i> New Game
                        </button>
                    </div>
                </div>
            </div>
            
            <div class="bg-white rounded-xl p-6 shadow-xl max-w-xs w-full">
                <h2 class="text-xl font-bold text-purple-800 mb-4">How to Play</h2>
                <ul class="space-y-3 text-gray-700">
                    <li class="flex items-start gap-2">
                        <i class="fas fa-arrow-right text-purple-500 mt-1"></i>
                        <span>Click on a tile adjacent to the empty space to move it</span>
                    </li>
                    <li class="flex items-start gap-2">
                        <i class="fas fa-arrow-right text-purple-500 mt-1"></i>
                        <span>Rearrange all tiles to complete the image</span>
                    </li>
                    <li class="flex items-start gap-2">
                        <i class="fas fa-arrow-right text-purple-500 mt-1"></i>
                        <span>Try to solve it in the fewest moves possible</span>
                    </li>
                </ul>
                
                <div class="mt-6">
                    <h3 class="font-semibold text-gray-800 mb-2">Completed Image:</h3>
                    <img src="https://source.unsplash.com/random/300x300/?nature" alt="Target image" class="rounded-lg border border-gray-200 w-full" id="target-image">
                </div>
            </div>
        </div>
    </div>
    
    <!-- Win Modal -->
    <div id="win-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">
        <div class="bg-white rounded-xl p-8 max-w-md w-full mx-4 win-message">
            <div class="text-center">
                <i class="fas fa-trophy text-6xl text-yellow-500 mb-4"></i>
                <h2 class="text-3xl font-bold text-purple-800 mb-2">Congratulations!</h2>
                <p class="text-gray-600 mb-6">You solved the puzzle in <span id="final-moves" class="font-bold">0</span> moves!</p>
                <button id="play-again-btn" class="bg-purple-600 hover:bg-purple-700 text-white px-6 py-3 rounded-lg text-lg font-medium w-full">
                    Play Again
                </button>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Game state
            const gridSize = 3;
            let puzzleState = [];
            let emptyPos = { row: gridSize - 1, col: gridSize - 1 };
            let moveCount = 0;
            let isGameWon = false;
            
            // DOM elements
            const puzzleGrid = document.getElementById('puzzle-grid');
            const moveCounter = document.getElementById('move-counter');
            const shuffleBtn = document.getElementById('shuffle-btn');
            const newGameBtn = document.getElementById('new-game-btn');
            const winModal = document.getElementById('win-modal');
            const finalMoves = document.getElementById('final-moves');
            const playAgainBtn = document.getElementById('play-again-btn');
            
            // Initialize the game
            initGame();
            
            // Event listeners
            shuffleBtn.addEventListener('click', shufflePuzzle);
            newGameBtn.addEventListener('click', initGame);
            playAgainBtn.addEventListener('click', initGame);
            
            // Initialize game
            function initGame() {
                // Reset game state
                moveCount = 0;
                isGameWon = false;
                moveCounter.textContent = moveCount;
                winModal.classList.add('hidden');
                
                // Create ordered puzzle state (1-8, with 9 as empty)
                puzzleState = [];
                for (let i = 0; i < gridSize * gridSize - 1; i++) {
                    puzzleState.push(i + 1);
                }
                puzzleState.push(0); // 0 represents the empty space
                
                // Shuffle the puzzle
                shufflePuzzle();
                
                // Render the puzzle
                renderPuzzle();
            }
            
            // Shuffle the puzzle
            function shufflePuzzle() {
                if (isGameWon) {
                    isGameWon = false;
                    winModal.classList.add('hidden');
                }
                
                // Reset move counter
                moveCount = 0;
                moveCounter.textContent = moveCount;
                
                // Fisher-Yates shuffle algorithm
                for (let i = puzzleState.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [puzzleState[i], puzzleState[j]] = [puzzleState[j], puzzleState[i]];
                }
                
                // Find the empty position
                const emptyIndex = puzzleState.indexOf(0);
                emptyPos = {
                    row: Math.floor(emptyIndex / gridSize),
                    col: emptyIndex % gridSize
                };
                
                // Check if the puzzle is solvable (must have even inversions)
                if (!isSolvable()) {
                    // If not solvable, swap first two non-empty tiles to make it solvable
                    if (puzzleState[0] === 0 || puzzleState[1] === 0) {
                        [puzzleState[2], puzzleState[3]] = [puzzleState[3], puzzleState[2]];
                    } else {
                        [puzzleState[0], puzzleState[1]] = [puzzleState[1], puzzleState[0]];
                    }
                }
                
                renderPuzzle();
            }
            
            // Check if the puzzle is solvable
            function isSolvable() {
                let inversions = 0;
                const flattened = puzzleState.filter(num => num !== 0);
                
                for (let i = 0; i < flattened.length - 1; i++) {
                    for (let j = i + 1; j < flattened.length; j++) {
                        if (flattened[i] > flattened[j]) {
                            inversions++;
                        }
                    }
                }
                
                // For a 3x3 grid, the puzzle is solvable if inversions are even
                return inversions % 2 === 0;
            }
            
            // Render the puzzle grid
            function renderPuzzle() {
                puzzleGrid.innerHTML = '';
                
                for (let row = 0; row < gridSize; row++) {
                    for (let col = 0; col < gridSize; col++) {
                        const index = row * gridSize + col;
                        const tileValue = puzzleState[index];
                        
                        if (tileValue === 0) {
                            // Empty space
                            const emptyTile = document.createElement('div');
                            emptyTile.className = 'bg-gray-200 rounded-lg aspect-square flex items-center justify-center opacity-70';
                            emptyTile.dataset.row = row;
                            emptyTile.dataset.col = col;
                            puzzleGrid.appendChild(emptyTile);
                        } else {
                            // Numbered tile
                            const tile = document.createElement('div');
                            tile.className = 'tile bg-gradient-to-br from-purple-100 to-blue-100 rounded-lg aspect-square flex items-center justify-center text-2xl font-bold text-purple-800 cursor-pointer';
                            tile.textContent = tileValue;
                            tile.dataset.row = row;
                            tile.dataset.col = col;
                            tile.dataset.value = tileValue;
                            
                            // Add background image slice
                            tile.style.backgroundImage = `url(https://source.unsplash.com/random/300x300/?nature)`;
                            tile.style.backgroundSize = `${gridSize * 100}% ${gridSize * 100}%`;
                            
                            // Calculate background position for the image slice
                            const targetRow = Math.floor((tileValue - 1) / gridSize);
                            const targetCol = (tileValue - 1) % gridSize;
                            const xPos = (targetCol / (gridSize - 1)) * 100;
                            const yPos = (targetRow / (gridSize - 1)) * 100;
                            tile.style.backgroundPosition = `${xPos}% ${yPos}%`;
                            
                            tile.addEventListener('click', () => handleTileClick(row, col));
                            puzzleGrid.appendChild(tile);
                        }
                    }
                }
                
                // Update empty position
                const emptyIndex = puzzleState.indexOf(0);
                emptyPos = {
                    row: Math.floor(emptyIndex / gridSize),
                    col: emptyIndex % gridSize
                };
            }
            
            // Handle tile click
            function handleTileClick(row, col) {
                if (isGameWon) return;
                
                // Check if the clicked tile is adjacent to the empty space
                const isAdjacent = 
                    (Math.abs(row - emptyPos.row) === 1 && col === emptyPos.col) ||
                    (Math.abs(col - emptyPos.col) === 1 && row === emptyPos.row);
                
                if (isAdjacent) {
                    // Swap positions
                    const clickedIndex = row * gridSize + col;
                    const emptyIndex = emptyPos.row * gridSize + emptyPos.col;
                    
                    // Update puzzle state
                    [puzzleState[clickedIndex], puzzleState[emptyIndex]] = 
                        [puzzleState[emptyIndex], puzzleState[clickedIndex]];
                    
                    // Update move counter
                    moveCount++;
                    moveCounter.textContent = moveCount;
                    
                    // Re-render the puzzle
                    renderPuzzle();
                    
                    // Check if puzzle is solved
                    checkWinCondition();
                }
            }
            
            // Check if the puzzle is solved
            function checkWinCondition() {
                for (let i = 0; i < puzzleState.length - 1; i++) {
                    if (puzzleState[i] !== i + 1) {
                        return false;
                    }
                }
                
                if (puzzleState[puzzleState.length - 1] === 0) {
                    // Puzzle is solved
                    isGameWon = true;
                    finalMoves.textContent = moveCount;
                    winModal.classList.remove('hidden');
                    
                    // Add confetti effect
                    const confettiSettings = { target: 'confetti-canvas', max: 150 };
                    const confetti = new ConfettiGenerator(confettiSettings);
                    confetti.render();
                    
                    setTimeout(() => {
                        confetti.clear();
                    }, 3000);
                }
            }
        });
    </script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/index.min.js"></script>
    <canvas id="confetti-canvas" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1000;"></canvas>
<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=madansa7/sliding-puzzle-challenge-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>