最终效果

在这里插入图片描述
在这里插入图片描述

前言

中秋佳节,月圆人团圆。月饼、玉兔、明月、灯笼——这些传统元素构成了中秋节独特的文化符号。为了让更多人在数字时代也能感受到传统节日的魅力,我设计并实现了这款"中秋连连看"小游戏。

连连看作为一款经典的益智游戏,规则简单却不失趣味性,特别适合在节日期间与家人朋友共同娱乐。本项目将传统的连连看玩法与中秋元素相结合,通过纯前端技术(HTML + CSS + JavaScript)实现了一个功能完整、可实际游玩的小游戏。

游戏特色

  • 完全可玩:不是Demo,是真正可以玩的游戏
  • 中秋主题:月饼、玉兔等8种中秋元素图案
  • 多种难度:简单(8×8)、普通(10×10)、困难(12×12)三种模式
  • 智能提示:卡住时可使用提示功能
  • 重排功能:当无法继续时自动或手动重排
  • 计时系统:限时挑战增加紧张感
  • 关卡系统:无限关卡,挑战你的极限
  • 精美界面:渐变背景、动画效果、响应式设计

游戏介绍

基本规则:

  1. 点击两个相同的图案进行配对
  2. 两个图案之间的连接路径不能超过2个转折点
  3. 连接路径上不能有其他图案阻挡
  4. 成功配对后图案消除,获得分数
  5. 在规定时间内消除所有图案即可过关

得分规则:

  • 基础分:每对10分
  • 连击奖励:连续消除有额外加分(1.5倍递增)
  • 时间奖励:剩余时间×2作为额外奖励

道具系统:

  • 提示:显示一对可消除的图案(3次)
  • 重排:重新打乱剩余图案位置(3次)

游戏元素

本游戏使用8种中秋主题的Emoji图案:

  • 月饼
  • 玉兔
  • 满月
  • 灯笼
  • 月牙
  • 竹子
  • 稻穗
  • 枫叶

技术架构

技术栈

  • HTML5:结构化标记语言
  • CSS3:样式、动画、渐变、响应式设计
  • JavaScript ES6+:游戏逻辑、算法实现
  • Canvas API:绘制连接线

项目结构

zhongqiu/
├── lianliankan.html          # 主HTML文件
├── lianliankan.css           # 样式文件
├── lianliankan.js            # 游戏逻辑
└── 连连看游戏技术文章.md      # 技术文档

核心模块划分

游戏系统
├── 游戏初始化模块
│   ├── 配置管理
│   ├── 状态初始化
│   └── 事件绑定
│
├── 棋盘管理模块
│   ├── 棋盘生成
│   ├── 图案分配
│   ├── 渲染更新
│   └── 重排功能
│
├── 交互处理模块
│   ├── 点击事件
│   ├── 选择逻辑
│   ├── 匹配判定
│   └── 消除动画
│
├── 算法核心模块
│   ├── 路径查找
│   ├── 直线判定
│   ├── 一次转折
│   ├── 两次转折
│   └── 有效移动检测
│
├── 游戏控制模块
│   ├── 计时系统
│   ├── 计分系统
│   ├── 关卡管理
│   ├── 暂停/继续
│   └── 结束判定
│
└── UI展示模块
    ├── 界面更新
    ├── 消息提示
    ├── 弹窗管理
    ├── 进度显示
    └── Canvas绘图

HTML结构设计

整体布局

HTML采用语义化标签,清晰地划分了游戏的各个功能区域:

<body>
  <!-- 背景装饰层 -->
      <div class="bg-decoration">
      月亮、星星、灯笼等装饰元素
    </div>
    <!-- 主游戏容器 -->
        <div class="game-container">
        <!-- 标题区 -->
        <header class="game-header"></header>
          <!-- 信息栏 -->
          <div class="game-info"></div>
            <!-- 控制按钮 -->
            <div class="game-controls"></div>
              <!-- 游戏棋盘 -->
                  <div class="game-board-container">
                <div class="game-board"></div>
                <canvas class="line-canvas"></canvas>
                </div>
                <!-- 进度条 -->
                <div class="progress-container"></div>
                  <!-- 消息提示 -->
                  <div class="game-message"></div>
                  </div>
                  <!-- 各种弹窗 -->
                  <div class="modal" id="startModal"></div>
                  <div class="modal" id="pauseModal"></div>
                  <div class="modal" id="endModal"></div>
                  </body>

