当前位置: 首页 > news >正文

中国象棋人机对战

main.c

#include "game.h"
#include "user.h"
#include <stdio.h>int main() 
{// 初始化用户系统initUserSystem();// 用户登录或注册User currentUser;if (!loginOrRegister(&currentUser)) {printf("程序退出\n");return 0;}// 初始化游戏initGame();// 开始游戏startGame(&currentUser);// 清理资源cleanupUserSystem();return 0;
}

一、项目概述
本项目是一款基于传统策略对战场景的 “中国象棋” 游戏,核心支持人机对战模式(红方为玩家,黑方为 AI)。玩家通过控制红方棋子遵循象棋规则移动,目标是吃掉黑方 “将” 获胜;AI 通过 α-β 剪枝算法控制黑方棋子自动走棋。游戏具备完整的用户系统(注册、登录、用户管理)和走棋记录功能,提供兼具竞技性与传统趣味的策略对战体验。代码采用多文件模块化设计,包括主程序、棋盘管理、游戏逻辑、记录系统、用户系统等模块,实现低耦合高内聚的架构。
二、功能需求
2.1 游戏初始化功能
资源加载:
加载棋盘布局规则、棋子类型定义(红方:帅、仕、相、马、车、炮、兵;黑方:将、士、象、马、车、炮、卒)及用户数据文件(users.txt)。验证资源完整性,若用户文件缺失则自动创建;若核心规则配置错误,弹出提示 “初始化失败,请检查配置文件” 并退出。
棋盘初始化:
尺寸:采用ROW×COL网格(代码中默认为 10 行 ×9 列),以左上角为原点 (0,0),右下角为 (9,8)。
布局:横向 9 条线、纵向 10 条线,线宽 2px;中间第 4-5 行之间为 “楚河汉界” 区域,显示对应文字。
初始化:通过二维数组board[ROW][COL]存储棋子状态(0 为空位,正数为红方棋子,负数为黑方棋子),按传统规则固定摆放初始棋子(如黑方车位于 (0,0)、(0,8),红方帅位于 (9,4) 等,具体坐标见代码initBoard()函数)。
棋子初始化:
类型与属性:红方(1-7)对应帅、仕、相、马、车、炮、兵;黑方(-1 至 - 7)对应将、士、象、马、车、炮、卒(代码中pieceName()函数定义映射关系)。
显示:红方棋子以红色字体显示,黑方以白色字体显示,空位置用两空格填充(保持棋盘对齐)。
用户系统初始化:
支持 “注册”(用户名 + 密码,存储于users.txt,需校验用户名唯一性)和 “登录”(验证用户名与密码匹配)。
登录后记录用户状态(User结构体:用户名、密码、登录状态),支持游客模式(默认用户名 “红方玩家”)。
附加功能:查看用户列表、删除用户、添加用户(通过菜单交互实现)。
2.2 核心游戏流程
回合控制:
采用回合制,初始回合为红方(玩家)。每完成一步有效走棋后,自动切换至黑方(AI)回合,屏幕顶部实时显示 “当前回合:红方 / 黑方”。
棋子移动规则(基于代码isValidMove()及细分检查函数):
车:沿直线(横 / 竖)移动,路径不可有棋子阻挡(checkLineMove())。
马:走 “日” 字(坐标差 (1,2) 或 (2,1)),“蹩马腿”(日字拐角处有棋子)时不可移动(checkHorseMove())。
炮:直线移动,不吃子时路径无棋子,吃子时路径需有且仅有 1 个棋子(炮架,checkCannonMove())。
士 / 仕:沿对角线走 1 格,仅限九宫格内(红方仕:(7-9,3-5);黑方士:(0-2,3-5),checkAdvisorMove())。
象 / 相:走 “田” 字(坐标差 (2,2)),“堵象眼”(田字中心有棋子)时不可移动,且红相不超过楚河(x≤4)、黑象不超过汉界(x≥5,checkElephantMove())。
将 / 帅:九宫格内横 / 竖走 1 格,不可与对方将 / 帅直接见面(checkLineMove())。
兵 / 卒:未过河时只能前进 1 格(红兵向上,黑卒向下);过河后可左右移动 1 格(checkSoldierMove())。
合法性校验:移动需满足 “目标位置非己方棋子”“符合棋子专属规则”“不自将军”,非法操作时提示 “走法无效!请检查规则或坐标”,不切换回合。
输入控制:
玩家走棋:通过键盘输入坐标(格式 “x1 y1 x2 y2”,如 “9 0 8 0” 表示从 (9,0) 移动到 (8,0))。
功能键:q/Q退出游戏;r/R查看当前用户的走棋记录;Enter确认输入。
AI 逻辑:
基于 α-β 剪枝的 minimax 算法搜索最优走法,搜索深度由AI_DEPTH控制(代码中可配置)。
走棋流程:遍历所有黑方棋子的合法移动,通过评估函数(evaluateBoard())计算分数(棋子价值 + 将军加分),选择最高分走法。
交互:AI 思考时显示 “AI 思考中…”,走棋后输出 “AI 走棋:(x1,y1) -> (x2,y2),移动 / 吃掉红方 XX”。
胜负判定:
若玩家吃掉黑方 “将”(board[x2][y2] == B_GENERAL),判定玩家胜利。
若 AI 吃掉红方 “帅”,或玩家被 “将死”(被将军且无合法走法),判定 AI 胜利。
结果显示于屏幕中央(如 “恭喜!你赢了!”),游戏结束后返回主菜单。
2.3 记录系统功能
记录内容:
每步走棋记录包含 “时间(格式%Y-%m-%d %H:%M:%S)、走棋方(玩家 / AI)、起始坐标 (x1,y1)、目标坐标 (x2,y2)、移动棋子类型、吃掉棋子类型(若有)”。
存储与查看:
按用户存储:每个用户的记录保存至用户名_records.txt(通过saveMoveRecord()函数追加写入)。
查看方式:游戏中输入r/R键,弹出记录窗口并按时间顺序展示所有记录(showMoveRecords()函数)。
2.4 图像渲染功能
棋盘打印:采用字符界面,带蓝色边框,显示行列坐标(左侧 0-9 行,底部 0-8 列),红方棋子用红色字体、黑方用白色字体,选中状态无额外高亮(字符界面限制)。
状态显示:走棋后实时刷新棋盘;AI 思考、胜负结果等信息通过文字提示展示。
三、非功能需求
性能需求:
资源加载:用户文件、棋盘布局加载时间≤1 秒。
运行流畅:棋子移动无卡顿,AI 走棋耗时≤5 秒(简单)/8 秒(中等)/12 秒(困难,随搜索深度调整)。
兼容性需求:
支持 Windows(cls清屏)和 Linux(clear清屏)系统,适配终端窗口分辨率≥80×24 字符。
可用性需求:
操作简洁:仅需键盘输入坐标和功能键,符合用户对字符界面游戏的操作习惯。
反馈明确:非法走法、登录失败等错误有文字提示;走棋记录清晰可查,便于复盘。
四、界面需求
界面组成:
标题区:顶部显示 “中国象棋(人机对战)” 及边框。
提示区:显示输入格式(“输入格式:9 0 7 0(从 x1 y1 移动到 x2 y2)”)和功能键说明(“‘q’ 退出游戏,‘r’ 查看记录”)。
棋盘区:居中显示 10×9 网格,含 “楚河汉界”,行列坐标标注于两侧。
信息区:底部显示当前回合、AI 走棋提示、胜负结果等。
视觉风格:
字符界面 + 彩色字体(红方红色、黑方白色、边框蓝色),布局对称,文字清晰,突出棋盘核心区域。
五、数据需求
核心数据结构:
游戏状态(GameState):当前回合(红方 1 / 黑方 - 1)、棋盘状态(board[ROW][COL])、AI 搜索深度(AI_DEPTH)。
棋子(piece):用整数表示(1-7 为红方,-1 至 - 7 为黑方),映射关系见pieceName()函数。
用户(User):包含用户名(username)、密码(password)、登录状态(loggedIn)。
走棋记录(MoveRecord):时间(time)、坐标(x1,y1,x2,y2)、移动棋子(piece)、被吃棋子(capturedPiece)、是否 AI 走棋(isAI)。
常量定义:
棋盘尺寸(ROW=10,COL=9)。
棋子类型(R_GENERAL=1,B_GENERAL=-1,R_CHARIOT=5,B_CHARIOT=-5等)。
棋子价值(PIECE_VALUE数组:帅 / 将 =±10000,车 =±9000,炮 =±4500 等)。
六、总结
本游戏基于传统中国象棋规则,通过模块化代码实现了人机对战核心功能,包括棋子移动规则校验、AI 决策、用户管理及走棋记录等模块。需求严格对应代码实现,确保功能完整、逻辑严谨,兼顾策略性与易用性,适合作为字符界面象棋游戏的开发规范与参考依据。
game.h

