前言
小时候家里有一副象棋,红黑两色,木质棋盘。那时候还不懂什么"马走日""象走田",只知道把棋子翻过来背面朝上,就成了另一种游戏。后来才知道,这叫"翻翻棋",是很多人童年都玩过的记忆。
上周用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能不能帮你实现。