{"id":257,"date":"2025-07-08T21:08:42","date_gmt":"2025-07-08T13:08:42","guid":{"rendered":"http:\/\/tommy.iapps.hk\/?page_id=257"},"modified":"2025-07-08T21:08:44","modified_gmt":"2025-07-08T13:08:44","slug":"sudoku","status":"publish","type":"page","link":"http:\/\/tommy.iapps.hk\/?page_id=257","title":{"rendered":"Sudoku"},"content":{"rendered":"<p><html lang=\"en\"><head><br \/>\n    <meta charset=\"UTF-8\"><br \/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><br \/>\n    <title>\u6570\u72ec\u6e38\u620f<\/title><br \/>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <link href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.7.2\/css\/all.min.css\" rel=\"stylesheet\">\n    <script>\n        tailwind.config = {\n            theme: {\n                extend: {\n                    colors: {\n                        primary: '#3B82F6',\n                        secondary: '#10B981',\n                        accent: '#F59E0B',\n                        dark: '#1F2937',\n                        light: '#F3F4F6'\n                    },\n                    fontFamily: {\n                        sans: ['Inter', 'system-ui', 'sans-serif'],\n                    },\n                }\n            }\n        }\n    <\/script><\/p>\n<style type=\"text\/tailwindcss\">\n        @layer utilities {\n            .content-auto {\n                content-visibility: auto;\n            }\n            .cell-border {\n                @apply border border-gray-300;\n            }\n            .cell-highlight {\n                @apply bg-blue-100 transition-colors duration-200;\n            }\n            .cell-selected {\n                @apply bg-blue-200 transition-colors duration-200;\n            }\n            .cell-error {\n                @apply bg-red-100 transition-colors duration-200;\n            }\n            .btn-hover {\n                @apply hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200;\n            }\n            .grid-line {\n                @apply border-b-2 border-r-2 border-gray-600;\n            }\n        }\n    <\/style>\n<p><\/head><br \/>\n<body class=\"bg-gradient-to-br from-light to-gray-200 min-h-screen font-sans\"><\/p>\n<div class=\"container mx-auto px-4 py-8 max-w-4xl\">\n        <!-- \u9876\u90e8\u6807\u9898\u533a\u57df --><\/p>\n<header class=\"text-center mb-8\">\n<h1 class=\"text-[clamp(2rem,5vw,3.5rem)] font-bold text-dark mb-2 tracking-tight\">\n                <span class=\"text-primary\">\u6570<\/span><span class=\"text-accent\">\u72ec<\/span><br \/>\n                <span class=\"text-[clamp(1rem,2vw,1.5rem)] font-normal text-gray-600 ml-2\">Sudoku<\/span><br \/>\n            <\/h1>\n<p class=\"text-gray-600 max-w-2xl mx-auto\">\u953b\u70bc\u903b\u8f91\u601d\u7ef4\u7684\u7ecf\u5178\u6570\u5b57\u6e38\u620f\uff0c\u5c06\u6570\u5b571-9\u586b\u5165\u7a7a\u683c\uff0c\u4f7f\u6bcf\u884c\u3001\u6bcf\u5217\u548c\u6bcf\u4e2a3&#215;3\u5c0f\u4e5d\u5bab\u683c\u5185\u5747\u4e0d\u91cd\u590d\u3002<\/p>\n<\/header>\n<p>        <!-- \u6e38\u620f\u533a\u57df --><\/p>\n<div class=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n            <!-- \u5de6\u4fa7\uff1a\u6e38\u620f\u4fe1\u606f --><\/p>\n<div class=\"lg:col-span-1 order-2 lg:order-1\">\n<div class=\"bg-white rounded-xl shadow-lg p-6 h-full flex flex-col\">\n<div class=\"mb-6\">\n<h2 class=\"text-xl font-bold text-dark mb-3 flex items-center\">\n                            <i class=\"fa fa-trophy text-accent mr-2\"><\/i>\u6e38\u620f\u8fdb\u5ea6<br \/>\n                        <\/h2>\n<div class=\"grid grid-cols-2 gap-4 mb-4\">\n<div class=\"bg-gray-50 rounded-lg p-4 text-center\">\n<p class=\"text-sm text-gray-500 mb-1\">\u5df2\u7528\u65f6<\/p>\n<p id=\"timer\" class=\"text-2xl font-bold text-primary\">00:00<\/p>\n<\/p><\/div>\n<div class=\"bg-gray-50 rounded-lg p-4 text-center\">\n<p class=\"text-sm text-gray-500 mb-1\">\u5b8c\u6210\u5ea6<\/p>\n<p id=\"progress\" class=\"text-2xl font-bold text-secondary\">0%<\/p>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"bg-gray-50 rounded-lg p-4\">\n<p class=\"text-sm text-gray-500 mb-1\">\u96be\u5ea6<\/p>\n<div class=\"flex items-center\">\n                                <select id=\"difficulty\" class=\"w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary\/50\"><option value=\"easy\">\u7b80\u5355<\/option><option value=\"medium\" selected=\"\">\u4e2d\u7b49<\/option><option value=\"hard\">\u56f0\u96be<\/option><option value=\"expert\">\u4e13\u5bb6<\/option><\/select>\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"mb-6\">\n<h2 class=\"text-xl font-bold text-dark mb-3 flex items-center\">\n                            <i class=\"fa fa-info-circle text-primary mr-2\"><\/i>\u6e38\u620f\u8bf4\u660e<br \/>\n                        <\/h2>\n<ul class=\"text-gray-600 space-y-2 text-sm\">\n<li class=\"flex items-start\">\n                                <i class=\"fa fa-check-circle text-secondary mt-1 mr-2\"><\/i><br \/>\n                                <span>\u70b9\u51fb\u5355\u5143\u683c\u540e\uff0c\u4f7f\u7528\u6570\u5b57\u952e\u76d8\u8f93\u51651-9<\/span>\n                            <\/li>\n<li class=\"flex items-start\">\n                                <i class=\"fa fa-check-circle text-secondary mt-1 mr-2\"><\/i><br \/>\n                                <span>\u9519\u8bef\u7684\u6570\u5b57\u4f1a\u663e\u793a\u4e3a\u7ea2\u8272<\/span>\n                            <\/li>\n<li class=\"flex items-start\">\n                                <i class=\"fa fa-check-circle text-secondary mt-1 mr-2\"><\/i><br \/>\n                                <span>\u70b9\u51fb&#8221;\u6e05\u9664&#8221;\u6309\u94ae\u5220\u9664\u5f53\u524d\u9009\u4e2d\u5355\u5143\u683c\u7684\u6570\u5b57<\/span>\n                            <\/li>\n<li class=\"flex items-start\">\n                                <i class=\"fa fa-check-circle text-secondary mt-1 mr-2\"><\/i><br \/>\n                                <span>\u70b9\u51fb&#8221;\u63d0\u793a&#8221;\u6309\u94ae\u83b7\u53d6\u4e00\u4e2a\u6b63\u786e\u6570\u5b57<\/span>\n                            <\/li>\n<\/ul><\/div>\n<div class=\"mt-auto\">\n<div class=\"grid grid-cols-2 gap-3\">\n                            <button id=\"new-game\" class=\"bg-primary hover:bg-primary\/90 text-white py-3 px-4 rounded-lg font-medium flex items-center justify-center btn-hover\"><br \/>\n                                <i class=\"fa fa-refresh mr-2\"><\/i>\u65b0\u6e38\u620f<br \/>\n                            <\/button><br \/>\n                            <button id=\"hint\" class=\"bg-accent hover:bg-accent\/90 text-white py-3 px-4 rounded-lg font-medium flex items-center justify-center btn-hover\"><br \/>\n                                <i class=\"fa fa-lightbulb-o mr-2\"><\/i>\u63d0\u793a<br \/>\n                            <\/button>\n                        <\/div>\n<p>                        <button id=\"solve\" class=\"w-full mt-3 bg-secondary hover:bg-secondary\/90 text-white py-3 px-4 rounded-lg font-medium flex items-center justify-center btn-hover\"><br \/>\n                            <i class=\"fa fa-magic mr-2\"><\/i>\u663e\u793a\u7b54\u6848<br \/>\n                        <\/button>\n                    <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>            <!-- \u53f3\u4fa7\uff1a\u6570\u72ec\u68cb\u76d8 --><\/p>\n<div class=\"lg:col-span-2 order-1 lg:order-2\">\n<div class=\"bg-white rounded-xl shadow-lg p-6\">\n<div class=\"flex justify-between items-center mb-4\">\n<h2 class=\"text-xl font-bold text-dark flex items-center\">\n                            <i class=\"fa fa-th text-primary mr-2\"><\/i>\u6570\u72ec\u68cb\u76d8<br \/>\n                        <\/h2>\n<div class=\"flex space-x-2\">\n                            <button id=\"clear\" class=\"bg-gray-200 hover:bg-gray-300 text-gray-800 py-2 px-4 rounded-lg font-medium btn-hover\"><br \/>\n                                <i class=\"fa fa-eraser mr-1\"><\/i>\u6e05\u9664<br \/>\n                            <\/button><br \/>\n                            <button id=\"check\" class=\"bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-lg font-medium btn-hover\"><br \/>\n                                <i class=\"fa fa-check mr-1\"><\/i>\u68c0\u67e5<br \/>\n                            <\/button>\n                        <\/div>\n<\/p><\/div>\n<p>                    <!-- \u6570\u72ec\u68cb\u76d8 --><\/p>\n<div class=\"flex justify-center mb-6\">\n<div id=\"sudoku-grid\" class=\"grid grid-cols-9 grid-rows-9 border-2 border-gray-600 rounded-md overflow-hidden\">\n                            <!-- \u6570\u72ec\u5355\u5143\u683c\u5c06\u7531JavaScript\u52a8\u6001\u751f\u6210 -->\n                        <\/div>\n<\/p><\/div>\n<p>                    <!-- \u6570\u5b57\u9009\u62e9\u5668 --><\/p>\n<div id=\"number-pad\" class=\"grid grid-cols-9 gap-2 max-w-md mx-auto mb-2\">\n                        <!-- \u6570\u5b57\u6309\u94ae\u5c06\u7531JavaScript\u52a8\u6001\u751f\u6210 -->\n                    <\/div>\n<p>                    <!-- \u6e38\u620f\u7ed3\u679c\u5f39\u7a97 --><\/p>\n<div id=\"result-modal\" class=\"fixed inset-0 bg-black\/50 flex items-center justify-center z-50 hidden opacity-0 transition-opacity duration-300\">\n<div class=\"bg-white rounded-xl shadow-2xl p-8 max-w-md w-full mx-4 transform transition-transform duration-300 scale-95\">\n<div class=\"text-center\">\n<div id=\"result-icon\" class=\"text-6xl mb-4\"><\/div>\n<h2 id=\"result-title\" class=\"text-2xl font-bold mb-2\"><\/h2>\n<p id=\"result-message\" class=\"text-gray-600 mb-6\">\n<p>                                <button id=\"play-again\" class=\"bg-primary hover:bg-primary\/90 text-white py-3 px-8 rounded-lg font-medium btn-hover\"><br \/>\n                                    \u518d\u73a9\u4e00\u6b21<br \/>\n                                <\/button>\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>        <!-- \u9875\u811a --><\/p>\n<footer class=\"mt-12 text-center text-gray-500 text-sm\">\n<p>\u00a9 2025 \u6570\u72ec\u6e38\u620f | \u953b\u70bc\u903b\u8f91\u601d\u7ef4\u7684\u7ecf\u5178\u6570\u5b57\u6e38\u620f<\/p>\n<\/footer><\/div>\n<p>    <script>\n        document.addEventListener('DOMContentLoaded', () => {\n            \/\/ \u6e38\u620f\u72b6\u6001\n            let board = []; \/\/ \u5b58\u50a8\u5b8c\u6574\u7684\u6570\u72ec\u89e3\n            let puzzle = []; \/\/ \u5b58\u50a8\u5f53\u524d\u8c1c\u9898\uff08\u7528\u6237\u770b\u5230\u7684\uff09\n            let solution = []; \/\/ \u5b58\u50a8\u6b63\u786e\u7b54\u6848\n            let selectedCell = null; \/\/ \u5f53\u524d\u9009\u4e2d\u7684\u5355\u5143\u683c\n            let timer = null; \/\/ \u8ba1\u65f6\u5668\n            let timeElapsed = 0; \/\/ \u5df2\u7528\u65f6\u95f4\uff08\u79d2\uff09\n            let gameStarted = false; \/\/ \u6e38\u620f\u662f\u5426\u5df2\u5f00\u59cb<\/p>\n<p>            \/\/ \u521d\u59cb\u5316\u6570\u72ec\u68cb\u76d8\n            function initializeBoard() {\n                const grid = document.getElementById('sudoku-grid');\n                grid.innerHTML = '';<\/p>\n<p>                \/\/ \u521b\u5efa81\u4e2a\u5355\u5143\u683c\n                for (let i = 0; i < 81; i++) {\n                    const row = Math.floor(i \/ 9);\n                    const col = i % 9;\n                    \n                    \/\/ \u8ba1\u7b97\u5355\u5143\u683c\u6837\u5f0f\uff08\u5904\u74063x3\u7f51\u683c\u7684\u7c97\u7ebf\uff09\n                    let cellClass = 'cell-border w-10 h-10 md:w-12 md:h-12 flex items-center justify-center text-lg md:text-xl font-medium';\n                    \n                    \/\/ 3x3\u7f51\u683c\u5206\u9694\u7ebf\n                    if (row === 2 || row === 5) cellClass += ' border-b-2';\n                    if (col === 2 || col === 5) cellClass += ' border-r-2';\n                    \n                    const cell = document.createElement('div');\n                    cell.id = `cell-${row}-${col}`;\n                    cell.className = cellClass;\n                    cell.dataset.row = row;\n                    cell.dataset.col = col;\n                    \n                    \/\/ \u5355\u5143\u683c\u70b9\u51fb\u4e8b\u4ef6\n                    cell.addEventListener('click', () => selectCell(row, col));<\/p>\n<p>                    grid.appendChild(cell);\n                }<\/p>\n<p>                \/\/ \u521b\u5efa\u6570\u5b57\u9009\u62e9\u5668\n                const numberPad = document.getElementById('number-pad');\n                numberPad.innerHTML = '';<\/p>\n<p>                for (let i = 1; i <= 9; i++) {\n                    const button = document.createElement('button');\n                    button.className = 'bg-gray-100 hover:bg-gray-200 text-gray-800 rounded-md h-10 flex items-center justify-center font-bold transition-colors duration-200';\n                    button.textContent = i;\n                    \n                    \/\/ \u6570\u5b57\u6309\u94ae\u70b9\u51fb\u4e8b\u4ef6\n                    button.addEventListener('click', () => {\n                        if (selectedCell) {\n                            const row = selectedCell.dataset.row;\n                            const col = selectedCell.dataset.col;\n                            fillCell(row, col, i);\n                        }\n                    });<\/p>\n<p>                    numberPad.appendChild(button);\n                }\n            }<\/p>\n<p>            \/\/ \u9009\u62e9\u5355\u5143\u683c\n            function selectCell(row, col) {\n                \/\/ \u53d6\u6d88\u4e4b\u524d\u9009\u4e2d\u7684\u5355\u5143\u683c\n                if (selectedCell) {\n                    selectedCell.classList.remove('cell-selected');\n                }<\/p>\n<p>                \/\/ \u9009\u62e9\u65b0\u5355\u5143\u683c\n                selectedCell = document.getElementById(`cell-${row}-${col}`);<\/p>\n<p>                \/\/ \u5982\u679c\u662f\u9884\u586b\u7684\u6570\u5b57\uff0c\u4e0d\u5141\u8bb8\u9009\u62e9\n                if (selectedCell.classList.contains('text-gray-800')) {\n                    selectedCell = null;\n                    return;\n                }<\/p>\n<p>                \/\/ \u9ad8\u4eae\u65b0\u9009\u4e2d\u7684\u5355\u5143\u683c\n                if (selectedCell) {\n                    selectedCell.classList.add('cell-selected');<\/p>\n<p>                    \/\/ \u9ad8\u4eae\u540c\u884c\u3001\u540c\u5217\u548c\u540c\u4e00\u4e2a3x3\u7f51\u683c\u7684\u5355\u5143\u683c\n                    highlightRelatedCells(row, col);\n                }\n            }<\/p>\n<p>            \/\/ \u9ad8\u4eae\u76f8\u5173\u5355\u5143\u683c\n            function highlightRelatedCells(row, col) {\n                \/\/ \u6e05\u9664\u4e4b\u524d\u7684\u9ad8\u4eae\n                document.querySelectorAll('.cell-highlight').forEach(cell => {\n                    cell.classList.remove('cell-highlight');\n                });<\/p>\n<p>                \/\/ \u9ad8\u4eae\u540c\u884c\u3001\u540c\u5217\u548c\u540c\u4e00\u4e2a3x3\u7f51\u683c\u7684\u5355\u5143\u683c\n                for (let i = 0; i < 9; i++) {\n                    \/\/ \u540c\u884c\n                    const rowCell = document.getElementById(`cell-${row}-${i}`);\n                    if (rowCell !== selectedCell &#038;&#038; !rowCell.classList.contains('text-gray-800')) {\n                        rowCell.classList.add('cell-highlight');\n                    }\n                    \n                    \/\/ \u540c\u5217\n                    const colCell = document.getElementById(`cell-${i}-${col}`);\n                    if (colCell !== selectedCell &#038;&#038; !colCell.classList.contains('text-gray-800')) {\n                        colCell.classList.add('cell-highlight');\n                    }\n                }\n                \n                \/\/ \u540c\u4e00\u4e2a3x3\u7f51\u683c\n                const startRow = Math.floor(row \/ 3) * 3;\n                const startCol = Math.floor(col \/ 3) * 3;\n                \n                for (let i = startRow; i < startRow + 3; i++) {\n                    for (let j = startCol; j < startCol + 3; j++) {\n                        const cell = document.getElementById(`cell-${i}-${j}`);\n                        if (cell !== selectedCell &#038;&#038; !cell.classList.contains('text-gray-800')) {\n                            cell.classList.add('cell-highlight');\n                        }\n                    }\n                }\n            }\n\n            \/\/ \u586b\u5145\u5355\u5143\u683c\n            function fillCell(row, col, number) {\n                if (puzzle[row][col] !== 0) return; \/\/ \u5982\u679c\u5355\u5143\u683c\u5df2\u7ecf\u6709\u6570\u5b57\uff0c\u4e0d\u586b\u5145\n                \n                const cell = document.getElementById(`cell-${row}-${col}`);\n                cell.textContent = number;\n                cell.classList.add('text-primary');\n                \n                \/\/ \u68c0\u67e5\u662f\u5426\u4e0e\u7b54\u6848\u4e00\u81f4\n                if (number === solution[row][col]) {\n                    cell.classList.remove('cell-error');\n                    puzzle[row][col] = number;\n                } else {\n                    cell.classList.add('cell-error');\n                }\n                \n                \/\/ \u68c0\u67e5\u6e38\u620f\u662f\u5426\u5b8c\u6210\n                checkGameCompletion();\n            }\n\n            \/\/ \u6e05\u9664\u5355\u5143\u683c\n            function clearCell(row, col) {\n                const cell = document.getElementById(`cell-${row}-${col}`);\n                if (cell.classList.contains('text-gray-800')) return; \/\/ \u5982\u679c\u662f\u9884\u586b\u7684\u6570\u5b57\uff0c\u4e0d\u6e05\u9664\n                \n                cell.textContent = '';\n                cell.classList.remove('text-primary', 'cell-error');\n                puzzle[row][col] = 0;\n            }\n\n            \/\/ \u751f\u6210\u65b0\u7684\u6570\u72ec\u6e38\u620f\n            function generateNewGame(difficulty = 'medium') {\n                \/\/ \u505c\u6b62\u4e4b\u524d\u7684\u8ba1\u65f6\u5668\n                if (timer) {\n                    clearInterval(timer);\n                    timer = null;\n                }\n                \n                \/\/ \u91cd\u7f6e\u6e38\u620f\u72b6\u6001\n                timeElapsed = 0;\n                document.getElementById('timer').textContent = '00:00';\n                document.getElementById('progress').textContent = '0%';\n                gameStarted = true;\n                \n                \/\/ \u751f\u6210\u5b8c\u6574\u7684\u6570\u72ec\u89e3\n                solution = generateSolution();\n                board = JSON.parse(JSON.stringify(solution));\n                \n                \/\/ \u6839\u636e\u96be\u5ea6\u79fb\u9664\u4e00\u4e9b\u6570\u5b57\u751f\u6210\u8c1c\u9898\n                puzzle = removeNumbers(board, difficulty);\n                \n                \/\/ \u6e32\u67d3\u6570\u72ec\u8c1c\u9898\n                renderPuzzle();\n                \n                \/\/ \u5f00\u59cb\u8ba1\u65f6\n                startTimer();\n                \n                \/\/ \u9690\u85cf\u7ed3\u679c\u5f39\u7a97\n                hideResultModal();\n            }\n\n            \/\/ \u751f\u6210\u5b8c\u6574\u7684\u6570\u72ec\u89e3\n            function generateSolution() {\n                const solution = Array(9).fill().map(() => Array(9).fill(0));<\/p>\n<p>                \/\/ \u4f7f\u7528\u56de\u6eaf\u6cd5\u751f\u6210\u6570\u72ec\u89e3\n                function backtrack(row, col) {\n                    if (row === 9) return true;<\/p>\n<p>                    const nextRow = col === 8 ? row + 1 : row;\n                    const nextCol = col === 8 ? 0 : col + 1;<\/p>\n<p>                    \/\/ \u968f\u673a\u5c1d\u8bd5\u6570\u5b571-9\n                    const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];\n                    shuffleArray(numbers);<\/p>\n<p>                    for (const num of numbers) {\n                        if (isValid(solution, row, col, num)) {\n                            solution[row][col] = num;<\/p>\n<p>                            if (backtrack(nextRow, nextCol)) {\n                                return true;\n                            }<\/p>\n<p>                            solution[row][col] = 0;\n                        }\n                    }<\/p>\n<p>                    return false;\n                }<\/p>\n<p>                backtrack(0, 0);\n                return solution;\n            }<\/p>\n<p>            \/\/ \u68c0\u67e5\u6570\u5b57\u662f\u5426\u53ef\u4ee5\u653e\u5728\u6307\u5b9a\u4f4d\u7f6e\n            function isValid(grid, row, col, num) {\n                \/\/ \u68c0\u67e5\u884c\n                for (let i = 0; i < 9; i++) {\n                    if (grid[row][i] === num) return false;\n                }\n                \n                \/\/ \u68c0\u67e5\u5217\n                for (let i = 0; i < 9; i++) {\n                    if (grid[i][col] === num) return false;\n                }\n                \n                \/\/ \u68c0\u67e53x3\u7f51\u683c\n                const startRow = Math.floor(row \/ 3) * 3;\n                const startCol = Math.floor(col \/ 3) * 3;\n                \n                for (let i = startRow; i < startRow + 3; i++) {\n                    for (let j = startCol; j < startCol + 3; j++) {\n                        if (grid[i][j] === num) return false;\n                    }\n                }\n                \n                return true;\n            }\n\n            \/\/ \u968f\u673a\u6253\u4e71\u6570\u7ec4\n            function shuffleArray(array) {\n                for (let i = array.length - 1; i > 0; i--) {\n                    const j = Math.floor(Math.random() * (i + 1));\n                    [array[i], array[j]] = [array[j], array[i]];\n                }\n            }<\/p>\n<p>            \/\/ \u6839\u636e\u96be\u5ea6\u79fb\u9664\u4e00\u4e9b\u6570\u5b57\n            function removeNumbers(board, difficulty) {\n                const puzzle = JSON.parse(JSON.stringify(board));\n                let cellsToRemove = 0;<\/p>\n<p>                \/\/ \u6839\u636e\u96be\u5ea6\u786e\u5b9a\u8981\u79fb\u9664\u7684\u6570\u5b57\u6570\u91cf\n                switch(difficulty) {\n                    case 'easy':\n                        cellsToRemove = 30;\n                        break;\n                    case 'medium':\n                        cellsToRemove = 40;\n                        break;\n                    case 'hard':\n                        cellsToRemove = 50;\n                        break;\n                    case 'expert':\n                        cellsToRemove = 60;\n                        break;\n                    default:\n                        cellsToRemove = 40;\n                }<\/p>\n<p>                \/\/ \u968f\u673a\u9009\u62e9\u8981\u79fb\u9664\u7684\u5355\u5143\u683c\n                const cells = [];\n                for (let i = 0; i < 81; i++) {\n                    cells.push(i);\n                }\n                shuffleArray(cells);\n                \n                \/\/ \u79fb\u9664\u9009\u5b9a\u7684\u5355\u5143\u683c\n                for (let i = 0; i < cellsToRemove; i++) {\n                    const cell = cells[i];\n                    const row = Math.floor(cell \/ 9);\n                    const col = cell % 9;\n                    puzzle[row][col] = 0;\n                }\n                \n                return puzzle;\n            }\n\n            \/\/ \u6e32\u67d3\u6570\u72ec\u8c1c\u9898\n            function renderPuzzle() {\n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        const cell = document.getElementById(`cell-${i}-${j}`);\n                        \n                        if (puzzle[i][j] !== 0) {\n                            cell.textContent = puzzle[i][j];\n                            cell.classList.add('text-gray-800');\n                        } else {\n                            cell.textContent = '';\n                            cell.classList.remove('text-gray-800', 'text-primary', 'cell-error');\n                        }\n                    }\n                }\n                \n                \/\/ \u91cd\u7f6e\u9009\u4e2d\u5355\u5143\u683c\n                if (selectedCell) {\n                    selectedCell.classList.remove('cell-selected');\n                    selectedCell = null;\n                }\n                \n                \/\/ \u6e05\u9664\u9ad8\u4eae\n                document.querySelectorAll('.cell-highlight').forEach(cell => {\n                    cell.classList.remove('cell-highlight');\n                });\n            }<\/p>\n<p>            \/\/ \u5f00\u59cb\u8ba1\u65f6\u5668\n            function startTimer() {\n                if (timer) clearInterval(timer);<\/p>\n<p>                timer = setInterval(() => {\n                    timeElapsed++;\n                    updateTimerDisplay();\n                }, 1000);\n            }<\/p>\n<p>            \/\/ \u66f4\u65b0\u8ba1\u65f6\u5668\u663e\u793a\n            function updateTimerDisplay() {\n                const minutes = Math.floor(timeElapsed \/ 60).toString().padStart(2, '0');\n                const seconds = (timeElapsed % 60).toString().padStart(2, '0');\n                document.getElementById('timer').textContent = `${minutes}:${seconds}`;\n            }<\/p>\n<p>            \/\/ \u68c0\u67e5\u6e38\u620f\u662f\u5426\u5b8c\u6210\n            function checkGameCompletion() {\n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        if (puzzle[i][j] === 0 || puzzle[i][j] !== solution[i][j]) {\n                            updateProgress();\n                            return false;\n                        }\n                    }\n                }\n                \n                \/\/ \u6e38\u620f\u5b8c\u6210\n                clearInterval(timer);\n                timer = null;\n                showResultModal(true);\n                return true;\n            }\n\n            \/\/ \u66f4\u65b0\u5b8c\u6210\u5ea6\n            function updateProgress() {\n                let filledCells = 0;\n                const totalCells = 81;\n                \n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        if (puzzle[i][j] !== 0) {\n                            filledCells++;\n                        }\n                    }\n                }\n                \n                const progress = Math.round((filledCells \/ totalCells) * 100);\n                document.getElementById('progress').textContent = `${progress}%`;\n            }\n\n            \/\/ \u663e\u793a\u63d0\u793a\n            function showHint() {\n                if (!gameStarted) return;\n                \n                \/\/ \u627e\u5230\u4e00\u4e2a\u7a7a\u5355\u5143\u683c\n                let emptyCells = [];\n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        if (puzzle[i][j] === 0) {\n                            emptyCells.push({ row: i, col: j });\n                        }\n                    }\n                }\n                \n                if (emptyCells.length === 0) return;\n                \n                \/\/ \u968f\u673a\u9009\u62e9\u4e00\u4e2a\u7a7a\u5355\u5143\u683c\n                const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];\n                const { row, col } = randomCell;\n                \n                \/\/ \u586b\u5165\u6b63\u786e\u7684\u6570\u5b57\n                fillCell(row, col, solution[row][col]);\n                \n                \/\/ \u9009\u4e2d\u8fd9\u4e2a\u5355\u5143\u683c\n                selectCell(row, col);\n            }\n\n            \/\/ \u663e\u793a\u7b54\u6848\n            function showSolution() {\n                if (!gameStarted) return;\n                \n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        if (puzzle[i][j] === 0) {\n                            fillCell(i, j, solution[i][j]);\n                        }\n                    }\n                }\n                \n                \/\/ \u505c\u6b62\u8ba1\u65f6\u5668\n                clearInterval(timer);\n                timer = null;\n            }\n\n            \/\/ \u68c0\u67e5\u7b54\u6848\n            function checkSolution() {\n                if (!gameStarted) return;\n                \n                let hasError = false;\n                \n                for (let i = 0; i < 9; i++) {\n                    for (let j = 0; j < 9; j++) {\n                        const cell = document.getElementById(`cell-${i}-${j}`);\n                        \n                        \/\/ \u8df3\u8fc7\u9884\u586b\u7684\u5355\u5143\u683c\n                        if (cell.classList.contains('text-gray-800')) continue;\n                        \n                        \/\/ \u68c0\u67e5\u975e\u7a7a\u5355\u5143\u683c\n                        if (puzzle[i][j] !== 0) {\n                            if (puzzle[i][j] !== solution[i][j]) {\n                                cell.classList.add('cell-error');\n                                hasError = true;\n                            } else {\n                                cell.classList.remove('cell-error');\n                            }\n                        }\n                    }\n                }\n                \n                \/\/ \u5982\u679c\u6ca1\u6709\u9519\u8bef\uff0c\u68c0\u67e5\u662f\u5426\u5b8c\u6210\n                if (!hasError &#038;&#038; checkGameCompletion()) {\n                    showResultModal(true);\n                } else if (hasError) {\n                    showResultModal(false);\n                }\n            }\n\n            \/\/ \u663e\u793a\u7ed3\u679c\u5f39\u7a97\n            function showResultModal(isSuccess) {\n                const modal = document.getElementById('result-modal');\n                const icon = document.getElementById('result-icon');\n                const title = document.getElementById('result-title');\n                const message = document.getElementById('result-message');\n                \n                if (isSuccess) {\n                    icon.className = 'fa fa-trophy text-6xl text-accent mb-4';\n                    title.textContent = '\u606d\u559c\u4f60\uff01';\n                    title.className = 'text-2xl font-bold mb-2 text-secondary';\n                    message.textContent = `\u4f60\u5b8c\u6210\u4e86\u6570\u72ec\u6e38\u620f\uff0c\u7528\u65f6 ${Math.floor(timeElapsed \/ 60)} \u5206 ${timeElapsed % 60} \u79d2\u3002`;\n                } else {\n                    icon.className = 'fa fa-times-circle text-6xl text-red-500 mb-4';\n                    title.textContent = '\u518d\u8bd5\u4e00\u6b21';\n                    title.className = 'text-2xl font-bold mb-2 text-red-600';\n                    message.textContent = '\u4f60\u7684\u7b54\u6848\u4e2d\u5305\u542b\u9519\u8bef\uff0c\u8bf7\u68c0\u67e5\u540e\u7ee7\u7eed\u3002';\n                }\n                \n                \/\/ \u663e\u793a\u5f39\u7a97\u5e76\u6dfb\u52a0\u52a8\u753b\n                modal.classList.remove('hidden');\n                setTimeout(() => {\n                    modal.classList.add('opacity-100');\n                    modal.querySelector('div').classList.add('scale-100');\n                    modal.querySelector('div').classList.remove('scale-95');\n                }, 10);\n            }<\/p>\n<p>            \/\/ \u9690\u85cf\u7ed3\u679c\u5f39\u7a97\n            function hideResultModal() {\n                const modal = document.getElementById('result-modal');\n                modal.classList.remove('opacity-100');\n                modal.querySelector('div').classList.remove('scale-100');\n                modal.querySelector('div').classList.add('scale-95');<\/p>\n<p>                setTimeout(() => {\n                    modal.classList.add('hidden');\n                }, 300);\n            }<\/p>\n<p>            \/\/ \u4e8b\u4ef6\u76d1\u542c\n            document.getElementById('new-game').addEventListener('click', () => {\n                const difficulty = document.getElementById('difficulty').value;\n                generateNewGame(difficulty);\n            });<\/p>\n<p>            document.getElementById('hint').addEventListener('click', showHint);\n            document.getElementById('solve').addEventListener('click', showSolution);\n            document.getElementById('clear').addEventListener('click', () => {\n                if (selectedCell) {\n                    const row = selectedCell.dataset.row;\n                    const col = selectedCell.dataset.col;\n                    clearCell(row, col);\n                }\n            });\n            document.getElementById('check').addEventListener('click', checkSolution);\n            document.getElementById('play-again').addEventListener('click', () => {\n                const difficulty = document.getElementById('difficulty').value;\n                generateNewGame(difficulty);\n            });<\/p>\n<p>            \/\/ \u952e\u76d8\u4e8b\u4ef6\u76d1\u542c\n            document.addEventListener('keydown', (e) => {\n                if (!selectedCell) return;<\/p>\n<p>                const row = parseInt(selectedCell.dataset.row);\n                const col = parseInt(selectedCell.dataset.col);<\/p>\n<p>                \/\/ \u6570\u5b57\u952e1-9\n                if (e.key >= '1' && e.key <= '9') {\n                    fillCell(row, col, parseInt(e.key));\n                }\n                \n                \/\/ \u5220\u9664\u952e\u6216\u9000\u683c\u952e\n                if (e.key === 'Delete' || e.key === 'Backspace') {\n                    clearCell(row, col);\n                }\n                \n                \/\/ \u65b9\u5411\u952e\u79fb\u52a8\u9009\u4e2d\u5355\u5143\u683c\n                if (e.key === 'ArrowUp' &#038;&#038; row > 0) {\n                    selectCell(row - 1, col);\n                } else if (e.key === 'ArrowDown' && row < 8) {\n                    selectCell(row + 1, col);\n                } else if (e.key === 'ArrowLeft' &#038;&#038; col > 0) {\n                    selectCell(row, col - 1);\n                } else if (e.key === 'ArrowRight' && col < 8) {\n                    selectCell(row, col + 1);\n                }\n            });\n\n            \/\/ \u521d\u59cb\u5316\u6e38\u620f\n            initializeBoard();\n            generateNewGame();\n        });\n    <\/script><\/p>\n<p>    <\/body><\/html><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6570\u72ec\u6e38\u620f \u6570\u72ec Sudoku \u953b\u70bc\u903b\u8f91\u601d\u7ef4\u7684\u7ecf\u5178\u6570\u5b57\u6e38\u620f\uff0c\u5c06\u6570\u5b571-9\u586b\u5165\u7a7a\u683c\uff0c &hellip;<\/p>\n<p class=\"read-more\"> <a class=\"more-link\" href=\"http:\/\/tommy.iapps.hk\/?page_id=257\"> <span class=\"screen-reader-text\">Sudoku<\/span> \u95b1\u8b80\u66f4\u591a &raquo;<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-257","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/P49oqL-49","_links":{"self":[{"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/pages\/257","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=257"}],"version-history":[{"count":2,"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/pages\/257\/revisions"}],"predecessor-version":[{"id":259,"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=\/wp\/v2\/pages\/257\/revisions\/259"}],"wp:attachment":[{"href":"http:\/\/tommy.iapps.hk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=257"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}