#ifndef GAME_H
#define GAME_H#include "user.h"
#include "board.h"
#include "record.h"// AI搜索深度
#define AI_DEPTH 2// 初始化游戏
void initGame();// 游戏主循环
void startGame(const User* user);// 检查移动是否合法
bool isValidMove(int x1, int y1, int x2, int y2, int currentPlayer);// 检查是否将军
bool isCheck(int currentPlayer);// 检查是否困毙
bool isStalemate(int currentPlayer);// AI走棋
void aiMove(const User* user);#endif

game.c

#include "game.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>// 棋子价值表
const int PIECE_VALUE[15] = 
{0,   // 0-EMPTY-10000, // 1-R_GENERAL-2000,  // 2-R_ADVISOR-2000,  // 3-R_ELEPHANT-4000,  // 4-R_HORSE-9000,  // 5-R_CHARIOT-4500,  // 6-R_CANNON-1000,  // 7-R_SOLDIER10000,  // 8-B_GENERAL (映射-1)2000,   // 9-B_ADVISOR (映射-2)2000,   // 10-B_ELEPHANT (映射-3)4000,   // 11-B_HORSE (映射-4)9000,   // 12-B_CHARIOT (映射-5)4500,   // 13-B_CANNON (映射-6)1000    // 14-B_SOLDIER (映射-7)};// 初始化游戏
void initGame() 
{srand((unsigned int)time(NULL)); // 随机种子,为 AI 随机探索initBoard(); // 初始化棋盘,清空,摆初始棋子
}// 车/帅/将移动合法性检查
static bool checkLineMove(int x1, int y1, int x2, int y2, int piece) 
{// 车、帅/将必须走直线(x 或 y 坐标一致)if (x1 != x2 && y1 != y2) return 0; if (abs(piece) == 1) {   // 帅/将(GENERAL)// 帅/将有“九宫格”限制:// 红帅(piece<0)只能在 (0-2, 3-5);黑将(piece>0)只能在 (7-9, 3-5)if ((piece > 0 && (x2 < 7 || x2 > 9 || y2 < 3 || y2 > 5)) ||(piece < 0 && (x2 < 0 || x2 > 2 || y2 < 3 || y2 > 5))) return 0;// 帅/将每次只能走 1 格if (abs(x2 - x1) + abs(y2 - y1) != 1) return 0;} else {   // 车(CHARIOT)int step = (x1 == x2) ? 1 : 0; // 1=沿 y 轴移动,0=沿 x 轴移动int start, end;if (step) {  // 沿 y 轴移动,检查路径是否被阻挡start = (y1 < y2) ? y1 + 1 : y2 + 1;end = (y1 < y2) ? y2 : y1;for (int y = start; y < end; y++) if (board[x1][y] != EMPTY) return false;} else { // 沿 x 轴移动,检查路径是否被阻挡start = (x1 < x2) ? x1 + 1 : x2 + 1;end = (x1 < x2) ? x2 : x1;for (int x = start; x < end; x++) if (board[x][y1] != EMPTY) return false;}}return true;
}// 马移动合法性检查
static bool checkHorseMove(int x1, int y1, int x2, int y2) {int dx = abs(x2 - x1), dy = abs(y2 - y1);// 马走“日”:必须是 (1,2) 或 (2,1) 的坐标差if (!((dx == 1 && dy == 2) || (dx == 2 && dy == 1))) return false; // 检查“蹩马腿”:日字拐角处是否有棋子if (dx == 2) { // 沿 x 轴跨 2 格,检查中间 x 坐标int xMid = (x1 < x2) ? x1 + 1 : x2 + 1;if (board[xMid][y1] != EMPTY) return false;} else { // 沿 y 轴跨 2 格,检查中间 y 坐标int yMid = (y1 < y2) ? y1 + 1 : y2 + 1;if (board[x1][yMid] != EMPTY) return false;}return true;
}// 象/相移动合法性检查
static bool checkElephantMove(int x1, int y1, int x2, int y2, int piece) {int dx = abs(x2 - x1), dy = abs(y2 - y1);// 象走“田”:坐标差必须是 (2,2)if (dx != 2 || dy != 2) return false; // 阵营过界限制:// 红象(piece<0)不能过楚河(x2 > 4);黑象(piece>0)不能过汉界(x2 < 5)if ((piece > 0 && x2 < 5) || (piece < 0 && x2 > 4)) return false;// 检查“堵象眼”:田字中心是否有棋子int xMid = (x1 + x2) / 2, yMid = (y1 + y2) / 2;if (board[xMid][yMid] != EMPTY) return false;return true;
}// 仕/士移动合法性检查
static bool checkAdvisorMove(int x1, int y1, int x2, int y2, int piece) 
{int dx = abs(x2 - x1), dy = abs(y2 - y1);// 士走“斜线”:坐标差必须是 (1,1)if (dx != 1 || dy != 1) return false; // 九宫格限制:// 红士(piece<0)只能在 (0-2, 3-5);黑士(piece>0)只能在 (7-9, 3-5)if ((piece > 0 && (x2 < 7 || x2 > 9 || y2 < 3 || y2 > 5)) ||(piece < 0 && (x2 < 0 || x2 > 2 || y2 < 3 || y2 > 5))) return false;return true;
}// 炮移动合法性检查
static bool checkCannonMove(int x1, int y1, int x2, int y2) {// 炮必须走直线(x 或 y 坐标一致)if (x1 != x2 && y1 != y2) return false; int step = (x1 == x2) ? 1 : 0; // 1=沿 y 轴,0=沿 x 轴int start, end, obstacle = 0;if (step) { // 沿 y 轴移动,统计路径棋子数start = (y1 < y2) ? y1 + 1 : y2 + 1;// 路径起始点(排除起始位置)end = (y1 < y2) ? y2 : y1;// 路径终点(排除目标位置)for (int y = start; y < end; y++)  // 遍历路径上的所有位置,统计棋子数量if (board[x1][y] != EMPTY) obstacle++;  // 非空位置即算障碍物} else { // 沿 x 轴移动,统计路径棋子数start = (x1 < x2) ? x1 + 1 : x2 + 1;// 路径起始点(排除起始位置)end = (x1 < x2) ? x2 : x1;// 路径终点(排除目标位置)for (int x = start; x < end; x++)   // 遍历路径上的所有位置,统计棋子数量if (board[x][y1] != EMPTY) obstacle++; // 非空位置即算障碍物}// 逻辑:// - 移动到空位:路径必须无棋子(obstacle == 0)// - 吃子:路径必须有且仅有 1 个棋子(炮架,obstacle == 1)return (board[x2][y2] == EMPTY) ? (obstacle == 0) : (obstacle == 1);
}// 兵/卒移动合法性检查
static bool checkSoldierMove(int x1, int y1, int x2, int y2, int piece) 
{int dx = x2 - x1, dy = abs(y2 - y1);if (piece > 0) {  // 红兵if (dx > 0) return false;if (x1 > 4) {  // 未过河return (dx == -1 && dy == 0);} else {  // 过河后return ((dx == -1 && dy == 0) || (dx == 0 && dy == 1));}} else {  // 黑卒if (dx < 0) return false;if (x1 < 5) {  // 未过河return (dx == 1 && dy == 0);} else {  // 过河后return ((dx == 1 && dy == 0) || (dx == 0 && dy == 1));}}
}// 综合移动合法性检查
bool isValidMove(int x1, int y1, int x2, int y2, int currentPlayer) {// 基本边界检查if (!isInBoard(x1, y1) || !isInBoard(x2, y2)) return false; if (board[x1][y1] == EMPTY) return false; // 起始位置非空if (isAlly(board[x2][y2], currentPlayer)) return false; // 目标位置非己方if (!isAlly(board[x1][y1], currentPlayer)) return false; // 起始位置是己方if (x1 
http://www.xdnf.cn/news/1305685.html

相关文章:

  • Linux Namespace隔离实战:dd/mkfs/mount/unshare构建终极沙箱
  • Spring Boot 静态函数无法自动注入 Bean?深入解析与解决方案
  • MySQL 主键详解:作用与使用方法
  • 嵌入式:Linux软件编程:线程
  • 【详细操作指南】如何将 Moodle 与编辑器连接,以修改文档、检查和批改作业等
  • 2025年最新油管视频下载,附MassTube下载软件地址
  • 【Canvas与玻璃光】铝圈蓝底玻璃光按钮
  • 华为实验综合小练习
  • YAML:锚点深度解析,告别重复,拥抱优雅的配置艺术
  • 第二十四天:虚函数与纯虚函数
  • 【科研绘图系列】R语言绘制三维曲线图
  • MySQL多表查询案例
  • 关系型数据库从入门到精通:MySQL 核心知识全解析
  • 单片机常用通信协议(一)
  • ubuntu 24.04 通过部署ollama提供大模型api接口
  • Storage.AI解读:构建AI数据基础设施的开放标准
  • 【万字精讲】 左枝清减·右枝丰盈:C++构筑的二叉搜索森林
  • Java 中使用阿里云日志服务(SLS)完整指南
  • nifi 增量处理组件
  • 区块链:用数学重构信任的数字文明基石
  • 【0基础3ds Max】学习计划
  • 007TG洞察:特斯拉Robotaxi成本降低84%?技术驱动的效率革命对营销自动化的启示
  • 以下是对智能电梯控制系统功能及系统云端平台设计要点的详细分析,结合用户提供的梯控系统网络架构设计和系统软硬件组成,分点论述并补充关键要点:
  • 深度解读 Browser-Use:让 AI 驱动浏览器自动化成为可能
  • 初识CNN02——认识CNN2
  • 数据结构初阶:排序算法(二)交换排序
  • Boost库中boost::function函数使用详解
  • Redis面试精讲 Day 22:Redis布隆过滤器应用场景
  • 测控一体化闸门驱动灌区信息化升级的核心引擎
  • 波浪模型SWAN学习(1)——模型编译与波浪折射模拟(Test of the refraction formulation)