{"id":319,"date":"2025-07-29T02:38:25","date_gmt":"2025-07-29T02:38:25","guid":{"rendered":"https:\/\/insaatsirketleri.com.tr\/en\/?p=319"},"modified":"2025-07-29T02:38:25","modified_gmt":"2025-07-29T02:38:25","slug":"jigsaw-puzzle","status":"publish","type":"post","link":"https:\/\/insaatsirketleri.com.tr\/en\/jigsaw-puzzle\/","title":{"rendered":"Jigsaw Puzzle"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <style>\n        \/* Custom CSS for the puzzle pieces and game *\/\n        body {\n            font-family: 'Inter', sans-serif;\n            background-color: #f0f2f5;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            min-height: 100vh;\n            margin: 0;\n            overflow: auto; \/* Allow scrolling if content overflows *\/\n        }\n\n        .puzzle-container {\n            display: grid;\n            border: 4px solid #4a90e2;\n            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);\n            background-color: #fff;\n            position: relative;\n            overflow: hidden; \/* Ensure pieces don't overflow the container *\/\n            border-radius: 15px;\n            padding: 10px;\n        }\n\n        .puzzle-piece {\n            position: absolute; \/* Allows for drag and drop positioning *\/\n            border: 1px solid rgba(0, 0, 0, 0.1);\n            box-sizing: border-box; \/* Include padding and border in the element's total width and height *\/\n            cursor: grab;\n            transition: transform 0.1s ease-out; \/* Smooth movement when snapping *\/\n            background-size: cover; \/* Ensure image covers the piece *\/\n            border-radius: 5px;\n            overflow: hidden; \/* Hide any overflow from background image *\/\n        }\n\n        .puzzle-piece.dragging {\n            cursor: grabbing;\n            z-index: 100; \/* Bring dragged piece to front *\/\n            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);\n        }\n\n        .puzzle-piece.correct {\n            border: 2px solid #28a745; \/* Green border for correct pieces *\/\n            box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);\n        }\n\n        .puzzle-piece.incorrect {\n            border: 2px solid #dc3545; \/* Red border for incorrect pieces *\/\n        }\n\n        .puzzle-piece::after {\n            content: '';\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            pointer-events: none; \/* Allow events to pass through to the piece *\/\n            border-radius: 5px;\n        }\n\n        .controls {\n            display: flex;\n            gap: 15px;\n            margin-top: 20px;\n            flex-wrap: wrap;\n            justify-content: center;\n        }\n\n        .btn {\n            padding: 12px 25px;\n            border-radius: 10px;\n            font-weight: bold;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n            border: none;\n            background-image: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);\n            color: white;\n            position: relative;\n            overflow: hidden;\n            z-index: 1;\n        }\n\n        .btn:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);\n        }\n\n        .btn:active {\n            transform: translateY(0);\n            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n        }\n\n        .btn::before {\n            content: '';\n            position: absolute;\n            top: 0;\n            left: -100%;\n            width: 100%;\n            height: 100%;\n            background: rgba(255, 255, 255, 0.2);\n            transition: all 0.4s ease;\n            z-index: -1;\n        }\n\n        .btn:hover::before {\n            left: 0;\n        }\n\n        .message-box {\n            position: fixed;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%);\n            background-color: rgba(0, 0, 0, 0.8);\n            color: white;\n            padding: 25px 40px;\n            border-radius: 15px;\n            z-index: 1000;\n            text-align: center;\n            font-size: 1.5rem;\n            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\n            display: none; \/* Hidden by default *\/\n        }\n\n        .message-box button {\n            margin-top: 20px;\n            padding: 10px 20px;\n            background-color: #4a90e2;\n            color: white;\n            border: none;\n            border-radius: 8px;\n            cursor: pointer;\n            font-size: 1rem;\n            transition: background-color 0.3s ease;\n        }\n\n        .message-box button:hover {\n            background-color: #357ABD;\n        }\n\n        .main-container {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            padding: 20px;\n            background-color: #ffffff;\n            border-radius: 20px;\n            box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);\n        }\n\n        .header {\n            font-size: 2.5rem;\n            font-weight: bold;\n            color: #333;\n            margin-bottom: 25px;\n            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);\n        }\n\n        .image-upload-section {\n            margin-bottom: 20px;\n            text-align: center;\n        }\n\n        .image-upload-section label {\n            display: block;\n            margin-bottom: 10px;\n            font-size: 1.1rem;\n            color: #555;\n        }\n\n        .image-upload-section input[type=\"file\"] {\n            padding: 10px;\n            border: 2px solid #ccc;\n            border-radius: 8px;\n            background-color: #f9f9f9;\n            cursor: pointer;\n            transition: border-color 0.3s ease;\n        }\n\n        .image-upload-section input[type=\"file\"]:hover {\n            border-color: #4a90e2;\n        }\n\n        .difficulty-select {\n            margin-bottom: 20px;\n            text-align: center;\n        }\n\n        .difficulty-select label {\n            display: block;\n            margin-bottom: 10px;\n            font-size: 1.1rem;\n            color: #555;\n        }\n\n        .difficulty-select select {\n            padding: 10px;\n            border: 2px solid #ccc;\n            border-radius: 8px;\n            background-color: #f9f9f9;\n            cursor: pointer;\n            transition: border-color 0.3s ease;\n            appearance: none; \/* Remove default select arrow *\/\n            background-image: url('data:image\/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23000000%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-6.5%200-12.3%203.2-16.1%208.1-3.9%204.9-4.8%2011.8-2.5%2017.7l139.3%20204.4c3.9%205.7%2010%209.1%2016.4%209.1s12.5-3.4%2016.4-9.1L289.5%2091c2.3-5.9%201.4-12.8-2.5-17.7z%22%2F%3E%3C%2Fsvg%3E');\n            background-repeat: no-repeat;\n            background-position: right 10px top 50%;\n            background-size: 12px auto;\n        }\n\n        .difficulty-select select:hover {\n            border-color: #4a90e2;\n        }\n\n        \/* Responsive adjustments *\/\n        @media (max-width: 768px) {\n            .header {\n                font-size: 2rem;\n            }\n            .puzzle-container {\n                width: 95vw; \/* Adjust width for smaller screens *\/\n                height: 95vw; \/* Keep aspect ratio *\/\n                padding: 5px;\n            }\n            .controls {\n                flex-direction: column;\n                gap: 10px;\n            }\n            .btn {\n                width: 80%;\n                margin: 0 auto;\n            }\n            .message-box {\n                font-size: 1.2rem;\n                padding: 20px 30px;\n            }\n        }\n\n        @media (max-width: 480px) {\n            .header {\n                font-size: 1.8rem;\n            }\n            .puzzle-container {\n                width: 98vw;\n                height: 98vw;\n            }\n            .btn {\n                width: 90%;\n            }\n            .message-box {\n                font-size: 1rem;\n                padding: 15px 25px;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"main-container\">\n        <h1 class=\"header\">Jigsaw Puzzle<\/h1>\n\n        <div class=\"image-upload-section\">\n            <label for=\"imageUpload\">Upload Your Own Image:<\/label>\n            <input type=\"file\" id=\"imageUpload\" accept=\"image\/*\">\n        <\/div>\n\n        <div class=\"difficulty-select\">\n            <label for=\"difficulty\">Select Difficulty:<\/label>\n            <select id=\"difficulty\">\n                <option value=\"3\">Easy (3&#215;3)<\/option>\n                <option value=\"4\" selected>Medium (4&#215;4)<\/option>\n                <option value=\"5\">Hard (5&#215;5)<\/option>\n                <option value=\"6\">Very Hard (6&#215;6)<\/option>\n            <\/select>\n        <\/div>\n\n        <div id=\"puzzleContainer\" class=\"puzzle-container w-[600px] h-[600px]\">\n            <!-- Puzzle pieces will be dynamically generated here -->\n        <\/div>\n\n        <div class=\"controls\">\n            <button id=\"shuffleBtn\" class=\"btn\">Shuffle<\/button>\n            <button id=\"resetBtn\" class=\"btn\">Reset<\/button>\n        <\/div>\n\n        <div id=\"messageBox\" class=\"message-box\">\n            <p id=\"messageText\"><\/p>\n            <button id=\"closeMessageBtn\">OK<\/button>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ Global variables for puzzle state\n        let puzzleImage = new Image();\n        puzzleImage.src = 'https:\/\/placehold.co\/600x600\/4a90e2\/ffffff?text=Puzzle+Image'; \/\/ Default image\n        let numPieces = 4; \/\/ Default 4x4 puzzle\n        let pieces = [];\n        let puzzleContainer;\n        let pieceWidth, pieceHeight;\n        let isDragging = false;\n        let currentDraggedPiece = null;\n        let offsetX, offsetY;\n        let correctPositions = []; \/\/ Stores the ideal top\/left for each piece\n        let puzzleSize = 600; \/\/ Default size for the puzzle container\n\n        \/\/ Get DOM elements\n        const imageUpload = document.getElementById('imageUpload');\n        const difficultySelect = document.getElementById('difficulty');\n        const shuffleBtn = document.getElementById('shuffleBtn');\n        const resetBtn = document.getElementById('resetBtn');\n        const messageBox = document.getElementById('messageBox');\n        const messageText = document.getElementById('messageText');\n        const closeMessageBtn = document.getElementById('closeMessageBtn');\n\n        \/**\n         * Displays a message box with the given text.\n         * @param {string} message - The message to display.\n         *\/\n        function showMessageBox(message) {\n            messageText.textContent = message;\n            messageBox.style.display = 'block';\n        }\n\n        \/**\n         * Hides the message box.\n         *\/\n        function hideMessageBox() {\n            messageBox.style.display = 'none';\n        }\n\n        \/**\n         * Initializes the puzzle by setting up the container and piece dimensions.\n         *\/\n        function initializePuzzle() {\n            puzzleContainer = document.getElementById('puzzleContainer');\n            \/\/ Dynamically set puzzle container size based on initial CSS or calculated value\n            const containerRect = puzzleContainer.getBoundingClientRect();\n            puzzleSize = Math.min(containerRect.width, containerRect.height); \/\/ Use the smaller dimension for square\n            puzzleContainer.style.width = `${puzzleSize}px`;\n            puzzleContainer.style.height = `${puzzleSize}px`;\n\n            pieceWidth = puzzleSize \/ numPieces;\n            pieceHeight = puzzleSize \/ numPieces;\n\n            \/\/ Clear any existing pieces\n            puzzleContainer.innerHTML = '';\n            pieces = [];\n            correctPositions = [];\n        }\n\n        \/**\n         * Creates and appends puzzle pieces to the container.\n         *\/\n        function createPuzzlePieces() {\n            for (let i = 0; i < numPieces * numPieces; i++) {\n                const piece = document.createElement('div');\n                piece.classList.add('puzzle-piece');\n                piece.dataset.index = i; \/\/ Store original index\n\n                \/\/ Calculate original row and column\n                const row = Math.floor(i \/ numPieces);\n                const col = i % numPieces;\n\n                \/\/ Calculate background position to show the correct part of the image\n                const bgX = -col * pieceWidth;\n                const bgY = -row * pieceHeight;\n\n                piece.style.width = `${pieceWidth}px`;\n                piece.style.height = `${pieceHeight}px`;\n                piece.style.backgroundImage = `url(${puzzleImage.src})`;\n                piece.style.backgroundSize = `${puzzleSize}px ${puzzleSize}px`; \/\/ Scale background to full image size\n                piece.style.backgroundPosition = `${bgX}px ${bgY}px`;\n\n                \/\/ Store correct position for later checking\n                correctPositions[i] = {\n                    top: row * pieceHeight,\n                    left: col * pieceWidth\n                };\n\n                \/\/ Set initial position (for shuffling later)\n                piece.style.top = `${row * pieceHeight}px`;\n                piece.style.left = `${col * pieceWidth}px`;\n\n                pieces.push(piece);\n                puzzleContainer.appendChild(piece);\n            }\n        }\n\n        \/**\n         * Shuffles the puzzle pieces randomly.\n         *\/\n        function shufflePieces() {\n            \/\/ Get current positions of pieces\n            const currentPositions = pieces.map(piece => ({\n                top: parseFloat(piece.style.top),\n                left: parseFloat(piece.style.left)\n            }));\n\n            \/\/ Shuffle the array of pieces\n            for (let i = pieces.length - 1; i > 0; i--) {\n                const j = Math.floor(Math.random() * (i + 1));\n                [pieces[i], pieces[j]] = [pieces[j], pieces[i]]; \/\/ Swap pieces\n            }\n\n            \/\/ Apply shuffled positions\n            pieces.forEach((piece, index) => {\n                const newPos = currentPositions[index]; \/\/ Use a shuffled position from the original grid\n                piece.style.top = `${newPos.top}px`;\n                piece.style.left = `${newPos.left}px`;\n                piece.classList.remove('correct', 'incorrect'); \/\/ Remove status classes\n            });\n\n            checkWin(); \/\/ Check if by some miracle it's already solved (unlikely)\n        }\n\n        \/**\n         * Resets the puzzle pieces to their correct, solved positions.\n         *\/\n        function resetPuzzle() {\n            pieces.forEach(piece => {\n                const index = parseInt(piece.dataset.index);\n                piece.style.top = `${correctPositions[index].top}px`;\n                piece.style.left = `${correctPositions[index].left}px`;\n                piece.classList.remove('correct', 'incorrect'); \/\/ Remove status classes\n            });\n            checkWin(); \/\/ Should be solved after reset\n        }\n\n        \/**\n         * Checks if the puzzle is solved.\n         *\/\n        function checkWin() {\n            let allCorrect = true;\n            pieces.forEach(piece => {\n                const index = parseInt(piece.dataset.index);\n                const currentTop = parseFloat(piece.style.top);\n                const currentLeft = parseFloat(piece.style.left);\n\n                \/\/ Check if the piece is within a small tolerance of its correct position\n                const tolerance = 5; \/\/ Pixels\n                if (Math.abs(currentTop - correctPositions[index].top) > tolerance ||\n                    Math.abs(currentLeft - correctPositions[index].left) > tolerance) {\n                    allCorrect = false;\n                    piece.classList.remove('correct');\n                    \/\/ piece.classList.add('incorrect'); \/\/ Optional: show incorrect pieces\n                } else {\n                    piece.classList.add('correct');\n                    piece.classList.remove('incorrect');\n                }\n            });\n\n            if (allCorrect) {\n                showMessageBox(\"Congratulations! You solved the puzzle!\");\n            }\n        }\n\n        \/\/ --- Drag and Drop Logic ---\n\n        \/**\n         * Handles the start of a drag operation.\n         * @param {MouseEvent} e - The mouse event.\n         *\/\n        function dragStart(e) {\n            if (e.button !== 0) return; \/\/ Only allow left click\n            currentDraggedPiece = e.target.closest('.puzzle-piece');\n            if (!currentDraggedPiece) return;\n\n            isDragging = true;\n            currentDraggedPiece.classList.add('dragging');\n\n            \/\/ Calculate offset relative to the piece's top-left corner\n            const rect = currentDraggedPiece.getBoundingClientRect();\n            offsetX = e.clientX - rect.left;\n            offsetY = e.clientY - rect.top;\n\n            \/\/ Set initial position for dragging (prevents jump)\n            currentDraggedPiece.style.left = `${e.clientX - puzzleContainer.getBoundingClientRect().left - offsetX}px`;\n            currentDraggedPiece.style.top = `${e.clientY - puzzleContainer.getBoundingClientRect().top - offsetY}px`;\n\n            \/\/ Prevent default drag behavior\n            e.preventDefault();\n        }\n\n        \/**\n         * Handles the drag movement.\n         * @param {MouseEvent} e - The mouse event.\n         *\/\n        function dragMove(e) {\n            if (!isDragging || !currentDraggedPiece) return;\n\n            const containerRect = puzzleContainer.getBoundingClientRect();\n            let newX = e.clientX - containerRect.left - offsetX;\n            let newY = e.clientY - containerRect.top - offsetY;\n\n            \/\/ Constrain piece within puzzle container boundaries\n            newX = Math.max(0, Math.min(newX, puzzleSize - pieceWidth));\n            newY = Math.max(0, Math.min(newY, puzzleSize - pieceHeight));\n\n            currentDraggedPiece.style.left = `${newX}px`;\n            currentDraggedPiece.style.top = `${newY}px`;\n        }\n\n        \/**\n         * Handles the end of a drag operation (mouse up).\n         * @param {MouseEvent} e - The mouse event.\n         *\/\n        function dragEnd(e) {\n            if (!isDragging || !currentDraggedPiece) return;\n\n            isDragging = false;\n            currentDraggedPiece.classList.remove('dragging');\n\n            snapToGrid(currentDraggedPiece);\n            currentDraggedPiece = null; \/\/ Clear dragged piece\n            checkWin(); \/\/ Check win condition after each drop\n        }\n\n        \/**\n         * Snaps a puzzle piece to the nearest correct grid position if it's close enough.\n         * @param {HTMLElement} piece - The puzzle piece to snap.\n         *\/\n        function snapToGrid(piece) {\n            const currentTop = parseFloat(piece.style.top);\n            const currentLeft = parseFloat(piece.style.left);\n            const pieceIndex = parseInt(piece.dataset.index);\n\n            let snapped = false;\n            const snapTolerance = 0.5 * pieceWidth; \/\/ Snap if within half a piece width\/height\n\n            \/\/ Iterate through all correct positions to find the closest one\n            for (let i = 0; i < correctPositions.length; i++) {\n                const targetTop = correctPositions[i].top;\n                const targetLeft = correctPositions[i].left;\n\n                if (Math.abs(currentTop - targetTop) < snapTolerance &#038;&#038;\n                    Math.abs(currentLeft - targetLeft) < snapTolerance) {\n\n                    \/\/ Check if this target position is already occupied by another correctly placed piece\n                    let occupied = false;\n                    for (const otherPiece of pieces) {\n                        if (otherPiece !== piece &#038;&#038; otherPiece.classList.contains('correct')) {\n                            const otherPieceIndex = parseInt(otherPiece.dataset.index);\n                            if (Math.abs(parseFloat(otherPiece.style.top) - targetTop) < 5 &#038;&#038;\n                                Math.abs(parseFloat(otherPiece.style.left) - targetLeft) < 5) {\n                                occupied = true;\n                                break;\n                            }\n                        }\n                    }\n\n                    if (!occupied) {\n                        piece.style.top = `${targetTop}px`;\n                        piece.style.left = `${targetLeft}px`;\n                        snapped = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        \/**\n         * Handles touch start event for drag and drop.\n         * @param {TouchEvent} e - The touch event.\n         *\/\n        function touchStart(e) {\n            if (e.touches.length === 1) {\n                const touch = e.touches[0];\n                currentDraggedPiece = touch.target.closest('.puzzle-piece');\n                if (!currentDraggedPiece) return;\n\n                isDragging = true;\n                currentDraggedPiece.classList.add('dragging');\n\n                const rect = currentDraggedPiece.getBoundingClientRect();\n                offsetX = touch.clientX - rect.left;\n                offsetY = touch.clientY - rect.top;\n\n                currentDraggedPiece.style.left = `${touch.clientX - puzzleContainer.getBoundingClientRect().left - offsetX}px`;\n                currentDraggedPiece.style.top = `${touch.clientY - puzzleContainer.getBoundingClientRect().top - offsetY}px`;\n\n                e.preventDefault(); \/\/ Prevent scrolling\n            }\n        }\n\n        \/**\n         * Handles touch move event for drag and drop.\n         * @param {TouchEvent} e - The touch event.\n         *\/\n        function touchMove(e) {\n            if (!isDragging || !currentDraggedPiece || e.touches.length !== 1) return;\n\n            const touch = e.touches[0];\n            const containerRect = puzzleContainer.getBoundingClientRect();\n            let newX = touch.clientX - containerRect.left - offsetX;\n            let newY = touch.clientY - containerRect.top - offsetY;\n\n            newX = Math.max(0, Math.min(newX, puzzleSize - pieceWidth));\n            newY = Math.max(0, Math.min(newY, puzzleSize - pieceHeight));\n\n            currentDraggedPiece.style.left = `${newX}px`;\n            currentDraggedPiece.style.top = `${newY}px`;\n\n            e.preventDefault(); \/\/ Prevent scrolling\n        }\n\n        \/**\n         * Handles touch end event for drag and drop.\n         * @param {TouchEvent} e - The touch event.\n         *\/\n        function touchEnd(e) {\n            if (!isDragging || !currentDraggedPiece) return;\n\n            isDragging = false;\n            currentDraggedPiece.classList.remove('dragging');\n\n            snapToGrid(currentDraggedPiece);\n            currentDraggedPiece = null;\n            checkWin();\n        }\n\n\n        \/\/ --- Event Listeners ---\n\n        \/\/ These event listeners are moved inside window.onload to ensure puzzleContainer is defined\n        \/\/ puzzleContainer.addEventListener('mousedown', dragStart);\n        \/\/ document.addEventListener('mousemove', dragMove);\n        \/\/ document.addEventListener('mouseup', dragEnd);\n\n        \/\/ Touch events for drag and drop\n        \/\/ puzzleContainer.addEventListener('touchstart', touchStart, { passive: false });\n        \/\/ document.addEventListener('touchmove', touchMove, { passive: false });\n        \/\/ document.addEventListener('touchend', touchEnd);\n        \/\/ document.addEventListener('touchcancel', touchEnd); \/\/ Handle touch cancel (e.g., call interrupted)\n\n        shuffleBtn.addEventListener('click', shufflePieces);\n        resetBtn.addEventListener('click', resetPuzzle);\n        closeMessageBtn.addEventListener('click', hideMessageBox);\n\n        imageUpload.addEventListener('change', (event) => {\n            const file = event.target.files[0];\n            if (file) {\n                const reader = new FileReader();\n                reader.onload = (e) => {\n                    puzzleImage.src = e.target.result;\n                    puzzleImage.onload = () => {\n                        \/\/ Re-initialize and create pieces with the new image\n                        initializePuzzle();\n                        createPuzzlePieces();\n                        shufflePieces();\n                    };\n                };\n                reader.readAsDataURL(file);\n            }\n        });\n\n        difficultySelect.addEventListener('change', (event) => {\n            numPieces = parseInt(event.target.value);\n            \/\/ Re-initialize and create pieces with the new difficulty\n            initializePuzzle();\n            createPuzzlePieces();\n            shufflePieces();\n        });\n\n        \/\/ Initial setup when the page loads\n        window.onload = function() {\n            \/\/ Ensure the image is loaded before creating pieces\n            puzzleImage.onload = () => {\n                initializePuzzle();\n                createPuzzlePieces();\n                shufflePieces();\n            };\n            \/\/ If image is already loaded (e.g., from cache), call directly\n            if (puzzleImage.complete) {\n                initializePuzzle();\n                createPuzzlePieces();\n                shufflePieces();\n            }\n\n            \/\/ Moved puzzleContainer event listeners here to ensure puzzleContainer is defined\n            puzzleContainer.addEventListener('mousedown', dragStart);\n            puzzleContainer.addEventListener('touchstart', touchStart, { passive: false });\n\n            \/\/ Document-level event listeners can remain outside puzzleContainer.onload\n            document.addEventListener('mousemove', dragMove);\n            document.addEventListener('mouseup', dragEnd);\n            document.addEventListener('touchmove', touchMove, { passive: false });\n            document.addEventListener('touchend', touchEnd);\n            document.addEventListener('touchcancel', touchEnd); \/\/ Handle touch cancel (e.g., call interrupted)\n        };\n\n        \/\/ Handle responsiveness on window resize\n        window.addEventListener('resize', () => {\n            \/\/ Re-calculate puzzle size and piece dimensions\n            const containerRect = puzzleContainer.getBoundingClientRect();\n            const newPuzzleSize = Math.min(containerRect.width, containerRect.height);\n\n            \/\/ Only re-render if the size has significantly changed\n            if (Math.abs(newPuzzleSize - puzzleSize) > 10) { \/\/ Threshold of 10px\n                puzzleSize = newPuzzleSize;\n                puzzleContainer.style.width = `${puzzleSize}px`;\n                puzzleContainer.style.height = `${puzzleSize}px`;\n                pieceWidth = puzzleSize \/ numPieces;\n                pieceHeight = puzzleSize \/ numPieces;\n\n                \/\/ Re-position all pieces based on new dimensions\n                pieces.forEach(piece => {\n                    const index = parseInt(piece.dataset.index);\n                    const row = Math.floor(index \/ numPieces);\n                    const col = index % numPieces;\n\n                    const bgX = -col * pieceWidth;\n                    const bgY = -row * pieceHeight;\n\n                    piece.style.width = `${pieceWidth}px`;\n                    piece.style.height = `${pieceHeight}px`;\n                    piece.style.backgroundSize = `${puzzleSize}px ${puzzleSize}px`;\n                    piece.style.backgroundPosition = `${bgX}px ${bgY}px`;\n\n                    \/\/ Update correct positions\n                    correctPositions[index] = {\n                        top: row * pieceHeight,\n                        left: col * pieceWidth\n                    };\n\n                    \/\/ If the piece is currently at its correct position, update its style\n                    if (piece.classList.contains('correct')) {\n                        piece.style.top = `${correctPositions[index].top}px`;\n                        piece.style.left = `${correctPositions[index].left}px`;\n                    }\n                    \/\/ Otherwise, its current (shuffled) position remains, but its dimensions are updated\n                });\n                checkWin(); \/\/ Re-check win condition after resize\n            }\n        });\n\n    <\/script>\n","protected":false},"excerpt":{"rendered":"<p>Jigsaw Puzzle Upload Your Own Image: Select Difficulty: Easy (3&#215;3)Medium (4&#215;4)Hard (5&#215;5)Very Hard (6&#215;6) Shuffle Reset OK<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-319","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/319","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/comments?post=319"}],"version-history":[{"count":1,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/319\/revisions"}],"predecessor-version":[{"id":320,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/319\/revisions\/320"}],"wp:attachment":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/media?parent=319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/categories?post=319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/tags?post=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}