从象棋到翻翻棋,一段童年的技术回忆

前言

小时候家里有一副象棋,红黑两色,木质棋盘。那时候还不懂什么"马走日""象走田",只知道把棋子翻过来背面朝上,就成了另一种游戏。后来才知道,这叫"翻翻棋",是很多人童年都玩过的记忆。

上周用Trae写了个中国象棋,突然想起这段童年回忆,索性把翻翻棋也实现了出来。

游戏规则其实很简单

翻翻棋用的是象棋的全部棋子,但玩法完全不同:

  • 所有棋子初始都是背面朝上(显示"棋"字)
  • 玩家轮流翻开棋子或移动已翻开的己方棋子
  • 红方和黑方轮流行动
  • 吃子规则沿用象棋原规则:帅>士>相>车>马>炮>兵>帅

第一次跟Trae简单的说,Trae并没有理解我的意思

生成出来的有颜色,字体还是反的,只能再次让Trae进行修改

这次终于get我要的翻翻棋,来看看最终的效果吧~

翻开之前都是一样的,未知是红方还是黑方的棋子,让人不到最后一刻都不知道谁输谁赢

Trae的关键代码解读

整个游戏的核心在于棋子的状态管理。每个棋子有三个关键属性:

  • 类型(帅、车、马等)
  • 颜色(红方或黑方)
  • 是否已翻开

1. 棋子配置

首先定义棋子的基本配置,主要有以下这些棋子

css 复制代码
getPiecesConfig() {
    return {
        red: [
            { type: '帅', count: 1, value: 100 },
            { type: '仕', count: 2, value: 20 },
            { type: '相', count: 2, value: 20 },
            { type: '俥', count: 2, value: 45 },
            { type: '傌', count: 2, value: 40 },
            { type: '炮', count: 2, value: 45 },
            { type: '兵', count: 5, value: 10 }
        ],
        black: [
            { type: '将', count: 1, value: 100 },
            { type: '士', count: 2, value: 20 },
            { type: '象', count: 2, value: 20 },
            { type: '車', count: 2, value: 45 },
            { type: '馬', count: 2, value: 40 },
            { type: '炮', count: 2, value: 45 },
            { type: '卒', count: 5, value: 10 }
        ]
    };
}

2. 随机打乱棋子

把所有棋子打乱后分配到棋盘上,让对局充满未知性

ini 复制代码
shufflePieces() {
    const pieces = [];
    const config = this.getPiecesConfig();
    
    // 添加红方和黑方棋子
    config.red.forEach(piece => {
        for (let i = 0; i < piece.count; i++) {
            pieces.push({
                type: piece.type,
                color: 'red',
                value: piece.value,
                flipped: false
            });
        }
    });

    config.black.forEach(piece => {
        for (let i = 0; i < piece.count; i++) {
            pieces.push({
                type: piece.type,
                color: 'black',
                value: piece.value,
                flipped: false
            });
        }
    });

    // Fisher-Yates洗牌算法
    for (let i = pieces.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i 
        + 1));
        [pieces[i], pieces[j]] = [pieces[j], 
        pieces[i]];
    }

    // 分配到4x8的棋盘
    let pieceIndex = 0;
    for (let row = 0; row < 4; row++) {
        for (let col = 0; col < 8; col++) {
            this.board[row][col].piece = pieces
            [pieceIndex++];
        }
    }
}

3. 翻转动画

用CSS实现3D翻转效果,让棋子翻开时更自然,让用户的体验更加好

css 复制代码
.chess-piece {
    transition: all 0.6s ease;
    transform-style: preserve-3d;
    backface-visibility: hidden;
}

.chess-piece::before {
    content: "棋";
    color: #DEB887;
    font-size: 20px;
    position: absolute;
    transform: rotateY(0deg);
    backface-visibility: hidden;
}

.chess-piece span {
    opacity: 0;
    transform: rotateY(180deg);
    transition: all 0.6s ease;
    position: absolute;
    font-size: 16px;
    font-weight: bold;
    backface-visibility: hidden;
}

.chess-piece.flipped {
    transform: rotateY(180deg);
}

.chess-piece.flipped span {
    opacity: 1;
}

4. 游戏交互逻辑

处理玩家的点击行为,点击出现可以移动的位置

kotlin 复制代码
handleCellClick(cellElement) {
    const row = parseInt(cellElement.dataset.
    row);
    const col = parseInt(cellElement.dataset.
    col);
    const cell = this.board[row][col];

    if (!this.selectedCell) {
        // 第一次点击:翻开棋子或选择己方棋子
        if (cell.piece && !cell.piece.flipped) {
            cell.piece.flipped = true;
            this.renderBoard();
            this.switchPlayer();
        } else if (cell.piece && cell.piece.
        flipped && cell.piece.color === this.
        currentPlayer) {
            this.selectCell(row, col);
        }
    } else {
        // 第二次点击:移动棋子或取消选择
        if (this.isValidMove(this.selectedCell.
        row, this.selectedCell.col, row, col)) {
            this.makeMove(this.selectedCell.row, 
            this.selectedCell.col, row, col);
            this.deselectCell();
        }
    }
}

5. 吃子规则

实现翻翻棋特有的吃子规则

typescript 复制代码
canCapture(attacker, defender) {
    const hierarchy = {
        '帅': 7, '将': 7,
        '仕': 6, '士': 6,
        '相': 5, '象': 5,
        '俥': 4, '車': 4,
        '傌': 3, '馬': 3,
        '炮': 2,
        '兵': 1, '卒': 1
    };
    
    const attackerLevel = hierarchy[attacker.
    type];
    const defenderLevel = hierarchy[defender.
    type];
    
    // 兵可以吃帅,形成循环
    if (attackerLevel === 1 && defenderLevel === 
    7) return true;
    return attackerLevel > defenderLevel;
}

总结

写完这个翻翻棋,突然意识到童年的游戏其实都很聪明。

它们用最简单的规则,创造了最纯粹的快乐。现在用代码复现这些记忆,不是为了创新,而是为了保留那些快要被遗忘的简单美好。

如果你也想重温这段记忆,不妨试试看,看看Trae能不能帮你实现。

相关推荐
豆包MarsCode21 小时前
用 SOLO Coder 搭建 3D 机器人项目
trae
风止何安啊1 天前
收到字节的短信:Trae SOLO上线了?尝尝鲜,浅浅做个音乐播放器
前端·html·trae
天天摸鱼的java工程师1 天前
从 0 到 1:我用 Java + Vue 实现了文件上传压缩功能(附完整项目结构)
trae
五号厂房1 天前
TRAE中国版SOLO模式上线尝鲜
trae·solo
围巾哥萧尘2 天前
🚀TRAE SOLO 实战干货:从零到一部署国内版“拍立得”应用的踩坑避坑指南🧣
trae
kungggyoyoyo2 天前
TRAE中国版SOLO模式上线!我用它从0到1开发了一款AI小说编辑器
前端·vue.js·trae
围巾哥萧尘2 天前
🚀TRAE SOLO Coder :网页版“切水果”游戏开发实录,基于手势识别的互动游戏制作🧣
trae
程序员爱钓鱼2 天前
Go语言 OCR 常用识别库与实战指南
后端·go·trae
程序员爱钓鱼2 天前
使用简单 JSON + 自定义 t 函数实现轻量多语言国际化(无需 next-intl)
前端·javascript·trae
天天摸鱼的java工程师2 天前
RuoYi-Cloud 完全解剖:TRAE AI 绘制的架构蓝图
trae