互动数独游戏构建器
来自 Wikiprompt,自由的提示词百科全书
互动数独游戏构建器 一个全面的提示,用于开发一款功能齐全的数独游戏,包含难度级别、提示、笔记、计时器、保存、统计、打印和无障碍功能。
提示词内容收藏
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>♾️ Sudoku · interactive</title>
<style>
* {
box-sizing: border-box;
font-family: system-ui, 'Segoe UI', Roboto, sans-serif;
}
body {
background: linear-gradient(145deg, #f5f7fb 0%, #e9edf5 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
padding: 16px;
}
.game-container {
max-width: 1000px;
width: 100%;
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(8px);
border-radius: 40px;
padding: 24px 28px;
box-shadow: 0 20px 40px rgba(0, 10, 30, 0.2);
border: 1px solid rgba(255, 255, 255, 0.6);
}
.header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
gap: 12px;
}
.title {
font-size: 2rem;
font-weight: 700;
letter-spacing: 2px;
background: linear-gradient(135deg, #1e3c72, #2a5298);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
button, select {
background: white;
border: 1px solid #b0c4de;
border-radius: 40px;
padding: 8px 16px;
font-weight: 500;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.15s;
box-shadow: 0 2px 4px rgba(0,0,0,0.02);
display: inline-flex;
align-items: center;
gap: 6px;
}
button:hover, select:hover {
background: #eef3fc;
border-color: #2a5298;
transform: scale(1.02);
}
button:active {
transform: scale(0.98);
}
.difficulty-select {
background: #f0f4fa;
font-weight: 600;
}
.board-section {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 24px;
justify-content: center;
}
.sudoku-board {
display: grid;
grid-template-columns: repeat(9, 1fr);
background: #1e3c72;
border: 3px solid #1e3c72;
border-radius: 12px;
width: min(70vw, 480px);
aspect-ratio: 1/1;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
overflow: hidden;
}
.cell {
background: white;
border: 0.5px solid #a0b8d0;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
font-weight: 500;
color: #0a1f44;
cursor: default;
position: relative;
transition: background 0.1s;
user-select: none;
}
.cell.given {
background: #eaf0fa;
font-weight: 700;
color: #0a2a5e;
}
.cell.selected {
background: #c7d9f0;
box-shadow: inset 0 0 0 2px #2a5298;
}
.cell.related {
background: #e2eaf8;
}
.cell.error {
background: #ffe1e1;
color: #b00020;
}
.cell.hint-highlight {
background: #fdf3c0;
}
.cell.note-mode {
font-size: 0.8rem;
color: #2a5298;
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: center;
gap: 2px;
}
.note-number {
width: 8px;
height: 8px;
font-size: 0.65rem;
display: inline-flex;
align-items: center;
justify-content: center;
background: #f0f4ff;
border-radius: 2px;
margin: 1px;
}
.right-panel {
flex: 1;
min-width: 220px;
display: flex;
flex-direction: column;
gap: 16px;
}
.timer-box {
background: #ffffffd0;
border-radius: 30px;
padding: 12px 18px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 8px rgba(0,0,0,0.05);
border: 1px solid #c0d0e8;
}
.timer {
font-size: 1.8rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
letter-spacing: 2px;
background: #1e3c72;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.action-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.action-grid button {
justify-content: center;
}
.stat-box {
background: #ffffffd0;
border-radius: 20px;
padding: 12px 16px;
border: 1px solid #c0d0e8;
font-size: 0.9rem;
}
.stat-line {
display: flex;
justify-content: space-between;
margin: 4px 0;
}
.save-slots {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.slot-btn {
background: #eef3fc;
border-radius: 30px;
padding: 6px 12px;
font-size: 0.8rem;
}
.print-btn {
background: #2a5298;
color: white;
border: none;
}
.print-btn:hover {
background: #1e3c72;
}
.footer-note {
margin-top: 12px;
font-size: 0.8rem;
color: #3a4a6a;
text-align: center;
}
.key-hint {
background: #eef3fc;
border-radius: 20px;
padding: 8px 12px;
font-size: 0.8rem;
color: #1e3c72;
}
@media (max-width: 700px) {
.sudoku-board {
width: 90vw;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="header">
<h1 class="title">♾️ SUDOKU</h1>
<div class="controls">
<select id="difficultySelect" class="difficulty-select" aria-label="difficulty level">
<option value="easy">🌱 easy</option>
<option value="medium" selected>🍂 medium</option>
<option value="hard">🔥 hard</option>
<option value="expert">💎 expert</option>
</select>
<button id="newGameBtn">✨ new</button>
<button id="pauseBtn">⏸️ pause</button>
<button id="hintBtn">💡 hint</button>
<button id="noteToggleBtn" class="note-toggle">✏️ notes</button>
</div>
</div>
<div class="board-section">
<div id="board" class="sudoku-board" role="grid" aria-label="sudoku board"></div>
<div class="right-panel">
<div class="timer-box">
<span>⏱️</span>
<span id="timerDisplay" class="timer">00:00</span>
<button id="resetTimerBtn" title="reset timer">↺</button>
</div>
<div class="action-grid">
<button id="checkBtn">✔️ check</button>
<button id="clearBtn">🧹 clear</button>
<button id="saveBtn">💾 save</button>
<button id="loadBtn">📂 load</button>
<button id="printBtn" class="print-btn">🖨️ print</button>
<button id="undoBtn">↩️ undo</button>
</div>
<div class="save-slots">
<button class="slot-btn" data-slot="1">slot 1</button>
<button class="slot-btn" data-slot="2">slot 2</button>
<button class="slot-btn" data-slot="3">slot 3</button>
</div>
<div class="stat-box">
<div class="stat-line"><span>🏆 wins</span><span id="winCount">0</span></div>
<div class="stat-line"><span>⏱️ best time</span><span id="bestTime">--</span></div>
<div class="stat-line"><span>📊 games</span><span id="gameCount">0</span></div>
</div>
<div class="key-hint">
⌨️ 1-9 set · N notes · H hint · P pause · S save
</div>
</div>
</div>
<div class="footer-note">immediate error feedback · multi-level hints · notes · save/load</div>
</div>
<script>
(function() {
// ---------- core state ----------
let board = Array(9).fill().map(() => Array(9).fill(0));
let solution = Array(9).fill().map(() => Array(9).fill(0));
let givenMask = Array(9).fill().map(() => Array(9).fill(false));
let notes = Array(9).fill().map(() => Array(9).fill().map(() => []));
let selectedRow = -1, selectedCol = -1;
let timerInterval = null;
let seconds = 0;
let paused = false;
let noteMode = false;
let difficulty = 'medium';
let gameOver = false;
let history = []; // for undo (snapshot)
let stats = { wins: 0, bestTime: null, games: 0 };
// DOM elements
const boardEl = document.getElementById('board');
const timerDisplay = document.getElementById('timerDisplay');
const difficultySelect = document.getElementById('difficultySelect');
const winCountEl = document.getElementById('winCount');
const bestTimeEl = document.getElementById('bestTime');
const gameCountEl = document.getElementById('gameCount');
// ---------- helpers ----------
function formatTime(sec) {
const m = Math.floor(sec / 60).toString().padStart(2, '0');
const s = (sec % 60).toString().padStart(2, '0');
return `${m}:${s}`;
}
function updateTimerDisplay() {
timerDisplay.textContent = formatTime(seconds);
}
function startTimer() {
if (timerInterval) clearInterval(timerInterval);
timerInterval = setInterval(() => {
if (!paused && !gameOver) {
seconds++;
updateTimerDisplay();
}
}, 1000);
}
function stopTimer() {
if (timerInterval) clearInterval(timerInterval);
timerInterval = null;
}
// ---------- puzzle generation (solver + dig) ----------
function generateSolution() {
const sol = Array(9).fill().map(() => Array(9).fill(0));
fillGrid(sol);
return sol;
}
function fillGrid(grid) {
const nums = [1,2,3,4,5,6,7,8,9];
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
if (grid[r][c] === 0) {
shuffle(nums);
for (let n of nums) {
if (isSafe(grid, r, c, n)) {
grid[r][c] = n;
if (isFull(grid) || fillGrid(grid)) return true;
grid[r][c] = 0;
}
}
return false;
}
}
}
return true;
}
function isSafe(grid, row, col, num) {
for (let i = 0; i < 9; i++) {
if (grid[row][i] === num || grid[i][col] === num) return false;
}
const br = Math.floor(row/3)*3, bc = Math.floor(col/3)*3;
for (let r = br; r < br+3; r++) {
for (let c = bc; c < bc+3; c++) {
if (grid[r][c] === num) return false;
}
}
return true;
}
function isFull(grid) {
return grid.every(row => row.every(v => v !== 0));
}
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
function generatePuzzle(diff) {
const sol = generateSolution();
const puzzle = sol.map(row => [...row]);
const cellsToRemove = { easy: 38, medium: 50, hard: 58, expert: 64 }[diff] || 50;
let removed = 0;
while (removed < cellsToRemove) {
const r = Math.floor(Math.random() * 9);
const c = Math.floor(Math.random() * 9);
if (puzzle[r][c] !== 0) {
puzzle[r][c] = 0;
removed++;
}
}
return { puzzle, solution: sol };
}
// ---------- board rendering ----------
function renderBoard() {
boardEl.innerHTML = '';
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
if (givenMask[r][c]) cell.classList.add('given');
if (selectedRow === r && selectedCol === c) cell.classList.add('selected');
// related highlight
if (selectedRow >= 0 && selectedCol >= 0 && (selectedRow === r || selectedCol === c ||
(Math.floor(selectedRow/3) === Math.floor(r/3) && Math.floor(selectedCol/3) === Math.floor(c/3)))) {
if (!(selectedRow === r && selectedCol === c)) cell.classList.add('related');
}
// error check (immediate feedback)
if (board[r][c] !== 0 && !givenMask[r][c] && board[r][c] !== solution[r][c]) {
cell.classList.add('error');
}
// notes display
if (board[r][c] === 0 && notes[r][c].length > 0) {
cell.classList.add('note-mode');
notes[r][c].forEach(n => {
const span = document.createElement('span');
span.className = 'note-number';
span.textContent = n;
cell.appendChild(span);
});
} else {
cell.textContent = board[r][c] !== 0 ? board[r][c] : '';
}
cell.dataset.row = r;
cell.dataset.col = c;
cell.addEventListener('click', () => {
if (gameOver) return;
selectedRow = r; selectedCol = c;
renderBoard();
});
boardEl.appendChild(cell);
}
}
}
// ---------- game actions ----------
function newGame() {
stopTimer();
seconds = 0;
paused = false;
gameOver = false;
updateTimerDisplay();
difficulty = difficultySelect.value;
const { puzzle, solution: sol } = generatePuzzle(difficulty);
board = puzzle.map(row => [...row]);
solution = sol.map(row => [...row]);
givenMask = board.map(row => row.map(v => v !== 0));
notes = Array(9).fill().map(() => Array(9).fill().map(() => []));
selectedRow = -1; selectedCol = -1;
history = [];
stats.games++;
gameCountEl.textContent = stats.games;
renderBoard();
startTimer();
}
function setCellValue(row, col, val) {
if (gameOver || givenMask[row][col]) return;
// snapshot for undo
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
if (history.length > 30) history.shift();
board[row][col] = val;
if (val !== 0) notes[row][col] = [];
// check win
if (isBoardComplete()) {
gameOver = true;
stopTimer();
stats.wins++;
winCountEl.textContent = stats.wins;
if (stats.bestTime === null || seconds < stats.bestTime) {
stats.bestTime = seconds;
bestTimeEl.textContent = formatTime(seconds);
}
alert('🎉 You win!');
}
renderBoard();
}
function isBoardComplete() {
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
if (board[r][c] !== solution[r][c]) return false;
}
}
return true;
}
// hint system (multi-level: fill cell, remove notes, highlight)
function giveHint() {
if (gameOver) return;
// find first empty or wrong cell
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
if (board[r][c] !== solution[r][c]) {
// if notes exist, remove wrong notes
if (board[r][c] === 0 && notes[r][c].length > 0) {
const correct = solution[r][c];
const filtered = notes[r][c].filter(n => n === correct);
if (filtered.length === 0) {
// set note to correct
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
notes[r][c] = [correct];
renderBoard();
return;
} else {
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
notes[r][c] = [correct];
renderBoard();
return;
}
} else {
// set value
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
board[r][c] = solution[r][c];
notes[r][c] = [];
renderBoard();
return;
}
}
}
}
}
// undo
function undo() {
if (history.length === 0) return;
const prev = history.pop();
board = prev.board;
notes = prev.notes;
renderBoard();
}
// check errors (optional immediate feedback already on)
function checkErrors() {
renderBoard(); // just re-render to show errors
}
// clear user entries (not given)
function clearUser() {
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
if (!givenMask[r][c]) {
board[r][c] = 0;
notes[r][c] = [];
}
}
}
renderBoard();
}
// save/load slots
function saveToSlot(slot) {
const data = { board, solution, givenMask, notes, seconds, difficulty, stats };
localStorage.setItem(`sudoku_slot_${slot}`, JSON.stringify(data));
alert(`saved to slot ${slot}`);
}
function loadFromSlot(slot) {
const raw = localStorage.getItem(`sudoku_slot_${slot}`);
if (!raw) { alert('empty slot'); return; }
const data = JSON.parse(raw);
board = data.board; solution = data.solution; givenMask = data.givenMask;
notes = data.notes; seconds = data.seconds; difficulty = data.difficulty;
if (data.stats) stats = data.stats;
gameOver = false; paused = false;
stopTimer(); startTimer();
updateTimerDisplay();
winCountEl.textContent = stats.wins;
bestTimeEl.textContent = stats.bestTime !== null ? formatTime(stats.bestTime) : '--';
gameCountEl.textContent = stats.games;
renderBoard();
}
// print (window.print)
function printPuzzle() {
window.print();
}
// ---------- event listeners ----------
document.getElementById('newGameBtn').addEventListener('click', newGame);
document.getElementById('pauseBtn').addEventListener('click', () => {
paused = !paused;
document.getElementById('pauseBtn').textContent = paused ? '▶️ resume' : '⏸️ pause';
});
document.getElementById('hintBtn').addEventListener('click', giveHint);
document.getElementById('noteToggleBtn').addEventListener('click', () => {
noteMode = !noteMode;
document.getElementById('noteToggleBtn').style.background = noteMode ? '#c7d9f0' : 'white';
});
document.getElementById('checkBtn').addEventListener('click', checkErrors);
document.getElementById('clearBtn').addEventListener('click', clearUser);
document.getElementById('undoBtn').addEventListener('click', undo);
document.getElementById('saveBtn').addEventListener('click', () => saveToSlot(1));
document.getElementById('loadBtn').addEventListener('click', () => loadFromSlot(1));
document.getElementById('printBtn').addEventListener('click', printPuzzle);
document.getElementById('resetTimerBtn').addEventListener('click', () => { seconds = 0; updateTimerDisplay(); });
// slot buttons
document.querySelectorAll('.slot-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
const slot = e.target.dataset.slot;
if (e.shiftKey) { // shift+click = save
saveToSlot(slot);
} else {
loadFromSlot(slot);
}
});
});
// keyboard controls
document.addEventListener('keydown', (e) => {
if (e.key >= '1' && e.key <= '9') {
const num = parseInt(e.key);
if (selectedRow >= 0 && selectedCol >= 0 && !givenMask[selectedRow][selectedCol]) {
if (noteMode) {
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
const idx = notes[selectedRow][selectedCol].indexOf(num);
if (idx > -1) notes[selectedRow][selectedCol].splice(idx, 1);
else notes[selectedRow][selectedCol].push(num);
renderBoard();
} else {
setCellValue(selectedRow, selectedCol, num);
}
}
} else if (e.key === 'n' || e.key === 'N') {
document.getElementById('noteToggleBtn').click();
} else if (e.key === 'h' || e.key === 'H') {
giveHint();
} else if (e.key === 'p' || e.key === 'P') {
document.getElementById('pauseBtn').click();
} else if (e.key === 's' || e.key === 'S') {
saveToSlot(1);
} else if (e.key === 'Backspace' || e.key === 'Delete') {
if (selectedRow >= 0 && selectedCol >= 0 && !givenMask[selectedRow][selectedCol]) {
history.push({ board: board.map(r => [...r]), notes: notes.map(r => r.map(n => [...n])) });
board[selectedRow][selectedCol] = 0;
notes[selectedRow][selectedCol] = [];
renderBoard();
}
}
});
// init
newGame();
})();
</script>
</body>
</html>
用法
此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。
为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。
讨论
0 条评论