关键设计点

  1. 背景装饰层:使用固定定位,不影响游戏区域的交互
  2. 游戏棋盘:采用CSS Grid布局,灵活适应不同难度的网格大小
  3. Canvas画布:覆盖在棋盘上方,用于绘制连接线
  4. 弹窗系统:统一的modal样式,通过显隐控制不同场景

数据属性设计

每个棋子使用data-*属性存储坐标:

<div class="tile" data-row="3" data-col="5"></div>

这样便于在JavaScript中快速定位和操作。


CSS样式实现

1. 整体风格

采用现代化、扁平化的设计风格,配合中秋主题的配色方案:

主色调:

  • 背景:深紫色渐变(#1a237e → #4a148c)
  • 主要元素:白色半透明卡片(backdrop-filter毛玻璃效果)
  • 强调色:红色(#d32f2f)、金黄色(#ffd700)
body {
background: linear-gradient(135deg,
#1a237e 0%,
#311b92 50%,
#4a148c 100%);
}
.game-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
}

2. 背景装饰动画

月亮呼吸效果:

.moon-bg {
animation: moonPulse 8s ease-in-out infinite;
}
@keyframes moonPulse {
0%, 100% {
transform: scale(1);
opacity: 0.8;
}
50% {
transform: scale(1.05);
opacity: 1;
}
}

星空移动效果:

使用径向渐变创建星星,配合background-position动画:

.stars-bg {
background-image:
radial-gradient(2px 2px at 20% 30%, white, transparent),
radial-gradient(2px 2px at 60% 70%, white, transparent),
/* ... 更多星星 */;
animation: starsMove 120s linear infinite;
}

灯笼摆动效果:

@keyframes lanternSwing {
0%, 100% { transform: rotate(-5deg); }
50% { transform: rotate(5deg); }
}

3. 棋盘与棋子样式

Grid布局:

.game-board {
display: grid;
gap: 5px;
/* 通过JavaScript动态设置行列数 */
}

棋子设计:

.tile {
width: 60px;
height: 60px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
}
/* 悬停效果 */
.tile:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
}
/* 选中状态 */
.tile.selected {
background: linear-gradient(135deg, #ffd700, #ffed4e);
transform: scale(1.1);
box-shadow: 0 0 20px rgba(255, 215, 0, 0.6);
}

4. 消除动画

@keyframes matchAnimation {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.3) rotate(10deg);
opacity: 0.8;
}
100% {
transform: scale(0);
opacity: 0;
}
}

这个动画分三个阶段:

  1. 保持原状
  2. 放大并旋转
  3. 缩小消失

5. 提示闪烁效果

@keyframes hintBlink {
0%, 100% {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
50% {
box-shadow: 0 0 25px rgba(76, 175, 80, 0.8);
transform: scale(1.1);
}
}

6. 按钮渐变与悬停效果

.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.3);
}

7. 响应式设计

@media (max-width: 768px) {
.tile {
width: 45px;
height: 45px;
font-size: 1.5rem;
}
}
@media (max-width: 480px) {
.tile {
width: 35px;
height: 35px;
font-size: 1.2rem;
}
}

JavaScript核心逻辑

1. 游戏配置与状态管理

配置对象:

const GAME_CONFIG = {
tiles: ['', '', '', '', '', '', '', ''],
easy: { rows: 8, cols: 8, time: 240 },
normal: { rows: 10, cols: 10, time: 180 },
hard: { rows: 12, cols: 12, time: 120 },
pointsPerMatch: 10,
comboMultiplier: 1.5
};

状态对象:

let gameState = {
board: [],              // 二维数组存储棋盘
rows: 0,                // 行数
cols: 0,                // 列数
level: 1,               // 当前关卡
score: 0,               // 分数
time: 180,              // 剩余时间
hints: 3,               // 提示次数
shuffles: 3,            // 重排次数
selectedTile: null,     // 当前选中的棋子
isPlaying: false,       // 是否正在游戏
isPaused: false,        // 是否暂停
timer: null,            // 计时器
combo: 0,               // 连击数
totalPairs: 0,          // 总对数
matchedPairs: 0,        // 已匹配对数
difficulty: 'normal'    // 难度
};

2. 棋盘初始化

生成算法:

