交互了几次,AI后面就开始顾此失彼了,也许一开始就把完整的游戏说明给它也许会好一点。
游戏就是选择相邻的格子的数字用四则运算生成新的数字,如果匹配到目标数字则消减并目标数字++。
新格子的数字用递增的方式填充。所以目标数字能玩到18、19已经是极限了
贴代码:
<!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;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
width: 100%;
max-width: 900px;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
header {
background: linear-gradient(90deg, #4b6cb7, #182848);
color: white;
text-align: center;
padding: 25px 20px;
position: relative;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.subtitle {
font-size: 1.1rem;
opacity: 0.9;
margin-bottom: 10px;
}
.game-rules {
background: rgba(255, 255, 255, 0.15);
border-radius: 10px;
padding: 10px;
font-size: 0.9rem;
max-width: 600px;
margin: 0 auto;
}
.main-game-area {
display: flex;
flex-direction: column;
padding: 20px;
}
.target-area {
display: flex;
justify-content: space-between;
align-items: center;
background: #f8f9fa;
border-radius: 15px;
padding: 15px;
margin-bottom: 20px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.target-display {
font-size: 2.2rem;
color: #e74c3c;
font-weight: bold;
text-align: center;
flex: 1;
}
.chances {
display: flex;
gap: 8px;
}
.chance {
width: 25px;
height: 25px;
background: #2ecc71;
border-radius: 50%;
}
.chance.lost {
background: #e74c3c;
}
.game-area {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
.grid-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 12px;
flex: 1;
max-width: 600px;
}
.cell {
aspect-ratio: 1/1;
background: linear-gradient(145deg, #e6e6e6, #ffffff);
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2.2rem;
font-weight: bold;
color: #333;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
border: 3px solid transparent;
position: relative;
overflow: hidden;
}
.cell:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.cell.selected {
background: linear-gradient(145deg, #43cea2, #185a9d);
color: white;
border-color: #fff;
box-shadow: 0 0 15px rgba(67, 206, 162, 0.5);
}
.cell.operator-source {
background: linear-gradient(145deg, #FFA62B, #EA4C89);
color: white;
border-color: #fff;
box-shadow: 0 0 15px rgba(234, 76, 137, 0.5);
}
.cell.adjacent {
background: linear-gradient(145deg, #b5ff7d, #5b8c2a);
box-shadow: 0 0 12px rgba(91, 140, 42, 0.5);
animation: pulse 1.5s infinite;
}
.cell.empty {
background: linear-gradient(145deg, #d1d1d1, #a0a0a0);
color: #777;
cursor: not-allowed;
}
.cell.new-value {
animation: newValueHighlight 1s;
}
.cell.target-match {
background: linear-gradient(145deg, #ff416c, #ff4b2b);
color: white;
box-shadow: 0 0 20px rgba(255, 75, 43, 0.7);
animation: targetMatch 1s infinite;
}
.operation-panel {
width: 120px;
display: flex;
flex-direction: column;
gap: 15px;
padding: 15px;
background: #f8f9fa;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.operator-btn {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 2.2rem;
font-weight: bold;
background: linear-gradient(145deg, #f5f7fa, #c3cfe2);
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
color: #4a5568;
}
.operator-btn:hover {
transform: scale(1.05);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
}
.operator-btn.selected {
background: linear-gradient(145deg, #FFA62B, #EA4C89);
color: white;
border-color: #fff;
box-shadow: 0 0 15px rgba(234, 76, 137, 0.5);
}
.stats {
background-color: #f8f9fa;
border-radius: 12px;
padding: 15px;
margin: 0 20px 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.stats h2 {
text-align: center;
color: #2c3e50;
margin-bottom: 12px;
font-size: 1.5rem;
}
.status-bar {
background: #e3f2fd;
border-radius: 8px;
padding: 12px;
text-align: center;
font-size: 1.2rem;
font-weight: 500;
color: #1a237e;
margin-bottom: 12px;
min-height: 50px;
display: flex;
justify-content: center;
align-items: center;
}
.controls {
display: flex;
justify-content: center;
gap: 15px;
padding: 0 20px 20px;
}
button {
padding: 12px 25px;
font-size: 1rem;
border: none;
border-radius: 40px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: bold;
letter-spacing: 0.5px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
#resetBtn {
background: linear-gradient(to right, #e74c3c, #c0392b);
color: white;
}
#hintBtn {
background: linear-gradient(to right, #3498db, #2980b9);
color: white;
}
#startBtn {
background: linear-gradient(to right, #2ecc71, #27ae60);
color: white;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
}
button:active {
transform: translateY(1px);
}
footer {
text-align: center;
padding: 15px;
color: #7f8c8d;
font-size: 0.9rem;
background-color: rgba(0, 0, 0, 0.03);
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
.score-board {
display: flex;
justify-content: space-between;
background: rgba(255, 255, 255, 0.9);
border-radius: 10px;
padding: 10px 15px;
font-weight: bold;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
margin-top: 10px;
}
.score-item {
text-align: center;
flex: 1;
}
.score-value {
font-size: 1.5rem;
font-weight: bold;
color: #3498db;
}
@keyframes pulse {
0% { transform: scale(1); box-shadow: 0 0 10px rgba(91, 140, 42, 0.5); }
50% { transform: scale(1.03); box-shadow: 0 0 15px rgba(91, 140, 42, 0.7); }
100% { transform: scale(1); box-shadow: 0 0 10px rgba(91, 140, 42, 0.5); }
}
@keyframes newValueHighlight {
0% { transform: scale(1); background: linear-gradient(145deg, #ffeb3b, #ff9800); }
50% { transform: scale(1.08); box-shadow: 0 0 20px rgba(255, 152, 0, 0.6); }
100% { transform: scale(1); }
}
@keyframes fallDown {
0% { transform: translateY(-80px); opacity: 0; }
100% { transform: translateY(0); opacity: 1; }
}
@keyframes targetMatch {
0% { transform: scale(1); box-shadow: 0 0 12px rgba(255, 75, 43, 0.6); }
50% { transform: scale(1.08); box-shadow: 0 0 25px rgba(255, 75, 43, 0.8); }
100% { transform: scale(1); box-shadow: 0 0 12px rgba(255, 75, 43, 0.6); }
}
@keyframes disappear {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(0); opacity: 0; }
}
@media (max-width: 768px) {
.game-area {
flex-direction: column;
}
.operation-panel {
width: 100%;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.operator-btn {
width: 70px;
height: 70px;
font-size: 1.8rem;
}
h1 {
font-size: 2rem;
}
.grid-container {
max-width: 100%;
}
.target-area {
flex-direction: column;
gap: 10px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>目标挑战数字格子游戏</h1>
<div class="subtitle">达成目标数字,挑战最高得分!</div>
<div class="game-rules">
游戏规则:选择数字 → 运算符 → 相邻数字 → 结果替换 → 结算目标数字
</div>
</header>
<div class="main-game-area">
<div class="target-area">
<div class="target-display">
目标数字: <span id="targetDisplay">1</span>
</div>
<div class="chances">
<span>剩余机会:</span>
<div class="chances" id="chancesContainer">
<div class="chance"></div>
<div class="chance"></div>
<div class="chance"></div>
</div>
</div>
</div>
<div class="game-area">
<div class="grid-container" id="gridContainer">
<!-- 格子将由JavaScript生成 -->
</div>
<div class="operation-panel">
<div class="operator-btn" data-operator="+">+</div>
<div class="operator-btn" data-operator="-">-</div>
<div class="operator-btn" data-operator="*">×</div>
<div class="operator-btn" data-operator="/">÷</div>
</div>
</div>
<div class="score-board">
<div class="score-item">
<div>当前得分</div>
<div class="score-value" id="currentScore">0</div>
</div>
<div class="score-item">
<div>最高得分</div>
<div class="score-value" id="highScore">0</div>
</div>
<div class="score-item">
<div>操作次数</div>
<div class="score-value" id="moveCount">0</div>
</div>
</div>
</div>
<div class="stats">
<h2>操作状态</h2>
<div class="status-bar" id="statusBar">
请点击"开始游戏"按钮
</div>
</div>
<div class="controls">
<button id="hintBtn">游戏说明</button>
<button id="startBtn">开始游戏</button>
<button id="resetBtn">重置游戏</button>
</div>
<footer>
<p>目标挑战数字格子游戏 © 2023 | 策略性数学挑战</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const gridContainer = document.getElementById('gridContainer');
const statusBar = document.getElementById('statusBar');
const resetBtn = document.getElementById('resetBtn');
const hintBtn = document.getElementById('hintBtn');
const startBtn = document.getElementById('startBtn');
const operatorBtns = document.querySelectorAll('.operator-btn');
const targetDisplay = document.getElementById('targetDisplay');
const chancesContainer = document.getElementById('chancesContainer');
const highScoreEl = document.getElementById('highScore');
const currentScoreEl = document.getElementById('currentScore');
const moveCountEl = document.getElementById('moveCount');
// 游戏状态
let gameState = 'idle'; // idle, selectFirst, selectOperator, selectSecond
let firstCell = null;
let selectedOperator = null;
let cells = [];
let moveCount = 0;
let nextNewNumber = 13;
let targetNumber = 1;
let remainingChances = 3;
let currentScore = 0;
let highScore = 0;
let gameActive = false;
// 创建3x4网格
function createGrid() {
gridContainer.innerHTML = '';
cells = [];
for (let i = 1; i <= 12; i++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.textContent = i;
cell.dataset.value = i;
cell.dataset.index = i-1;
// 计算行列位置
const row = Math.floor((i-1) / 4);
const col = (i-1) % 4;
cell.dataset.row = row;
cell.dataset.col = col;
cell.addEventListener('click', () => {
if (gameActive) handleCellClick(cell);
});
gridContainer.appendChild(cell);
cells.push(cell);
}
}
// 高亮相邻的格子
function highlightAdjacentCells(cell) {
// 先清除所有相邻标记
cells.forEach(c => c.classList.remove('adjacent'));
const row = parseInt(cell.dataset.row);
const col = parseInt(cell.dataset.col);
// 检查四个方向:上、右、下、左
const directions = [
{r: row-1, c: col}, // 上
{r: row, c: col+1}, // 右
{r: row+1, c: col}, // 下
{r: row, c: col-1} // 左
];
// 标记相邻且非空的格子
directions.forEach(dir => {
if (dir.r >= 0 && dir.r < 3 && dir.c >= 0 && dir.c < 4) {
const index = dir.r * 4 + dir.c;
const adjacentCell = cells[index];
// 只标记非空格子
if (adjacentCell.textContent !== '') {
adjacentCell.classList.add('adjacent');
}
}
});
}
// 处理格子点击
function handleCellClick(cell) {
// 忽略空单元格
if (cell.textContent === '') return;
switch(gameState) {
case 'selectFirst':
// 选择第一个数字
clearSelections();
cell.classList.add('selected');
firstCell = cell;
gameState = 'selectOperator';
highlightAdjacentCells(cell);
statusBar.textContent = `已选择: ${cell.textContent} → 请选择运算符`;
break;
case 'selectOperator':
// 在等待选择运算符时点击数字,视为重新选择第一个数字
clearSelections();
cell.classList.add('selected');
firstCell = cell;
highlightAdjacentCells(cell);
statusBar.textContent = `已选择: ${cell.textContent} → 请选择运算符`;
break;
case 'selectSecond':
// 检查是否相邻
const firstRow = parseInt(firstCell.dataset.row);
const firstCol = parseInt(firstCell.dataset.col);
const secondRow = parseInt(cell.dataset.row);
const secondCol = parseInt(cell.dataset.col);
const rowDiff = Math.abs(firstRow - secondRow);
const colDiff = Math.abs(firstCol - secondCol);
// 相邻判断:行或列差1,但不能同时差1(对角线)
const isAdjacent = (rowDiff === 1 && colDiff === 0) ||
(rowDiff === 0 && colDiff === 1);
if (!isAdjacent) {
statusBar.textContent = '错误:只能选择相邻的格子!';
return;
}
// 选择第二个数字
if (cell === firstCell) {
statusBar.textContent = '不能选择同一个格子!请选择另一个数字';
return;
}
const firstValue = parseFloat(firstCell.textContent);
const secondValue = parseFloat(cell.textContent);
// 执行运算
let result;
let operationSymbol;
switch(selectedOperator) {
case '+':
result = firstValue + secondValue;
operationSymbol = '+';
break;
case '-':
result = firstValue - secondValue;
operationSymbol = '-';
break;
case '*':
result = firstValue * secondValue;
operationSymbol = '×';
break;
case '/':
if (secondValue === 0) {
statusBar.textContent = '错误:不能除以零!';
resetOperation();
return;
}
result = firstValue / secondValue;
operationSymbol = '÷';
break;
}
// 检查结果是否为正整数
if (result <= 0 || !Number.isInteger(result)) {
statusBar.textContent = '错误:结果必须为正整数!';
resetOperation();
return;
}
// 保存原始值用于回退
const originalFirstValue = firstCell.textContent;
const originalSecondValue = cell.textContent;
// 更新第一个格子
firstCell.textContent = result;
firstCell.dataset.value = result;
firstCell.classList.add('operator-source');
firstCell.classList.remove('selected');
firstCell.classList.add('new-value');
// 清空第二个格子
cell.textContent = '';
cell.dataset.value = '';
cell.classList.remove('selected');
cell.classList.add('empty');
// 更新操作次数
moveCount++;
moveCountEl.textContent = moveCount;
// 显示操作结果
statusBar.innerHTML = `
<span style="color: #43cea2;">${originalFirstValue}</span>
${operationSymbol}
<span style="color: #43cea2;">${originalSecondValue}</span>
=
<span style="color: #EA4C89; font-weight: bold;">${result}</span>
`;
// 执行数字下移和填充
setTimeout(() => {
fillEmptyCells();
firstCell.classList.remove('new-value');
// 结算目标数字
setTimeout(() => {
settleTargetNumbers();
}, 600);
}, 800);
break;
}
}
// 结算目标数字
function settleTargetNumbers() {
let targetCells = [];
// 检查所有格子是否包含目标数字
cells.forEach(cell => {
if (cell.textContent === targetNumber.toString() &&
!cell.classList.contains('empty')) {
targetCells.push(cell);
}
});
if (targetCells.length > 0) {
// 高亮目标格子
targetCells.forEach(cell => {
cell.classList.add('target-match');
});
// 清空目标格子
setTimeout(() => {
targetCells.forEach(cell => {
cell.classList.add('disappear');
setTimeout(() => {
cell.textContent = '';
cell.dataset.value = '';
cell.classList.add('empty');
cell.classList.remove('target-match', 'disappear');
}, 400);
});
// 增加当前分数
currentScore = targetNumber;
currentScoreEl.textContent = currentScore;
// 更新最高分
if (currentScore > highScore) {
highScore = currentScore;
highScoreEl.textContent = highScore;
localStorage.setItem('highScore', highScore);
}
// 目标数字递增
targetNumber++;
targetDisplay.textContent = targetNumber;
// 重置剩余机会
remainingChances = 3;
updateChancesDisplay();
// 状态提示
statusBar.innerHTML = `<span style="color: #27ae60;">达成目标 ${targetNumber-1}!新目标: ${targetNumber}</span>`;
// 执行数字下移和填充
setTimeout(() => {
fillEmptyCells();
resetOperation();
}, 600);
}, 800);
} else {
// 未找到目标数字
remainingChances--;
updateChancesDisplay();
if (remainingChances <= 0) {
// 游戏结束
gameOver();
} else {
statusBar.innerHTML = `<span style="color: #e67e22;">未找到目标数字 ${targetNumber},剩余机会: ${remainingChances}</span>`;
}
// 重置所有按钮状态
resetOperation();
}
}
// 更新机会显示
function updateChancesDisplay() {
const chances = chancesContainer.querySelectorAll('.chance');
chances.forEach((chance, index) => {
if (index < remainingChances) {
chance.classList.remove('lost');
} else {
chance.classList.add('lost');
}
});
}
// 游戏结束
function gameOver() {
gameActive = false;
statusBar.innerHTML = `<span style="color: #e74c3c; font-size: 1.4rem;">游戏结束!最终得分: ${currentScore}</span>`;
// 禁用操作
cells.forEach(cell => {
cell.style.pointerEvents = 'none';
});
operatorBtns.forEach(btn => {
btn.style.pointerEvents = 'none';
});
}
// 填充空单元格
function fillEmptyCells() {
// 第一步:从上到下,从左到右移动数字填补空白
// 创建一个二维数组表示当前网格状态
let grid = [[], [], []];
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 4; col++) {
const index = row * 4 + col;
grid[row][col] = {
element: cells[index],
value: cells[index].textContent,
row: row,
col: col
};
}
}
// 移动数字填补空白(重力效果)
for (let col = 0; col < 4; col++) {
for (let row = 2; row >= 0; row--) {
if (grid[row][col].value === '') {
// 寻找上方第一个非空格子
let found = false;
for (let above = row - 1; above >= 0; above--) {
if (grid[above][col].value !== '') {
// 移动数字
const targetCell = grid[row][col].element;
const sourceCell = grid[above][col].element;
targetCell.textContent = sourceCell.textContent;
targetCell.dataset.value = sourceCell.dataset.value;
targetCell.classList.remove('empty');
targetCell.classList.add('fall-animation');
sourceCell.textContent = '';
sourceCell.dataset.value = '';
sourceCell.classList.add('empty');
// 更新grid状态
grid[row][col].value = targetCell.textContent;
grid[above][col].value = '';
found = true;
// 设置动画后移除类
setTimeout(() => {
targetCell.classList.remove('fall-animation');
}, 500);
break;
}
}
}
}
}
// 第二步:填充第一行的空白
for (let col = 0; col < 4; col++) {
const topCell = grid[0][col].element;
if (topCell.textContent === '') {
topCell.textContent = nextNewNumber;
topCell.dataset.value = nextNewNumber;
topCell.classList.remove('empty');
topCell.classList.add('new-value');
// 设置新数字动画
setTimeout(() => {
topCell.classList.remove('new-value');
}, 800);
nextNewNumber++;
}
}
}
// 处理运算符点击
operatorBtns.forEach(btn => {
btn.addEventListener('click', () => {
if (!gameActive) return;
// 只在选择运算符状态有效
if (gameState !== 'selectOperator' && gameState !== 'selectSecond') return;
// 清除之前选择的运算符
operatorBtns.forEach(b => b.classList.remove('selected'));
// 设置当前选择的运算符
btn.classList.add('selected');
selectedOperator = btn.dataset.operator;
gameState = 'selectSecond';
// 更新状态栏
statusBar.textContent = `已选择: ${firstCell.textContent} ${getOperatorSymbol(selectedOperator)} ? → 请选择相邻的第二个数字`;
});
});
// 获取运算符的显示符号
function getOperatorSymbol(operator) {
switch(operator) {
case '+': return '+';
case '-': return '-';
case '*': return '×';
case '/': return '÷';
default: return operator;
}
}
// 清除所有选择状态
function clearSelections() {
cells.forEach(cell => {
cell.classList.remove('selected', 'operator-source', 'adjacent');
});
operatorBtns.forEach(btn => {
btn.classList.remove('selected');
});
}
// 重置操作状态
function resetOperation() {
gameState = 'selectFirst';
firstCell = null;
selectedOperator = null;
clearSelections();
}
// 重置游戏
resetBtn.addEventListener('click', () => {
// 重置所有格子
createGrid();
// 重置状态
resetOperation();
moveCount = 0;
moveCountEl.textContent = moveCount;
nextNewNumber = 13;
targetNumber = 1;
remainingChances = 3;
currentScore = 0;
targetDisplay.textContent = targetNumber;
currentScoreEl.textContent = currentScore;
updateChancesDisplay();
statusBar.textContent = '游戏已重置!请点击"开始游戏"';
gameActive = false;
// 启用操作
cells.forEach(cell => {
cell.style.pointerEvents = 'auto';
});
operatorBtns.forEach(btn => {
btn.style.pointerEvents = 'auto';
});
});
// 开始游戏
startBtn.addEventListener('click', () => {
if (!gameActive) {
createGrid();
gameActive = true;
gameState = 'selectFirst';
statusBar.textContent = '游戏开始!请选择第一个数字';
// 加载最高分
const savedHighScore = localStorage.getItem('highScore');
if (savedHighScore) {
highScore = parseInt(savedHighScore);
highScoreEl.textContent = highScore;
}
}
});
// 提示按钮
hintBtn.addEventListener('click', () => {
statusBar.innerHTML = `
<div style="text-align: left; padding: 10px;">
<h3>游戏说明:</h3>
<p>1. 选择相邻数字进行运算,结果必须为正整数</p>
<p>2. 目标数字:<span style="color: #e74c3c; font-weight: bold;">${targetNumber}</span></p>
<p>3. 达成目标数字可清空格子并提高目标</p>
<p>4. 连续三次未达成目标游戏结束</p>
<p>5. 空格子会被上方数字或新数字填充</p>
</div>
`;
});
// 添加CSS动画规则
const style = document.createElement('style');
style.textContent = `
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.03); }
100% { transform: scale(1); }
}
.new-value {
animation: newValueHighlight 0.8s ease;
}
.fall-animation {
animation: fallDown 0.5s ease;
}
.disappear {
animation: disappear 0.5s ease forwards;
}
`;
document.head.appendChild(style);
// 初始化游戏
createGrid();
updateChancesDisplay();
});
</script>
</body>
</html>