五子棋游戏
五子棋是一款传统的两人策略型棋类游戏,游戏的目的是在棋盘上首先形成连续的五个同色棋子的玩家获胜。游戏规则简单,易于上手,但要达到高手水平则需要相当的策略和技巧。
游戏设计思路
-
游戏核心组件:
- 棋盘组件:绘制15×15的网格
- 棋子组件:显示黑白棋子
- 游戏状态管理:处理落子、胜负判断
- 控制面板:显示当前玩家和游戏控制
-
游戏流程:
- 黑方先行,玩家轮流在交叉点落子
- 当形成5个同色棋子连线时游戏结束
- 显示胜利方并提供重新开始选项
完整代码实现
import { display } from '@kit.ArkUI';
// 游戏状态管理类 - 简化版
class GomokuGame {
// 棋盘尺寸
static BOARD_SIZE = 15;
// 棋盘状态:0=空, 1=黑子, 2=白子
board: number[][];
// 当前玩家:1=黑子, 2=白子
currentPlayer: number;
// 游戏状态:true=已结束, false=进行中
gameOver: boolean;
// 胜利者:0=无, 1=黑子, 2=白子
winner: number;
constructor() {
this.resetGame();
}
// 重置游戏状态
resetGame() {
// 创建空棋盘
this.board = Array(GomokuGame.BOARD_SIZE).fill(0)
.map(() => Array(GomokuGame.BOARD_SIZE).fill(0));
this.currentPlayer = 1; // 黑子先行
this.gameOver = false;
this.winner = 0;
}
// 在指定位置落子
placePiece(row: number, col: number): boolean {
// 如果游戏结束或位置已有棋子,返回false
if (this.gameOver || this.board[row][col] !== 0) {
return false;
}
// 放置棋子
this.board[row][col] = this.currentPlayer;
// 检查是否获胜
if (this.checkWin(row, col)) {
this.gameOver = true;
this.winner = this.currentPlayer;
return true;
}
// 切换玩家
this.currentPlayer = this.currentPlayer === 1 ? 2 : 1;
return true;
}
// 检查是否获胜
private checkWin(row: number, col: number): boolean {
// 定义检查方向:水平、垂直、两条对角线
const directions = [
[[0, 1], [0, -1]], // 水平
[[1, 0], [-1, 0]], // 垂直
[[1, 1], [-1, -1]], // 右下对角线
[[1, -1], [-1, 1]] // 左下对角线
];
for (const direction of directions) {
let count = 1; // 当前位置已经有一个棋子
// 检查两个相反方向
for (const [dx, dy] of direction) {
let r = row + dx;
let c = col + dy;
// 沿着方向计数连续的同色棋子
while (
r >= 0 && r < GomokuGame.BOARD_SIZE &&
c >= 0 && c < GomokuGame.BOARD_SIZE &&
this.board[r][c] === this.currentPlayer
) {
count++;
r += dx;
c += dy;
}
}
// 如果连续棋子数达到5,获胜
if (count >= 5) {
return true;
}
}
return false;
}
}
// 棋盘组件
@Component
struct GameBoard {
// 引用游戏状态
@ObjectLink game: GomokuGame;
// 棋盘尺寸计算
@State private boardSize: number = 0;
@State private cellSize: number = 0;
// 棋盘边距
private boardPadding: number = 20;
// 屏幕尺寸
private screenWidth: number = display.getDefaultDisplaySync().width;
aboutToAppear() {
this.calculateBoardSize();
}
// 计算棋盘尺寸
private calculateBoardSize() {
// 棋盘宽度 = 屏幕宽度 - 两边边距
this.boardSize = this.screenWidth - 2 * this.boardPadding;
// 每个格子的大小
this.cellSize = this.boardSize / (GomokuGame.BOARD_SIZE - 1);
}
// 处理点击事件
private handleTap(event: ClickEvent) {
if (this.game.gameOver) return;
// 计算点击位置对应的棋盘坐标
const col = Math.round((event.x - this.boardPadding) / this.cellSize);
const row = Math.round((event.y - this.boardPadding) / this.cellSize);
// 确保坐标在棋盘范围内
if (row >= 0 && row < GomokuGame.BOARD_SIZE &&
col >= 0 && col < GomokuGame.BOARD_SIZE) {
this.game.placePiece(row, col);
}
}
// 绘制棋盘网格
private drawGrid(ctx: CanvasRenderingContext2D) {
ctx.strokeStyle = '#000000';
ctx.lineWidth = 1;
// 绘制横线
for (let i = 0; i < GomokuGame.BOARD_SIZE; i++) {
const y = this.boardPadding + i * this.cellSize;
ctx.beginPath();
ctx.moveTo(this.boardPadding, y);
ctx.lineTo(this.boardPadding + this.boardSize, y);
ctx.stroke();
}
// 绘制竖线
for (let i = 0; i < GomokuGame.BOARD_SIZE; i++) {
const x = this.boardPadding + i * this.cellSize;
ctx.beginPath();
ctx.moveTo(x, this.boardPadding);
ctx.lineTo(x, this.boardPadding + this.boardSize);
ctx.stroke();
}
// 绘制星位点(天元和星)
const starPoints = [3, 7, 11];
ctx.fillStyle = '#000000';
for (const i of starPoints) {
for (const j of starPoints) {
const x = this.boardPadding + i * this.cellSize;
const y = this.boardPadding + j * this.cellSize;
ctx.beginPath();
ctx.arc(x, y, 4, 0, Math.PI * 2);
ctx.fill();
}
}
}
build() {
// 棋盘背景设置
const settings = new RenderingContextSettings(true);
const ctx = new CanvasRenderingContext2D(settings);
Stack() {
// 棋盘背景
Rect()
.width(this.boardSize + 2 * this.boardPadding)
.height(this.boardSize + 2 * this.boardPadding)
.fill('#E8C9A1') // 木色棋盘
.radius(8)
// 棋盘网格
Canvas(ctx)
.width(this.boardSize + 2 * this.boardPadding)
.height(this.boardSize + 2 * this.boardPadding)
.onReady(() => this.drawGrid(ctx))
.onClick((event) => this.handleTap(event))
// 绘制棋子
ForEach(this.game.board, (row, rowIndex) => {
ForEach(row, (cell, colIndex) => {
if (cell !== 0) {
// 棋子
Circle()
.fill(cell === 1 ? '#000000' : '#FFFFFF') // 黑子/白子
.stroke(cell === 1 ? '#000000' : '#CCCCCC')
.strokeWidth(1)
.width(this.cellSize * 0.8)
.height(this.cellSize * 0.8)
.position({
x: this.boardPadding + colIndex * this.cellSize - this.cellSize * 0.4,
y: this.boardPadding + rowIndex * this.cellSize - this.cellSize * 0.4
})
}
})
})
// 游戏结束提示
if (this.game.gameOver) {
Column() {
Text(this.game.winner === 1 ? '黑棋胜利!' : '白棋胜利!')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#FF0000')
.margin({ bottom: 20 })
Button('再来一局')
.width(120)
.height(40)
.backgroundColor('#4A86E8')
.onClick(() => this.game.resetGame())
}
.width(260)
.height(150)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.justifyContent(FlexAlign.Center)
.position({
x: (this.boardSize + 2 * this.boardPadding) / 2 - 130,
y: (this.boardSize + 2 * this.boardPadding) / 2 - 75
})
}
}
.width(this.boardSize + 2 * this.boardPadding)
.height(this.boardSize + 2 * this.boardPadding)
}
}
// 主页面
@Entry
@Component
struct GomokuApp {
// 创建游戏实例
@State game: GomokuGame = new GomokuGame();
build() {
Column() {
// 标题
Text('五子棋')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
// 当前玩家状态
Row() {
Circle()
.width(20)
.height(20)
.fill(this.game.currentPlayer === 1 ? '#000000' : '#FFFFFF')
.margin({ right: 10 })
Text(this.game.currentPlayer === 1 ? '黑方回合' : '白方回合')
.fontSize(18)
}
.padding(10)
.backgroundColor('#F0F0F0')
.borderRadius(20)
.margin({ bottom: 20 })
// 游戏棋盘
GameBoard({ game: this.game })
// 控制按钮
Row() {
Button('重新开始')
.width(120)
.height(40)
.backgroundColor('#4A86E8')
.onClick(() => this.game.resetGame())
Button('悔棋')
.width(120)
.height(40)
.backgroundColor('#999999')
.margin({ left: 20 })
.enabled(false) // 暂未实现悔棋功能
}
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Start)
}
}
游戏特点说明
-
直观的棋盘设计:
- 使用木色背景模拟真实棋盘
- 清晰的网格线和星位点
- 黑白棋子对比鲜明
-
简洁的游戏状态显示:
- 顶部显示当前玩家
- 棋子下方显示当前回合状态
- 游戏结束时有明显提示
-
清晰的游戏逻辑:
- 游戏状态管理类封装了所有游戏逻辑
- 胜负判断使用四个方向检查
- 棋盘点击处理精确到交叉点
-
响应式布局:
- 棋盘大小根据屏幕尺寸自动计算
- 在不同尺寸设备上都能良好显示
-
用户友好的交互:
- 落子后有视觉反馈
- 游戏结束提示明显
- 控制按钮布局合理