function initBoard() {
const { rows, cols } = gameState;
const totalCells = rows * cols;
gameState.totalPairs = totalCells / 2;
// 1. 创建图案对
const tiles = [];
const tilesPerType = totalCells / GAME_CONFIG.tiles.length;
GAME_CONFIG.tiles.forEach(tile => {
for (let i = 0; i < tilesPerType / 2; i++) {
tiles.push(tile, tile);  // 成对添加
}
});
// 2. 打乱图案
shuffleArray(tiles);
// 3. 填充二维数组
gameState.board = [];
for (let i = 0; i < rows; i++) {
gameState.board[i] = [];
for (let j = 0; j < cols; j++) {
gameState.board[i][j] = tiles[i * cols + j];
}
}
renderBoard();
}

关键点:

  • 确保每种图案有偶数个(成对)
  • 使用Fisher-Yates算法打乱数组
  • 按行列顺序填充二维数组

3. 渲染棋盘

function renderBoard() {
const { rows, cols, board } = gameState;
// 设置Grid布局
elements.gameBoard.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
elements.gameBoard.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
// 清空并重新创建
elements.gameBoard.innerHTML = '';
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const tile = document.createElement('div');
tile.className = 'tile';
tile.textContent = board[i][j];
tile.dataset.row = i;
tile.dataset.col = j;
tile.addEventListener('click', () => handleTileClick(i, j));
elements.gameBoard.appendChild(tile);
}
}
// 设置Canvas大小
const boardRect = elements.gameBoard.getBoundingClientRect();
elements.lineCanvas.width = boardRect.width;
elements.lineCanvas.height = boardRect.height;
}

4. 点击处理流程

function handleTileClick(row, col) {
// 1. 游戏状态检查
if (!gameState.isPlaying || gameState.isPaused) return;
const clickedTile = getTileElement(row, col);
if (!clickedTile || clickedTile.classList.contains('empty')) return;
// 2. 点击同一个棋子,取消选择
if (gameState.selectedTile &&
gameState.selectedTile.row === row &&
gameState.selectedTile.col === col) {
deselectTile();
return;
}
// 3. 第一次点击,选中棋子
if (!gameState.selectedTile) {
selectTile(row, col);
return;
}
// 4. 第二次点击,尝试匹配
const firstTile = gameState.selectedTile;
// 检查图案是否相同
if (gameState.board[firstTile.row][firstTile.col] !==
gameState.board[row][col]) {
deselectTile();
selectTile(row, col);
showMessage('图案不匹配', 'error');
return;
}
// 检查是否可连接
const path = findPath(firstTile.row, firstTile.col, row, col);
if (path) {
matchTiles(firstTile.row, firstTile.col, row, col, path);
} else {
deselectTile();
selectTile(row, col);
showMessage('无法连接', 'error');
}
}

流程图:

点击棋子
    ↓
检查游戏状态 → 暂停/结束 → 返回
    ↓
检查是否为空 → 是 → 返回
    ↓
已选同一个 → 是 → 取消选择 → 返回
    ↓
第一次选择 → 是 → 标记选中 → 返回
    ↓
第二次选择
    ↓
图案相同? → 否 → 重新选择
    ↓ 是
可以连接? → 否 → 显示提示 + 重新选择
    ↓ 是
执行消除 → 更新状态 → 检查胜利条件

连连看算法详解

这是游戏的核心,也是最复杂的部分。连连看的规则是:两个相同图案之间的连接路径最多只能有2个转折点

算法分类

  1. 直线连接(0个转折)
  2. 一次转折连接(1个转折)
  3. 两次转折连接(2个转折)

1. 直线连接

两点在同一行或同一列,且之间无障碍物。

function canConnectDirect(row1, col1, row2, col2) {
// 同一行
if (row1 === row2) {
const minCol = Math.min(col1, col2);
const maxCol = Math.max(col1, col2);
for (let col = minCol + 1; col < maxCol; col++) {
if (gameState.board[row1][col] !== null) {
return false;  // 有障碍
}
}
return true;
}
// 同一列
if (col1 === col2) {
const minRow = Math.min(row1, row2);
const maxRow = Math.max(row1, row2);
for (let row = minRow + 1; row < maxRow; row++) {
if (gameState.board[row][col1] !== null) {
return false;  // 有障碍
}
}
return true;
}
return false;
}

示意图:

横向直线:
 . . .    ✓ 可连接
 .  .    ✗ 中间有障碍
纵向直线:

.
.
   ✓ 可连接

2. 一次转折连接

