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

前言

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

上周用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能不能帮你实现。

相关推荐
小徐_23331 小时前
老乡鸡也开源?我用 Trae SOLO 做了个像老乡鸡那样做饭小程序!
前端·trae
用户4099322502128 小时前
PostgreSQL数据类型怎么选才高效不踩坑?
后端·ai编程·trae
用户4099322502122 天前
PostgreSQL UPDATE语句怎么玩?从改邮箱到批量更新的避坑技巧你都会吗?
后端·ai编程·trae
用户4099322502126 天前
PostgreSQL 17安装总翻车?Windows/macOS/Linux避坑指南帮你搞定?
后端·ai编程·trae
用户4099322502127 天前
能当关系型数据库还能玩对象特性,能拆复杂查询还能自动管库存,PostgreSQL 凭什么这么香?
后端·ai编程·trae
豆包MarsCode8 天前
基于 TRAE 的自动化测试用例智能生成方案
trae
岛风风8 天前
你还在让ai这样解决编程问题?
程序员·trae
用户4099322502128 天前
给接口加新字段又不搞崩老客户端?FastAPI的多版本API靠哪三招实现?
后端·ai编程·trae
程序员爱钓鱼9 天前
Go语言100个实战案例-项目实战篇:股票行情数据爬虫
后端·go·trae
用户40993225021210 天前
FastAPI秒杀库存总变负数?Redis分布式锁能帮你守住底线吗
后端·ai编程·trae