<!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>智能数独大师 - 多规则版</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

        }

 

        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            min-height: 100vh;

            display: flex;

            justify-content: center;

            align-items: center;

            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

            transition: background 1s ease;

            overflow-x: hidden;

            padding: 10px;

        }

 

        /* 背景动画粒子 */

        .particles {

            position: fixed;

            top: 0;

            left: 0;

            width: 100%;

            height: 100%;

            pointer-events: none;

            overflow: hidden;

            z-index: 0;

        }

 

        .particle {

            position: absolute;

            width: 4px;

            height: 4px;

            background: rgba(255, 255, 255, 0.5);

            border-radius: 50%;

            animation: float 15s infinite linear;

        }

 

        @keyframes float {

            from {

                transform: translateY(100vh) rotate(0deg);

                opacity: 0;

            }

            10% {

                opacity: 1;

            }

            90% {

                opacity: 1;

            }

            to {

                transform: translateY(-100vh) rotate(360deg);

                opacity: 0;

            }

        }

 

        .container {

            position: relative;

            z-index: 1;

            background: rgba(255, 255, 255, 0.95);

            border-radius: 20px;

            padding: 20px;

            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);

            backdrop-filter: blur(10px);

            max-width: 1200px;

            width: 100%;

            animation: slideIn 0.5s ease;

        }

 

        @keyframes slideIn {

            from {

                opacity: 0;

                transform: translateY(-30px);

            }

            to {

                opacity: 1;

                transform: translateY(0);

            }

        }

 

        header {

            text-align: center;

            margin-bottom: 20px;

        }

 

        h1 {

            font-size: 2em;

            background: linear-gradient(135deg, #667eea, #764ba2);

            -webkit-background-clip: text;

            -webkit-text-fill-color: transparent;

            margin-bottom: 10px;

            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);

        }

 

        .game-area {

            display: flex;

            gap: 20px;

            flex-wrap: wrap;

            justify-content: center;

        }

 

        .sudoku-board {

            position: relative;

        }

 

        .sudoku-grid {

            display: grid;

            grid-template-columns: repeat(9, 1fr);

            gap: 0;

            border: 3px solid #333;

            background: #fff;

            border-radius: 10px;

            overflow: hidden;

            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);

        }

 

        .cell {

            width: 40px;

            height: 40px;

            border: 1px solid #ddd;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 18px;

            font-weight: bold;

            cursor: pointer;

            transition: all 0.3s ease;

            position: relative;

            background: white;

        }

 

        .cell:hover {

            background: #f0f0f0;

            transform: scale(1.05);

            z-index: 10;

        }

 

        .cell.selected {

            background: #e3f2fd;

            box-shadow: inset 0 0 0 2px #2196f3;

        }

 

        .cell.highlighted {

            background: #fff3e0;

        }

 

        .cell.same-number {

            background: #f3e5f5;

        }

 

        .cell.fixed {

            background: #f5f5f5;

            color: #333;

            cursor: default;

            font-weight: 900;

        }

 

        .cell.user-input {

            color: #2196f3;

            font-weight: 600;

            background: #e8f5e9;

        }

 

        .cell.ai-solved {

            color: #4caf50;

            font-weight: 600;

        }

 

        .cell.error {

            background: #ffebee;

            color: #c62828;

            animation: shake 0.5s;

        }

 

        .cell.correct {

            animation: pulse 0.5s;

            background: #e8f5e9;

        }

 

        /* 特殊规则样式 */

        .cell.diagonal {

            background: #fff8e1;

        }

 

        .cell.window {

            background: #f3e5f5;

        }

 

        .cell.extra-area {

            background: #e0f2f1;

        }

 

        .cell.odd {

            background: #fce4ec;

        }

 

        .cell.even {

            background: #e1f5fe;

        }

 

        .cell.greater-than::after,

        .cell.less-than::after {

            position: absolute;

            font-size: 12px;

            color: #666;

        }

 

        .cell.greater-than::after {

            content: '>';

            right: 2px;

            top: 2px;

        }

 

        .cell.less-than::after {

            content: '<';

            left: 2px;

            top: 2px;

        }

 

        @keyframes shake {

            0%, 100% { transform: translateX(0); }

            25% { transform: translateX(-5px); }

            75% { transform: translateX(5px); }

        }

 

        @keyframes pulse {

            0% { transform: scale(1); }

            50% { transform: scale(1.1); }

            100% { transform: scale(1); }

        }

 

        /* 3x3 区块边框 */

        .cell:nth-child(3n) {

            border-right: 2px solid #333;

        }

 

        .cell:nth-child(n+19):nth-child(-n+27),

        .cell:nth-child(n+46):nth-child(-n+54) {

            border-bottom: 2px solid #333;

        }

 

        .controls {

            display: flex;

            flex-direction: column;

            gap: 15px;

            min-width: 250px;

        }

 

        /* 规则选择器 */

        .rule-selector {

            position: relative;

            margin-bottom: 15px;

        }

 

        .rule-dropdown {

            width: 100%;

            padding: 10px;

            border: 2px solid #ddd;

            border-radius: 8px;

            background: white;

            font-size: 14px;

            font-weight: 600;

            cursor: pointer;

            transition: all 0.3s ease;

            appearance: none;

            background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");

            background-repeat: no-repeat;

            background-position: right 10px center;

            background-size: 20px;

            padding-right: 40px;

        }

 

        .rule-dropdown:hover {

            border-color: #667eea;

            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2);

        }

 

        .rule-dropdown:focus {

            outline: none;

            border-color: #667eea;

            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);

        }

 

        .rule-info {

            margin-top: 5px;

            padding: 8px;

            background: #f5f5f5;

            border-radius: 6px;

            font-size: 12px;

            color: #666;

            display: none;

        }

 

        .rule-info.show {

            display: block;

        }

 

        .difficulty-selector {

            display: flex;

            gap: 5px;

            margin-bottom: 15px;

        }

 

        .difficulty-btn {

            flex: 1;

            padding: 8px;

            border: 2px solid #ddd;

            background: white;

            border-radius: 6px;

            cursor: pointer;

            transition: all 0.3s ease;

            font-weight: 600;

            font-size: 12px;

        }

 

        .difficulty-btn.active {

            background: linear-gradient(135deg, #667eea, #764ba2);

            color: white;

            border-color: #667eea;

        }

 

        .number-pad {

            display: grid;

            grid-template-columns: repeat(3, 1fr);

            gap: 8px;

        }

 

        .num-btn {

            padding: 12px;

            font-size: 18px;

            font-weight: bold;

            border: none;

            border-radius: 8px;

            background: linear-gradient(135deg, #667eea, #764ba2);

            color: white;

            cursor: pointer;

            transition: all 0.3s ease;

            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);

        }

 

        .num-btn:hover {

            transform: translateY(-2px);

            box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);

        }

 

        .num-btn:active {

            transform: translateY(0);

        }

 

        .action-buttons {

            display: grid;

            grid-template-columns: repeat(2, 1fr);

            gap: 8px;

        }

 

        .btn {

            padding: 10px 15px;

            border: none;

            border-radius: 8px;

            font-size: 12px;

            font-weight: 600;

            cursor: pointer;

            transition: all 0.3s ease;

            text-transform: uppercase;

            letter-spacing: 0.5px;

        }

 

        .btn-primary {

            background: linear-gradient(135deg, #4caf50, #45a049);

            color: white;

            box-shadow: 0 4px 15px rgba(76, 175, 80, 0.4);

        }

 

        .btn-secondary {

            background: linear-gradient(135deg, #ff9800, #f57c00);

            color: white;

            box-shadow: 0 4px 15px rgba(255, 152, 0, 0.4);

        }

 

        .btn-danger {

            background: linear-gradient(135deg, #f44336, #d32f2f);

            color: white;

            box-shadow: 0 4px 15px rgba(244, 67, 54, 0.4);

        }

 

        .btn-info {

            background: linear-gradient(135deg, #2196f3, #1976d2);

            color: white;

            box-shadow: 0 4px 15px rgba(33, 150, 243, 0.4);

        }

 

        .btn:hover {

            transform: translateY(-2px);

            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);

        }

 

        .stats {

            background: linear-gradient(135deg, #f5f5f5, #e0e0e0);

            padding: 15px;

            border-radius: 10px;

            box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.1);

        }

 

        .stat-item {

            display: flex;

            justify-content: space-between;

            margin-bottom: 8px;

            font-size: 14px;

        }

 

        .stat-label {

            color: #666;

            font-weight: 600;

        }

 

        .stat-value {

            color: #333;

            font-weight: bold;

        }

 

        .theme-selector {

            display: grid;

            grid-template-columns: repeat(6, 1fr);

            gap: 8px;

            margin-top: 15px;

        }

 

        .theme-btn {

            width: 30px;

            height: 30px;

            border-radius: 50%;

            border: 2px solid white;

            cursor: pointer;

            transition: all 0.3s ease;

            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);

        }

 

        .theme-btn:hover {

            transform: scale(1.2);

            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);

        }

 

        .notes-mode {

            display: flex;

            align-items: center;

            gap: 10px;

            padding: 10px;

            background: #f5f5f5;

            border-radius: 8px;

        }

 

        .toggle-switch {

            position: relative;

            width: 50px;

            height: 25px;

            background: #ccc;

            border-radius: 12px;

            cursor: pointer;

            transition: background 0.3s ease;

        }

 

        .toggle-switch.active {

            background: #4caf50;

        }

 

        .toggle-slider {

            position: absolute;

            top: 2px;

            left: 2px;

            width: 21px;

            height: 21px;

            background: white;

            border-radius: 50%;

            transition: transform 0.3s ease;

            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);

        }

 

        .toggle-switch.active .toggle-slider {

            transform: translateX(25px);

        }

 

        .message {

            position: fixed;

            top: 20px;

            right: 20px;

            padding: 12px 20px;

            background: white;

            border-radius: 10px;

            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);

            z-index: 1000;

            animation: slideInRight 0.5s ease;

            display: none;

            font-size: 14px;

        }

 

        @keyframes slideInRight {

            from {

                transform: translateX(100%);

                opacity: 0;

            }

            to {

                transform: translateX(0);

                opacity: 1;

            }

        }

 

        .message.success {

            border-left: 5px solid #4caf50;

        }

 

        .message.error {

            border-left: 5px solid #f44336;

        }

 

        .message.info {

            border-left: 5px solid #2196f3;

        }

 

        .progress-bar {

            width: 100%;

            height: 8px;

            background: #e0e0e0;

            border-radius: 4px;

            overflow: hidden;

            margin-top: 8px;

        }

 

        .progress-fill {

            height: 100%;

            background: linear-gradient(90deg, #4caf50, #8bc34a);

            transition: width 0.5s ease;

            border-radius: 4px;

        }

 

        /* 移动端优化 */

        @media (max-width: 768px) {

            .container {

                padding: 15px;

            }

 

            h1 {

                font-size: 1.5em;

            }

 

            .game-area {

                flex-direction: column;

                gap: 15px;

            }

 

            .cell {

                width: 32px;

                height: 32px;

                font-size: 14px;

            }

 

            .controls {

                min-width: 100%;

            }

 

            .number-pad {

                gap: 5px;

            }

 

            .num-btn {

                padding: 10px;

                font-size: 16px;

            }

 

            .action-buttons {

                grid-template-columns: repeat(3, 1fr);

                gap: 5px;

            }

 

            .btn {

                padding: 8px 10px;

                font-size: 11px;

            }

 

            .difficulty-selector {

                gap: 3px;

            }

 

            .difficulty-btn {

                padding: 6px;

                font-size: 11px;

            }

 

            .theme-selector {

                grid-template-columns: repeat(4, 1fr);

                gap: 5px;

            }

 

            .theme-btn {

                width: 25px;

                height: 25px;

            }

 

            .stats {

                padding: 10px;

            }

 

            .stat-item {

                font-size: 12px;

                margin-bottom: 5px;

            }

 

            .notes-mode {

                padding: 8px;

                font-size: 14px;

            }

 

            .rule-dropdown {

                font-size: 12px;

                padding: 8px;

            }

        }

 

        @media (max-width: 480px) {

            .cell {

                width: 28px;

                height: 28px;

                font-size: 12px;

            }

 

            .action-buttons {

                grid-template-columns: repeat(2, 1fr);

            }

 

            .theme-selector {

                grid-template-columns: repeat(3, 1fr);

            }

        }

    </style>

</head>

<body>

    <div class="particles" id="particles"></div>

    

    <div class="container">

        <header>

            <h1>🎮 智能数独大师</h1>

            <p style="color: #666; font-size: 14px;">多规则挑战,AI辅助解题</p>

        </header>

 

        <div class="game-area">

            <div class="sudoku-board">

                <div class="sudoku-grid" id="sudokuGrid"></div>

            </div>

 

            <div class="controls">

                <!-- 规则选择器 -->

                <div class="rule-selector">

                    <select class="rule-dropdown" id="ruleSelector">

                        <option value="standard">🎯 标准数独</option>

                        <option value="diagonal">🔸 对角线数独</option>

                        <option value="window">🪟 窗口数独</option>

                        <option value="extra">🎨 额外区域数独</option>

                        <option value="odd-even">⚡ 奇偶数独</option>

                        <option value="consecutive">🔗 连续数独</option>

                        <option value="inequality">📊 不等号数独</option>

                        <option value="killer">🔪 杀手数独</option>

                        <option value="irregular">🌀 不规则数独</option>

                        <option value="center">⭐ 中心数独</option>

                        <option value="color">🌈 颜色数独</option>

                        <option value="mini">📱 迷你数独 (6x6)</option>

                        <option value="super">🏆 超级数独 (16x16)</option>

                        <option value="arrow">➡️ 箭头数独</option>

                        <option value="thermo">🌡️ 温度计数独</option>

                    </select>

                    <div class="rule-info" id="ruleInfo"></div>

                </div>

 

                <div class="difficulty-selector">

                    <button class="difficulty-btn active" data-level="easy">简单</button>

                    <button class="difficulty-btn" data-level="medium">中等</button>

                    <button class="difficulty-btn" data-level="hard">困难</button>

                    <button class="difficulty-btn" data-level="expert">专家</button>

                </div>

 

                <div class="number-pad">

                    <button class="num-btn" data-num="1">1</button>

                    <button class="num-btn" data-num="2">2</button>

                    <button class="num-btn" data-num="3">3</button>

                    <button class="num-btn" data-num="4">4</button>

                    <button class="num-btn" data-num="5">5</button>

                    <button class="num-btn" data-num="6">6</button>

                    <button class="num-btn" data-num="7">7</button>

                    <button class="num-btn" data-num="8">8</button>

                    <button class="num-btn" data-num="9">9</button>

                </div>

 

                <div class="action-buttons">

                    <button class="btn btn-primary" id="newGameBtn">新游戏</button>

                    <button class="btn btn-secondary" id="hintBtn">提示</button>

                    <button class="btn btn-info" id="aiSolveBtn">AI解题</button>

                    <button class="btn btn-danger" id="clearBtn">清除</button>

                    <button class="btn btn-secondary" id="undoBtn">撤销</button>

                    <button class="btn btn-secondary" id="redoBtn">重做</button>

                    <button class="btn btn-primary" id="checkBtn">检查</button>

                    <button class="btn btn-info" id="pauseBtn">暂停</button>

                </div>

 

                <div class="notes-mode">

                    <span style="font-size: 14px;">笔记模式:</span>

                    <div class="toggle-switch" id="notesToggle">

                        <div class="toggle-slider"></div>

                    </div>

                </div>

 

                <div class="stats">

                    <div class="stat-item">

                        <span class="stat-label">⏱️ 时间:</span>

                        <span class="stat-value" id="timer">00:00</span>

                    </div>

                    <div class="stat-item">

                        <span class="stat-label">💡 提示:</span>

                        <span class="stat-value" id="hints">3</span>

                    </div>

                    <div class="stat-item">

                        <span class="stat-label">❌ 错误:</span>

                        <span class="stat-value" id="mistakes">0/3</span>

                    </div>

                    <div class="stat-item">

                        <span class="stat-label">📊 进度:</span>

                        <span class="stat-value" id="progress">0%</span>

                    </div>

                    <div class="progress-bar">

                        <div class="progress-fill" id="progressBar" style="width: 0%"></div>

                    </div>

                </div>

 

                <div class="theme-selector">

                    <div class="theme-btn" style="background: linear-gradient(135deg, #667eea, #764ba2)" data-theme="purple"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #f093fb, #f5576c)" data-theme="pink"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #4facfe, #00f2fe)" data-theme="blue"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #43e97b, #38f9d7)" data-theme="green"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #fa709a, #fee140)" data-theme="sunset"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #30cfd0, #330867)" data-theme="ocean"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #a8edea, #fed6e3)" data-theme="pastel"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #ff9a9e, #fecfef)" data-theme="coral"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #ffecd2, #fcb69f)" data-theme="peach"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #a1c4fd, #c2e9fb)" data-theme="sky"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #d299c2, #fef9d7)" data-theme="lavender"></div>

                    <div class="theme-btn" style="background: linear-gradient(135deg, #89f7fe, #66a6ff)" data-theme="cyan"></div>

                </div>

            </div>

        </div>

    </div>

 

    <div class="message" id="message"></div>

 

    <script>

        class SudokuGame {

            constructor() {

                this.grid = [];

                this.solution = [];

                this.initialGrid = [];

                this.selectedCell = null;

                this.difficulty = 'easy';

                this.notesMode = false;

                this.hints = 3;

                this.mistakes = 0;

                this.history = [];

                this.historyIndex = -1;

                this.timer = 0;

                this.timerInterval = null;

                this.isPaused = false;

                this.aiSolving = false;

                this.currentRule = 'standard';

                this.gridSize = 9;

                

                this.rules = {

                    standard: {

                        name: '标准数独',

                        description: '每行、每列、每个3x3宫格内数字1-9不重复',

                        gridSize: 9

                    },

                    diagonal: {

                        name: '对角线数独',

                        description: '标准规则 + 两条对角线数字1-9不重复',

                        gridSize: 9

                    },

                    window: {

                        name: '窗口数独',

                        description: '标准规则 + 四个2x2窗口内数字不重复',

                        gridSize: 9

                    },

                    extra: {

                        name: '额外区域数独',

                        description: '标准规则 + 指定额外区域内数字不重复',

                        gridSize: 9

                    },

                    'odd-even': {

                        name: '奇偶数独',

                        description: '标准规则 + 指定格子只能是奇数或偶数',

                        gridSize: 9

                    },

                    consecutive: {

                        name: '连续数独',

                        description: '标准规则 + 相邻标记格子数字差为1',

                        gridSize: 9

                    },

                    inequality: {

                        name: '不等号数独',

                        description: '标准规则 + 相邻格子有大小关系约束',

                        gridSize: 9

                    },

                    killer: {

                        name: '杀手数独',

                        description: '标准规则 + 虚线框内数字和等于指定值',

                        gridSize: 9

                    },

                    irregular: {

                        name: '不规则数独',

                        description: '每行、每列数字不重复,但宫格形状不规则',

                        gridSize: 9

                    },

                    center: {

                        name: '中心数独',

                        description: '标准规则 + 中心3x3区域数字不重复',

                        gridSize: 9

                    },

                    color: {

                        name: '颜色数独',

                        description: '标准规则 + 相同颜色格子数字不重复',

                        gridSize: 9

                    },

                    mini: {

                        name: '迷你数独',

                        description: '6x6网格,每行、每列、每个2x3宫格内数字1-6不重复',

                        gridSize: 6

                    },

                    super: {

                        name: '超级数独',

                        description: '16x16网格,使用数字1-9和字母A-G',

                        gridSize: 16

                    },

                    arrow: {

                        name: '箭头数独',

                        description: '标准规则 + 箭头指向格子数字和等于箭头起点数字',

                        gridSize: 9

                    },

                    thermo: {

                        name: '温度计数独',

                        description: '标准规则 + 温度计上数字递增',

                        gridSize: 9

                    }

                };

                

                this.themes = {

                    purple: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',

                    pink: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',

                    blue: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',

                    green: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',

                    sunset: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)',

                    ocean: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)',

                    pastel: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)',

                    coral: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)',

                    peach: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)',

                    sky: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',

                    lavender: 'linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)',

                    cyan: 'linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)'

                };

                

                this.init();

            }

 

            init() {

                this.setupRuleSelector();

                this.createGrid();

                this.setupEventListeners();

                this.createParticles();

                this.newGame();

                this.startTimer();

            }

 

            setupRuleSelector() {

                const ruleSelector = document.getElementById('ruleSelector');

                const ruleInfo = document.getElementById('ruleInfo');

                

                ruleSelector.addEventListener('change', (e) => {

                    this.currentRule = e.target.value;

                    const rule = this.rules[this.currentRule];

                    ruleInfo.textContent = rule.description;

                    ruleInfo.classList.add('show');

                    

                    setTimeout(() => {

                        ruleInfo.classList.remove('show');

                    }, 3000);

                    

                    this.newGame();

                });

            }

 

            createGrid() {

                const gridElement = document.getElementById('sudokuGrid');

                gridElement.innerHTML = '';

                

                const size = this.gridSize;

                gridElement.style.gridTemplateColumns = `repeat(${size}, 1fr)`;

                

                for (let i = 0; i < size * size; i++) {

                    const cell = document.createElement('div');

                    cell.className = 'cell';

                    cell.dataset.index = i;

                    cell.dataset.row = Math.floor(i / size);

                    cell.dataset.col = i % size;

                    

                    if (size === 9) {

                        cell.dataset.box = Math.floor((Math.floor(i / 9) / 3)) * 3 + Math.floor((i % 9) / 3);

                    } else if (size === 6) {

                        cell.dataset.box = Math.floor((Math.floor(i / 6) / 2)) * 3 + Math.floor((i % 6) / 3);

                    } else if (size === 16) {

                        cell.dataset.box = Math.floor((Math.floor(i / 16) / 4)) * 4 + Math.floor((i % 16) / 4);

                    }

                    

                    // 应用特殊规则样式

                    this.applyRuleStyles(cell, i);

                    

                    gridElement.appendChild(cell);

                }

            }

 

            applyRuleStyles(cell, index) {

                const row = Math.floor(index / this.gridSize);

                const col = index % this.gridSize;

                

                switch(this.currentRule) {

                    case 'diagonal':

                        if (row === col || row + col === this.gridSize - 1) {

                            cell.classList.add('diagonal');

                        }

                        break;

                    case 'window':

                        if ((row >= 1 && row <= 2 && col >= 1 && col <= 2) ||

                            (row >= 1 && row <= 2 && col >= 6 && col <= 7) ||

                            (row >= 6 && row <= 7 && col >= 1 && col <= 2) ||

                            (row >= 6 && row <= 7 && col >= 6 && col <= 7)) {

                            cell.classList.add('window');

                        }

                        break;

                    case 'center':

                        if (row >= 3 && row <= 5 && col >= 3 && col <= 5) {

                            cell.classList.add('center');

                        }

                        break;

                    case 'odd-even':

                        if ((row + col) % 2 === 0) {

                            cell.classList.add('even');

                        } else {

                            cell.classList.add('odd');

                        }

                        break;

                    case 'color':

                        const colorIndex = Math.floor(row / 3) * 3 + Math.floor(col / 3);

                        if (colorIndex % 2 === 0) {

                            cell.classList.add('extra-area');

                        }

                        break;

                    case 'inequality':

                        if (Math.random() > 0.7) {

                            if (Math.random() > 0.5) {

                                cell.classList.add('greater-than');

                            } else {

                                cell.classList.add('less-than');

                            }

                        }

                        break;

                }

            }

 

            setupEventListeners() {

                // 单元格点击

                document.getElementById('sudokuGrid').addEventListener('click', (e) => {

                    if (e.target.classList.contains('cell') && !e.target.classList.contains('fixed')) {

                        this.selectCell(e.target);

                    }

                });

 

                // 数字按钮

                document.querySelectorAll('.num-btn').forEach(btn => {

                    btn.addEventListener('click', () => {

                        const num = parseInt(btn.dataset.num);

                        this.inputNumber(num);

                    });

                });

 

                // 键盘输入

                document.addEventListener('keydown', (e) => {

                    if (this.aiSolving) return;

                    

                    let num = null;

                    if (this.gridSize === 6) {

                        if (e.key >= '1' && e.key <= '6') {

                            num = parseInt(e.key);

                        }

                    } else if (this.gridSize === 16) {

                        if (e.key >= '1' && e.key <= '9') {

                            num = parseInt(e.key);

                        } else if (e.key >= 'a' && e.key <= 'g') {

                            num = e.key.toUpperCase();

                        }

                    } else {

                        if (e.key >= '1' && e.key <= '9') {

                            num = parseInt(e.key);

                        }

                    }

                    

                    if (num !== null) {

                        this.inputNumber(num);

                    } else if (e.key === 'Delete' || e.key === 'Backspace') {

                        this.clearCell();

                    } else if (e.key === 'ArrowUp' || e.key === 'ArrowDown' || 

                              e.key === 'ArrowLeft' || e.key === 'ArrowRight') {

                        this.navigateWithArrows(e.key);

                    }

                });

 

                // 功能按钮

                document.getElementById('newGameBtn').addEventListener('click', () => this.newGame());

                document.getElementById('hintBtn').addEventListener('click', () => this.giveHint());

                document.getElementById('aiSolveBtn').addEventListener('click', () => this.aiSolve());

                document.getElementById('clearBtn').addEventListener('click', () => this.clearCell());

                document.getElementById('undoBtn').addEventListener('click', () => this.undo());

                document.getElementById('redoBtn').addEventListener('click', () => this.redo());

                document.getElementById('checkBtn').addEventListener('click', () => this.checkSolution());

                document.getElementById('pauseBtn').addEventListener('click', () => this.togglePause());

 

                // 难度选择

                document.querySelectorAll('.difficulty-btn').forEach(btn => {

                    btn.addEventListener('click', () => {

                        document.querySelectorAll('.difficulty-btn').forEach(b => b.classList.remove('active'));

                        btn.classList.add('active');

                        this.difficulty = btn.dataset.level;

                        this.newGame();

                    });

                });

 

                // 笔记模式

                document.getElementById('notesToggle').addEventListener('click', () => {

                    this.notesMode = !this.notesMode;

                    document.getElementById('notesToggle').classList.toggle('active');

                });

 

                // 主题选择

                document.querySelectorAll('.theme-btn').forEach(btn => {

                    btn.addEventListener('click', () => {

                        const theme = btn.dataset.theme;

                        document.body.style.background = this.themes[theme];

                        this.showMessage('主题已切换', 'success');

                    });

                });

            }

 

            createParticles() {

                const particlesContainer = document.getElementById('particles');

                for (let i = 0; i < 30; i++) {

                    const particle = document.createElement('div');

                    particle.className = 'particle';

                    particle.style.left = Math.random() * 100 + '%';

                    particle.style.animationDelay = Math.random() * 15 + 's';

                    particle.style.animationDuration = (15 + Math.random() * 10) + 's';

                    particlesContainer.appendChild(particle);

                }

            }

 

            newGame() {

                this.aiSolving = false;

                const rule = this.rules[this.currentRule];

                this.gridSize = rule.gridSize;

                

                // 更新数字按钮

                this.updateNumberPad();

                

                this.generatePuzzle();

                this.renderGrid();

                this.hints = 3;

                this.mistakes = 0;

                this.timer = 0;

                this.history = [];

                this.historyIndex = -1;

                this.updateStats();

                this.showMessage(`新游戏开始!${rule.name}`, 'success');

            }

 

            updateNumberPad() {

                const numberPad = document.querySelector('.number-pad');

                numberPad.innerHTML = '';

                

                if (this.gridSize === 6) {

                    for (let i = 1; i <= 6; i++) {

                        const btn = document.createElement('button');

                        btn.className = 'num-btn';

                        btn.dataset.num = i;

                        btn.textContent = i;

                        btn.addEventListener('click', () => this.inputNumber(i));

                        numberPad.appendChild(btn);

                    }

                } else if (this.gridSize === 16) {

                    for (let i = 1; i <= 9; i++) {

                        const btn = document.createElement('button');

                        btn.className = 'num-btn';

                        btn.dataset.num = i;

                        btn.textContent = i;

                        btn.addEventListener('click', () => this.inputNumber(i));

                        numberPad.appendChild(btn);

                    }

                    for (let i = 65; i <= 71; i++) {

                        const btn = document.createElement('button');

                        btn.className = 'num-btn';

                        btn.dataset.num = String.fromCharCode(i);

                        btn.textContent = String.fromCharCode(i);

                        btn.addEventListener('click', () => this.inputNumber(String.fromCharCode(i)));

                        numberPad.appendChild(btn);

                    }

                } else {

                    for (let i = 1; i <= 9; i++) {

                        const btn = document.createElement('button');

                        btn.className = 'num-btn';

                        btn.dataset.num = i;

                        btn.textContent = i;

                        btn.addEventListener('click', () => this.inputNumber(i));

                        numberPad.appendChild(btn);

                    }

                }

            }

 

            generatePuzzle() {

                const totalCells = this.gridSize * this.gridSize;

                

                // 生成完整的数独解

                this.solution = this.generateCompleteSudoku();

                

                // 根据难度移除数字

                const cellsToRemove = {

                    easy: Math.floor(totalCells * 0.4),

                    medium: Math.floor(totalCells * 0.5),

                    hard: Math.floor(totalCells * 0.6),

                    expert: Math.floor(totalCells * 0.7)

                }[this.difficulty];

 

                this.grid = [...this.solution];

                const positions = Array.from({length: totalCells}, (_, i) => i);

                

                for (let i = 0; i < cellsToRemove; i++) {

                    const randomIndex = Math.floor(Math.random() * positions.length);

                    const position = positions.splice(randomIndex, 1)[0];

                    this.grid[position] = 0;

                }

 

                this.initialGrid = [...this.grid];

            }

 

            generateCompleteSudoku() {

                const grid = Array(this.gridSize * this.gridSize).fill(0);

                this.fillGrid(grid);

                return grid;

            }

 

            fillGrid(grid) {

                const numbers = [];

                if (this.gridSize === 6) {

                    numbers.push(...[1, 2, 3, 4, 5, 6]);

                } else if (this.gridSize === 16) {

                    numbers.push(...[1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G']);

                } else {

                    numbers.push(...[1, 2, 3, 4, 5, 6, 7, 8, 9]);

                }

                

                for (let i = 0; i < this.gridSize * this.gridSize; i++) {

                    if (grid[i] === 0) {

                        const shuffled = this.shuffle([...numbers]);

                        

                        for (let num of shuffled) {

                            if (this.isValidMove(grid, i, num)) {

                                grid[i] = num;

                                

                                if (this.fillGrid(grid)) {

                                    return true;

                                }

                                

                                grid[i] = 0;

                            }

                        }

                        return false;

                    }

                }

                return true;

            }

 

            shuffle(array) {

                for (let i = array.length - 1; i > 0; i--) {

                    const j = Math.floor(Math.random() * (i + 1));

                    [array[i], array[j]] = [array[j], array[i]];

                }

                return array;

            }

 

            isValidMove(grid, index, num) {

                const row = Math.floor(index / this.gridSize);

                const col = index % this.gridSize;

                

                // 检查行

                for (let i = 0; i < this.gridSize; i++) {

                    if (grid[row * this.gridSize + i] === num) return false;

                }

                

                // 检查列

                for (let i = 0; i < this.gridSize; i++) {

                    if (grid[i * this.gridSize + col] === num) return false;

                }

                

                // 检查宫格

                let boxSize;

                if (this.gridSize === 6) {

                    boxSize = 2;

                } else if (this.gridSize === 16) {

                    boxSize = 4;

                } else {

                    boxSize = 3;

                }

                

                const boxRow = Math.floor(row / boxSize) * boxSize;

                const boxCol = Math.floor(col / boxSize) * boxSize;

                for (let i = 0; i < boxSize; i++) {

                    for (let j = 0; j < boxSize; j++) {

                        if (grid[(boxRow + i) * this.gridSize + (boxCol + j)] === num) return false;

                    }

                }

                

                // 特殊规则检查

                return this.checkSpecialRules(grid, index, num, row, col);

            }

 

            checkSpecialRules(grid, index, num, row, col) {

                switch(this.currentRule) {

                    case 'diagonal':

                        // 检查对角线

                        if (row === col) {

                            for (let i = 0; i < this.gridSize; i++) {

                                if (grid[i * this.gridSize + i] === num) return false;

                            }

                        }

                        if (row + col === this.gridSize - 1) {

                            for (let i = 0; i < this.gridSize; i++) {

                                if (grid[i * this.gridSize + (this.gridSize - 1 - i)] === num) return false;

                            }

                        }

                        break;

                    case 'center':

                        // 检查中心区域

                        if (row >= 3 && row <= 5 && col >= 3 && col <= 5) {

                            for (let i = 3; i <= 5; i++) {

                                for (let j = 3; j <= 5; j++) {

                                    if (grid[i * this.gridSize + j] === num) return false;

                                }

                            }

                        }

                        break;

                    case 'odd-even':

                        // 检查奇偶约束

                        const cell = document.querySelector(`.cell[data-index="${index}"]`);

                        if (cell.classList.contains('odd') && num % 2 === 0) return false;

                        if (cell.classList.contains('even') && num % 2 === 1) return false;

                        break;

                }

                

                return true;

            }

 

            renderGrid() {

                const cells = document.querySelectorAll('.cell');

                cells.forEach((cell, index) => {

                    cell.textContent = this.grid[index] || '';

                    cell.classList.remove('fixed', 'error', 'selected', 'highlighted', 'same-number', 'user-input', 'ai-solved');

                    

                    if (this.initialGrid[index] !== 0) {

                        cell.classList.add('fixed');

                    } else if (this.grid[index] !== 0) {

                        if (this.aiSolving) {

                            cell.classList.add('ai-solved');

                        } else {

                            cell.classList.add('user-input');

                        }

                    }

                });

            }

 

            selectCell(cell) {

                if (this.aiSolving) return;

                

                document.querySelectorAll('.cell').forEach(c => {

                    c.classList.remove('selected', 'highlighted', 'same-number');

                });

 

                cell.classList.add('selected');

                this.selectedCell = cell;

 

                const index = parseInt(cell.dataset.index);

                const row = parseInt(cell.dataset.row);

                const col = parseInt(cell.dataset.col);

                const box = parseInt(cell.dataset.box);

                const value = this.grid[index];

 

                // 高亮同行、同列、同宫格

                document.querySelectorAll('.cell').forEach(c => {

                    if (parseInt(c.dataset.row) === row || 

                        parseInt(c.dataset.col) === col || 

                        parseInt(c.dataset.box) === box) {

                        c.classList.add('highlighted');

                    }

                    

                    // 高亮相同数字

                    if (value && this.grid[parseInt(c.dataset.index)] === value) {

                        c.classList.add('same-number');

                    }

                });

            }

 

            inputNumber(num) {

                if (!this.selectedCell || this.selectedCell.classList.contains('fixed') || this.aiSolving) return;

 

                const index = parseInt(this.selectedCell.dataset.index);

                

                if (this.notesMode) {

                    this.toggleNote(this.selectedCell, num);

                } else {

                    this.saveHistory();

                    

                    this.grid[index] = num;

                    this.selectedCell.textContent = num;

                    this.selectedCell.classList.remove('ai-solved');

                    this.selectedCell.classList.add('user-input');

                    

                    if (num !== this.solution[index]) {

                        this.selectedCell.classList.add('error');

                        this.mistakes++;

                        this.updateStats();

                        

                        if (this.mistakes >= 3) {

                            this.showMessage('游戏结束!错误次数过多', 'error');

                            setTimeout(() => this.newGame(), 2000);

                        }

                    } else {

                        this.selectedCell.classList.remove('error');

                        this.selectedCell.classList.add('correct');

                        setTimeout(() => {

                            this.selectedCell.classList.remove('correct');

                        }, 500);

                    }

                    

                    this.updateProgress();

                    this.checkWin();

                }

            }

 

            toggleNote(cell, num) {

                const currentNotes = cell.dataset.notes || '';

                const notes = currentNotes.split('').filter(n => n !== num.toString());

                

                if (currentNotes.includes(num.toString())) {

                    cell.dataset.notes = notes.join('');

                } else {

                    notes.push(num.toString());

                    cell.dataset.notes = notes.join('');

                }

                

                if (cell.dataset.notes) {

                    cell.innerHTML = `<small style="font-size: 10px; color: #666;">${cell.dataset.notes}</small>`;

                } else {

                    cell.textContent = '';

                }

            }

 

            clearCell() {

                if (!this.selectedCell || this.selectedCell.classList.contains('fixed') || this.aiSolving) return;

 

                this.saveHistory();

                const index = parseInt(this.selectedCell.dataset.index);

                this.grid[index] = 0;

                this.selectedCell.textContent = '';

                this.selectedCell.classList.remove('error', 'user-input', 'ai-solved');

                delete this.selectedCell.dataset.notes;

                this.updateProgress();

            }

 

            navigateWithArrows(key) {

                if (!this.selectedCell || this.aiSolving) {

                    if (!this.aiSolving) {

                        this.selectCell(document.querySelector('.cell'));

                    }

                    return;

                }

 

                const index = parseInt(this.selectedCell.dataset.index);

                const row = Math.floor(index / this.gridSize);

                const col = index % this.gridSize;

                let newIndex = index;

 

                switch(key) {

                    case 'ArrowUp':

                        if (row > 0) newIndex = (row - 1) * this.gridSize + col;

                        break;

                    case 'ArrowDown':

                        if (row < this.gridSize - 1) newIndex = (row + 1) * this.gridSize + col;

                        break;

                    case 'ArrowLeft':

                        if (col > 0) newIndex = row * this.gridSize + (col - 1);

                        break;

                    case 'ArrowRight':

                        if (col < this.gridSize - 1) newIndex = row * this.gridSize + (col + 1);

                        break;

                }

 

                const newCell = document.querySelector(`.cell[data-index="${newIndex}"]`);

                if (newCell) this.selectCell(newCell);

            }

 

            giveHint() {

                if (this.hints <= 0) {

                    this.showMessage('没有提示了!', 'error');

                    return;

                }

 

                const emptyCells = [];

                this.grid.forEach((val, index) => {

                    if (val === 0) emptyCells.push(index);

                });

 

                if (emptyCells.length === 0) return;

 

                const randomIndex = emptyCells[Math.floor(Math.random() * emptyCells.length)];

                const cell = document.querySelector(`.cell[data-index="${randomIndex}"]`);

                

                this.grid[randomIndex] = this.solution[randomIndex];

                cell.textContent = this.solution[randomIndex];

                cell.classList.add('correct');

                cell.classList.add('user-input');

                

                setTimeout(() => {

                    cell.classList.remove('correct');

                }, 1000);

 

                this.hints--;

                this.updateStats();

                this.updateProgress();

                this.checkWin();

                this.showMessage('使用了一个提示!', 'info');

            }

 

            aiSolve() {

                if (this.aiSolving) {

                    this.showMessage('AI正在解题中...', 'info');

                    return;

                }

 

                this.aiSolving = true;

                this.showMessage('AI正在解题...', 'info');

                

                const emptyCells = [];

                this.grid.forEach((val, index) => {

                    if (val === 0) emptyCells.push(index);

                });

 

                let currentIndex = 0;

                const solveInterval = setInterval(() => {

                    if (currentIndex >= emptyCells.length || !this.aiSolving) {

                        clearInterval(solveInterval);

                        this.aiSolving = false;

                        if (currentIndex >= emptyCells.length) {

                            this.showMessage('AI解题完成!', 'success');

                        }

                        return;

                    }

 

                    const index = emptyCells[currentIndex];

                    const cell = document.querySelector(`.cell[data-index="${index}"]`);

                    

                    this.grid[index] = this.solution[index];

                    cell.textContent = this.solution[index];

                    cell.classList.add('correct');

                    cell.classList.add('ai-solved');

                    

                    setTimeout(() => {

                        cell.classList.remove('correct');

                    }, 500);

                    

                    currentIndex++;

                }, 300);

 

                this.updateProgress();

            }

 

            checkSolution() {

                let hasErrors = false;

                document.querySelectorAll('.cell').forEach((cell, index) => {

                    if (this.grid[index] !== 0 && this.grid[index] !== this.solution[index]) {

                        cell.classList.add('error');

                        hasErrors = true;

                    } else {

                        cell.classList.remove('error');

                    }

                });

 

                if (hasErrors) {

                    this.showMessage('发现错误!', 'error');

                } else {

                    this.showMessage('目前没有错误!', 'success');

                }

            }

 

            checkWin() {

                const isComplete = this.grid.every((val, index) => val === this.solution[index]);

                

                if (isComplete) {

                    this.stopTimer();

                    this.showMessage(`🎉 恭喜完成!用时 ${this.formatTime(this.timer)}`, 'success');

                    

                    document.querySelectorAll('.cell').forEach((cell, index) => {

                        setTimeout(() => {

                            cell.classList.add('correct');

                        }, index * 10);

                    });

                }

            }

 

            saveHistory() {

                this.history = this.history.slice(0, this.historyIndex + 1);

                this.history.push([...this.grid]);

                this.historyIndex++;

            }

 

            undo() {

                if (this.historyIndex > 0) {

                    this.historyIndex--;

                    this.grid = [...this.history[this.historyIndex]];

                    this.renderGrid();

                    this.updateProgress();

                }

            }

 

            redo() {

                if (this.historyIndex < this.history.length - 1) {

                    this.historyIndex++;

                    this.grid = [...this.history[this.historyIndex]];

                    this.renderGrid();

                    this.updateProgress();

                }

            }

 

            togglePause() {

                this.isPaused = !this.isPaused;

                const btn = document.getElementById('pauseBtn');

                

                if (this.isPaused) {

                    this.stopTimer();

                    btn.textContent = '继续';

                    document.getElementById('sudokuGrid').style.opacity = '0.3';

                    this.showMessage('游戏已暂停', 'info');

                } else {

                    this.startTimer();

                    btn.textContent = '暂停';

                    document.getElementById('sudokuGrid').style.opacity = '1';

                    this.showMessage('游戏继续', 'info');

                }

            }

 

            startTimer() {

                this.timerInterval = setInterval(() => {

                    this.timer++;

                    document.getElementById('timer').textContent = this.formatTime(this.timer);

                }, 1000);

            }

 

            stopTimer() {

                clearInterval(this.timerInterval);

            }

 

            formatTime(seconds) {

                const mins = Math.floor(seconds / 60);

                const secs = seconds % 60;

                return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;

            }

 

            updateStats() {

                document.getElementById('hints').textContent = this.hints;

                document.getElementById('mistakes').textContent = `${this.mistakes}/3`;

            }

 

            updateProgress() {

                const filled = this.grid.filter((val, index) => val === this.solution[index]).length;

                const total = this.gridSize * this.gridSize;

                const progress = Math.round((filled / total) * 100);

                

                document.getElementById('progress').textContent = `${progress}%`;

                document.getElementById('progressBar').style.width = `${progress}%`;

            }

 

            showMessage(text, type) {

                const messageEl = document.getElementById('message');

                messageEl.textContent = text;

                messageEl.className = `message ${type}`;

                messageEl.style.display = 'block';

                

                setTimeout(() => {

                    messageEl.style.display = 'none';

                }, 3000);

            }

        }

 

        // 启动游戏

        const game = new SudokuGame();

 

        // 自动切换背景主题

        const themes = Object.keys(game.themes);

        let currentThemeIndex = 0;

 

        setInterval(() => {

            currentThemeIndex = (currentThemeIndex + 1) % themes.length;

            const theme = themes[currentThemeIndex];

            document.body.style.background = game.themes[theme];

        }, 30000);

    </script>

</body>

</html>

 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