经过一个转折点连接两点。转折点有两种可能:

  • (row1, col2):先横后竖
  • (row2, col1):先竖后横
function canConnectWithOneTurn(row1, col1, row2, col2) {
// 转折点1: (row1, col2)
if (isEmpty(row1, col2) || (row1 === row2 && col1 === col2)) {
if (canConnectDirect(row1, col1, row1, col2) &&
canConnectDirect(row1, col2, row2, col2)) {
return [[row1, col1], [row1, col2], [row2, col2]];
}
}
// 转折点2: (row2, col1)
if (isEmpty(row2, col1) || (row1 === row2 && col1 === col2)) {
if (canConnectDirect(row1, col1, row2, col1) &&
canConnectDirect(row2, col1, row2, col2)) {
return [[row1, col1], [row2, col1], [row2, col2]];
}
}
return null;
}

示意图:

转折点 (row1, col2):
 → → ↓
      ↓
      
转折点 (row2, col1):

↓
↓
→ → → 

3. 两次转折连接

需要经过两个转折点。策略:

  • 尝试在每一行寻找可行的中转点
  • 尝试在每一列寻找可行的中转点
function canConnectWithTwoTurns(row1, col1, row2, col2) {
const { rows, cols } = gameState;
// 通过行扩展 (寻找横向中转线)
for (let col = 0; col < cols; col++) {
if (col === col1 || col === col2) continue;
if ((isEmpty(row1, col) || col === col2) &&
(isEmpty(row2, col) || col === col1)) {
if (canConnectDirect(row1, col1, row1, col) &&
canConnectDirect(row1, col, row2, col) &&
canConnectDirect(row2, col, row2, col2)) {
return [[row1, col1], [row1, col], [row2, col], [row2, col2]];
}
}
}
// 通过列扩展 (寻找纵向中转线)
for (let row = 0; row < rows; row++) {
if (row === row1 || row === row2) continue;
if ((isEmpty(row, col1) || row === row2) &&
(isEmpty(row, col2) || row === row1)) {
if (canConnectDirect(row1, col1, row, col1) &&
canConnectDirect(row, col1, row, col2) &&
canConnectDirect(row, col2, row2, col2)) {
return [[row1, col1], [row, col1], [row, col2], [row2, col2]];
}
}
}
return null;
}

示意图:

横向中转:
 → → → col
         ↓
         ↓
       ← col
纵向中转:

↓
↓
row → → → 

路径查找总控函数

function findPath(row1, col1, row2, col2) {
// 1. 尝试直线连接
if (canConnectDirect(row1, col1, row2, col2)) {
return [[row1, col1], [row2, col2]];
}
// 2. 尝试一次转折
const oneTurn = canConnectWithOneTurn(row1, col1, row2, col2);
if (oneTurn) return oneTurn;
// 3. 尝试两次转折
const twoTurns = canConnectWithTwoTurns(row1, col1, row2, col2);
if (twoTurns) return twoTurns;
// 4. 无法连接
return null;
}

算法复杂度分析

  • 直线连接:O(n),n为行数或列数
  • 一次转折:O(n),最多检查2个转折点
  • 两次转折:O(n²),需要遍历所有可能的中转线
  • 总体:O(n²),可接受的时间复杂度

游戏状态管理

计时系统

function startTimer() {
if (gameState.timer) clearInterval(gameState.timer);
gameState.timer = setInterval(() => {
if (gameState.isPaused) return;
gameState.time--;
updateUI();
// 时间警告
if (gameState.time === 30) {
showMessage('⚠️ 只剩30秒了!', 'error');
}
// 时间到
if (gameState.time <= 0) {
loseGame();
}
}, 1000);
}

设计考虑:

  • 暂停时不计时(通过检查isPaused标志)
  • 最后30秒警告提醒
  • 时间归零触发失败

计分系统

基础分数:

const basePoints = GAME_CONFIG.pointsPerMatch;  // 10分

连击加成:

gameState.combo++;  // 每次成功匹配增加连击数
let points = basePoints;
if (gameState.combo > 1) {
// 1.5倍递增:10, 15, 22, 33, 49, ...
points = Math.floor(
basePoints * Math.pow(GAME_CONFIG.comboMultiplier, gameState.combo - 1)
);
}

时间奖励:

const timeBonus = gameState.time * 2;  // 剩余每秒2分
gameState.score += timeBonus;

