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

前言

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

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

相关推荐
一乐小哥18 小时前
大龄程序员的失业自救之路——Chrome 插件从注册到审核全程踩坑总结
前端·chrome·trae
围巾哥萧尘18 小时前
约翰·科特尔《紧迫感》核心主题与关键思想🧣
trae
毅航19 小时前
Spring WebFlux 原理与实践全解析
后端·spring·trae
围巾哥萧尘20 小时前
AI工具和应用概览🧣
trae
橙某人1 天前
基于 TRAE SOLO 模式开发媒体数据分析平台 - Hackathon 🎉
vue.js·python·trae
pepedd8641 天前
AI Coding 最佳实践-从零到一全栈项目编写
前端·aigc·trae
用户4099322502121 天前
如何让FastAPI测试不再成为你的噩梦?
后端·ai编程·trae
前端日常开发1 天前
什么?纯前端还不会实现投屏
trae
潘锦1 天前
从 Claude Code到 Gemini CLI,AI Agent 的上下文管理策略
agent·claude·trae