匹配逻辑

function matchTiles(row1, col1, row2, col2, path) {
// 1. 绘制连接线
drawPath(path);
// 2. 增加连击
gameState.combo++;
// 3. 计算分数
let points = GAME_CONFIG.pointsPerMatch;
if (gameState.combo > 1) {
points = Math.floor(
points * Math.pow(GAME_CONFIG.comboMultiplier, gameState.combo - 1)
);
showMessage(`连击 x${gameState.combo}! +${points}`, 'combo');
} else {
showMessage(`匹配成功! +${points}`, 'success');
}
gameState.score += points;
gameState.matchedPairs++;
// 4. 延迟后移除棋子(显示动画)
setTimeout(() => {
removeTiles(row1, col1, row2, col2);
updateUI();
// 5. 检查胜利/失败条件
checkGameEnd();
}, 500);
}

胜利与失败判定

function checkGameEnd() {
// 全部消除 → 胜利
if (gameState.matchedPairs >= gameState.totalPairs) {
setTimeout(() => winGame(), 500);
return;
}
// 无有效移动 → 自动重排
if (!hasValidMoves()) {
showMessage('没有可消除的图案了!自动重排...', 'error');
setTimeout(() => shuffleBoard(), 1500);
}
}
// 时间到 → 失败
if (gameState.time <= 0) {
loseGame();
}

UI交互设计

Canvas绘制连接线

function drawPath(path) {
const canvas = elements.lineCanvas;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
const tileSize = 60 + 5;  // 棋子大小 + 间距
const offset = tileSize / 2 + 20;  // 棋盘padding
ctx.strokeStyle = '#4caf50';  // 绿色
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.beginPath();
// 连接路径上的所有点
for (let i = 0; i < path.length; i++) {
const [row, col] = path[i];
const x = col * tileSize + offset;
const y = row * tileSize + offset;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
// 500ms后清除
setTimeout(() => clearCanvas(), 500);
}

提示功能

function useHint() {
if (gameState.hints <= 0) {
showMessage('没有提示次数了!', 'error');
return;
}
// 查找一对可消除的图案
const validMove = findValidMove();
if (validMove) {
gameState.hints--;
const [row1, col1, row2, col2] = validMove;
// 添加闪烁效果
const tile1 = getTileElement(row1, col1);
const tile2 = getTileElement(row2, col2);
if (tile1) tile1.classList.add('hint');
if (tile2) tile2.classList.add('hint');
// 3秒后移除效果
setTimeout(() => {
if (tile1) tile1.classList.remove('hint');
if (tile2) tile2.classList.remove('hint');
}, 3000);
updateUI();
showMessage(' 已显示提示', 'success');
} else {
showMessage('没有可消除的图案!', 'error');
}
}

查找有效移动:

function findValidMove() {
const { rows, cols, board } = gameState;
// 双重循环遍历所有可能的配对
for (let i1 = 0; i1 < rows; i1++) {
for (let j1 = 0; j1 < cols; j1++) {
if (board[i1][j1] === null) continue;
for (let i2 = 0; i2 < rows; i2++) {
for (let j2 = 0; j2 < cols; j2++) {
if (board[i2][j2] === null) continue;
if (i1 === i2 && j1 === j2) continue;
// 图案相同且可连接
if (board[i1][j1] === board[i2][j2]) {
if (findPath(i1, j1, i2, j2)) {
return [i1, j1, i2, j2];
}
}
}
}
}
}
return null;
}

重排功能

function shuffleBoard() {
// 1. 收集所有非空棋子
const tiles = [];
const { rows, cols, board } = gameState;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (board[i][j] !== null) {
tiles.push(board[i][j]);
}
}
}
// 2. 打乱
shuffleArray(tiles);
// 3. 重新分配到非空位置
let index = 0;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (board[i][j] !== null) {
board[i][j] = tiles[index++];
}
}
}
// 4. 重新渲染
renderBoard();
updateUI();
showMessage(' 棋盘已重排!', 'success');
}

弹窗管理

function showModal(modalId) {
document.getElementById(modalId).classList.remove('hidden');
}
function hideModal(modalId) {
document.getElementById(modalId).classList.add('hidden');
}

三种弹窗:

  1. 开始弹窗:游戏介绍、难度选择
  2. 暂停弹窗:暂停时显示
  3. 结束弹窗:胜利/失败统计

消息提示系统

function showMessage(message, type = '') {
elements.gameMessage.textContent = message;
elements.gameMessage.className = 'game-message ' + type;
// 2秒后自动清除
setTimeout(() => {
elements.gameMessage.textContent = '';
elements.gameMessage.className = 'game-message';
}, 2000);
}

消息类型:

  • success:绿色,成功操作
  • error:红色,错误提示
  • combo:橙色,连击提示

最终实现场景

游戏启动流程

  1. 打开页面

    • 显示精美的背景(月亮、星星、灯笼)
    • 弹出开始弹窗
  2. 选择难度

    • 简单:8×8,240秒
    • 普通:10×10,180秒
    • 困难:12×12,120秒
  3. 点击开始

    • 生成随机棋盘
    • 启动倒计时
    • 按钮变为可用状态

游戏进行中

正常游玩:

[查看棋盘] → [点击第一个棋子] → [高亮显示]
    ↓
[点击第二个棋子]
    ↓
[判断是否匹配]
    ├─ 匹配且可连接 → [绘制路径] → [播放动画] → [消除] → [加分]
    └─ 不匹配/无法连接 → [提示错误] → [重新选择]

使用道具:

  • 点击"提示"按钮 → 两个可消除的棋子闪烁
  • 点击"重排"按钮 → 剩余棋子重新打乱
  • 点击"暂停"按钮 → 弹出暂停窗口,计时暂停

连击系统:

第1对:+10分
第2对:+15分(连击x2)
第3对:+22分(连击x3)
第4对:+33分(连击x4)
...

游戏结束

胜利条件:

  • 在规定时间内消除所有棋子

胜利界面:

 恭喜过关!
最终得分:1250
剩余时间:45秒
时间奖励:+90分
当前关卡:3
[下一关] [返回主菜单]

失败条件:

  • 时间归零

失败界面:

 时间到!
最终得分:680
已消除:28/50对
完成度:56%
[重新挑战] [返回主菜单]

关卡递进

每通过一关:

  • 关卡数 +1
  • 保持之前的总分
  • 时间重置
  • 道具次数重置

实际游玩体验

第1关(普通难度):

  • 10×10的棋盘,100个棋子(50对)
  • 8种图案,每种12-13个
  • 180秒倒计时
  • 新手较容易,图案分布均匀

第5关:

  • 同样10×10,但因为熟练度提升,玩得更快
  • 连击次数增多,高分段出现
  • 策略性增强(先消边缘还是中间?)

高难度挑战:

  • 12×12的棋盘,144个棋子(72对)
  • 只有120秒
  • 极度考验观察力和反应速度
  • 提示和重排要谨慎使用

技术总结

关键技术点

  1. 数据结构

    • 二维数组存储棋盘状态
    • 对象管理游戏状态
    • 数组存储路径信息
  2. 算法实现

    • Fisher-Yates洗牌算法
    • 路径搜索算法(DFS思想)
    • 有效移动检测
  3. DOM操作

    • 动态创建元素
    • Grid布局应用
    • 事件监听与处理
  4. Canvas绘图

    • 2D上下文操作
    • 路径绘制
    • 动画清除
  5. CSS动画

    • Keyframes定义
    • Transform变换
    • Transition过渡
  6. 游戏设计

    • 状态机管理
    • 计时系统
    • 计分机制
    • UI反馈

使用说明

快速开始

  1. 下载文件

    # 确保以下三个文件在同一目录
    - lianliankan.html
    - lianliankan.css
    - lianliankan.js
  2. 打开游戏

    • 直接在浏览器中打开 lianliankan.html
    • 或使用本地服务器:
      python -m http.server 8000
      # 访问 http://localhost:8000/lianliankan.html
  3. 开始游玩

    • 阅读游戏说明
    • 选择难度
    • 点击"开始游戏"

操作指南

鼠标操作:

  • 点击棋子选择
  • 再次点击可消除的图案配对
  • 点击控制按钮使用功能

按钮说明:

  • 开始游戏:开始新游戏
  • ⏸️ 暂停:暂停当前游戏
  • 提示:显示一对可消除的图案
  • 重排:重新打乱剩余图案
  • 重新开始:返回主菜单

结语

用代码绘制节日,用技术传承文化。愿每一位开发者都能在创作中感受到编程的乐趣,在分享中传递技术的温度。

最好祝大家中秋快乐!Happy Mid-Autumn Festival! ✨


参考资源