C语⾔实现中国象棋(Qt实现界⾯,源码下载,详细注释,易
移植)
前⾔:中国象棋的规则很多⼈都懂,⽤C语⾔做⼀个中国象棋游戏,其要点是怎么把抽象的规则变成形象、具体的代码。本项⽬提供详细的实现思路,源码附带⼤量的注释说明,源码逐步地实现了每⼀种棋类的⾛棋规则、吃棋规则,将每⼀条细化的规则整合起来也就实现了⼀个完整的游戏规则。
本项⽬提供两种调试⽅式,⼀种是带界⾯操控(QT实现),⼀种是终端输⼊操控。本项⽬⾮常适合初学者⽤以参考学习。
Qt 5.14完整源码下载,。效果预览:
下载源码:
源码下载解压后有两个⽂件夹,分别是QT⼯程和Dev-C++⼯程,前者带界⾯后者是终端输⼊⽅式调试。
代码设计:
两个⼯程的源码都包含了chess.cpp和chess.h两个⽂件,这两个⽂件实现了象棋的游戏规则,将⼀盘象棋游戏的所有操作通过接⼝来实现,⾮常⽅便移植到其他的嵌⼊式平台。下⾯先对这两个源码⽂件的部分内容作说明。
typedef struct{
eChessColour Colour:4;
eChessClass Class:4;
}ChessPiecesStr;//装载棋⼦的容器,携带棋⼦颜⾊、棋⼦种类信息
/*由多个棋⼦容器组成的虚拟棋盘 10(row)*9(col)*/
static ChessPiecesStr CheckerBoard[10][9];
⽤ChessPiecesStr结构体表⽰⼀个象棋包含的信息(颜⾊、棋类),那么可以定义这样⼀个数组ChessPiecesStr CheckerBoard[10] [9],它代表整个棋盘,10⾏,9列,每个数组元素代表棋盘的每⼀个位置上的棋⼦,如果某个元素的信息是NULL,则代表该位置上没有棋⼦。我们在游戏过程的⾛棋、吃棋、悔棋等操作,其实是对数组CheckerBoard⾥的数据进⾏操作,然后将操作完的棋盘更新显⽰出来。
typedef struct{
ChessPiecesStr ChPs;
uchar col,row;//位置:列、⾏
}PickUpChessStruct;//被选中的棋⼦,携带棋⼦所在的位置、棋⼦容器⾥的信息
⽤PickUpChessStruct结构体表⽰游戏者当前要操作的棋⼦,它包含了该棋⼦的坐标信息、棋⾊、棋类,这么封装是为了⽅便实现每⼀种棋类的⾛棋规则、吃起规则,下⾯以炮的⾛棋规则为例:
bool MovemenRules_PAO(PickUpChessStruct* pActiveChess,uchar row,uchar col)//【炮】⾛棋规则
{
int i,col_min,col_max,row_min,row_max;
//【炮】⾛棋规则:⾛直线,不能跨越棋⼦
//穷举法+假设法要么横着⾛,要么竖着⾛,其他都是违规;假设成功了,那么起点到终点之间不能有其他棋⼦
if(pActiveChess->row == row){//横着⾛
if(pActiveChess->col > col){
col_min = col;
col_max = pActiveChess->col;
}else{
col_min = pActiveChess->col;
col_max = col;
}
for(i = col_min+1;i < col_max; i++ ){
if(CheckerBoard[row][i].Class != 0) return false;//假设不成⽴
}
return true;//假设成⽴
}else if(pActiveChess->col == col){//竖着⾛
if(pActiveChess->row > row){
row_min = row;
row_max = pActiveChess->row;
}else{
row_min = pActiveChess->row;
row_max = row;
}
for(i = row_min+1;i < row_max; i++ ){
if(CheckerBoard[i][col].Class != 0) return false;//假设不成⽴
}
return true;//假设成⽴
}else{
return false;
}
}
函数传⼊的参数包括了⼀个类型PickUpChessStruct的结构体代表拿起来将要操作的棋⼦,row、col代
表落棋的位置,将这些信息传⼊MovemenRules_PAO函数就能判断是否满⾜炮的⾛棋规则,注意这⾥仅仅是判断,CheckerBoard数组也就是棋盘,并没有发送发⽣任
何变化。
bool MoveChess(char Operator,uchar start_row,uchar start_col,uchar end_row,uchar end_col)//将start_row,start_col处的棋⼦,移到end_row,end_col位置上
{
bool ret = false;
PickUpChessStruct ActiveChess;
/*判断游戏是否结束*/
if(Winner != Cc_NULL) return ret;
/*判断选中的起始坐标上是否有棋,若⽆棋返回*/
if(CheckerBoard[start_row][start_col].Class == Cn_NULL){
return ret;
}
/*判断是否允许该操作者⾛棋*/
if(CurOperator != Operator){
return ret;
}
/*将选中的棋⼦信息复制到ActiveChess结构体⾥*/
ActiveChess.ChPs.Class = CheckerBoard[start_row][start_col].Class;
ActiveChess.ChPs.Colour = CheckerBoard[start_row][start_col].Colour;
/
/判断落在位置是否有棋⼦
if(CheckerBoard[end_row][end_col].Class != Cn_NULL){
//落的位置有棋
//1.判断是否是⼰⽅棋⼦
if(ActiveChess.ChPs.Colour == CheckerBoard[end_row][end_col].Colour){
return false;
}
//2.判断是否能吃
ret = (*ChessEatRulesArry[(unsigned char)ActiveChess.ChPs.Class-1])(&ActiveChess,end_row,end_col);//该棋类的吃棋规则,将选中的棋⼦和要落得位置传⼊ if(ret == false){
return ret;//不能吃,返回是失败
}else{
//能吃,判断被吃的是否是”将/帥“
if(CheckerBoard[end_row][end_col].Class == Cn_JIANG){
//游戏结束
Winner = CheckerBoard[end_row][end_col].Colour==Cc_BLACK?Cc_RED:Cc_BLACK;
}
}
}else{
//落的位置没棋,判断是否能⾛
ret = (*ChessMovemenRulesArry[(unsigned char)ActiveChess.ChPs.Class-1])(&ActiveChess,end_row,end_col);//该棋类的⾛棋规则,将选中的棋⼦,要落得位 if(ret == false){
return false;
}
}
//能到这⾥说明符合⾛棋、吃棋规则,接下来进⾏棋⼦移动
//切换操作者
CurOperator = (CurOperator==Cc_BLACK)?Cc_RED:Cc_BLACK;
//备份,实现悔棋功能
pushStack(&w][l],l);
pushStack(&CheckerBoard[end_row][end_col],end_row,end_col);
//1.先棋盘中移除选中的棋
w][l].Class = Cn_NULL;
w][l].Colour = Cc_NULL;
/
/2.将选中的棋放到新的位置 row col
CheckerBoard[end_row][end_col].Class= ActiveChess.ChPs.Class;
CheckerBoard[end_row][end_col].Colour= ActiveChess.ChPs.Colour;
return ret;
}
MoveChess函数是实现⾛棋的功能,参数Operator代表是操作者的⾝份(红棋、⿊棋),start_row、start_col代表选中的棋⼦在棋盘的位置,end_row、end_col代表选中的棋⼦落棋的位置。通过起始坐标可以知道选中的棋⼦在CheckerBoard数组⾥的位置,从⽽知道该棋⼦是什么颜⾊什么棋类,再调⽤与该棋类相应的⾛棋、吃棋规则函数来判断是否合法。处理的每⼀步流程都有代码注释,不⽤看代码框架图也很容易理解。
悔棋功能是通过栈原理实现的,栈的特点是先进后出,在棋盘上成功地⾛⼀步棋⼦,总共有两个位置发⽣变化,不管是⾛棋还是吃棋,那么只要把这两个位置的棋⼦信息保存到栈⾥⾯,并且如果栈满了之后直接覆盖较早的记录,悔棋时,从栈⾥取出上⼀步变化的两个位置的信息,将其还原就⾏了。
Dev-C++⼯程使⽤
‘ Dev-C++开发⼯具可以从⽹上免费下载,上⼿容易,对于初学者来说是⼀款不错的学习⼯具;打开源码⼯程后,可看到包括了两个源码⽂件是chess.cpp、chess.h,Dev-C++⼯程⽂件Chess-alone.dev,编译⽣成的可执⾏⽂件。
main函数:
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
int start_row,start_col,end_row,end_col;
InitCheckerBoard();
CheckerBoardPrintf();
PrintfTips();
while(1){
if(CurOperator == Cc_BLACK){
printf("⿊棋⾛棋:");
}else{
printf("红棋⾛棋:");
}
fflush(stdin);
scanf("(%d,%d)>(%d,%d)",&start_row,&start_col,&end_row,&end_col);
if(start_row < 0 || start_row > 10 || start_col < 0 || start_col > 9||\
end_row < 0 || end_row > 10 || end_col < 0 || end_col > 9){\
PrintfTips();
}
MoveChess(CurOperator,start_row,start_col,end_row,end_col);
CheckerBoardPrintf();
if(Winner != Cc_NULL){
if(Winner == Cc_BLACK){
printf("⿊棋胜利,游戏重新开始!\n");
}else{
printf("红旗胜利,游戏重新开始!\n");
}
InitCheckerBoard();
CheckerBoardPrintf();
}
c语言下载什么}
return 0;
}
Main函数主要是从终端输⼊⾛棋的起始坐标和终点坐标传⼊MoveChess完成⾛棋操作,然后再将棋盘的内容打印出来,实现了⼀个简单的接⼝使⽤演⽰。这⾥不⽤纠结⽆法区分颜⾊的问题。效果图如下:
Qt⼯程的使⽤
Qt Creator是我经常使⽤的⼀款开发⼯具,它可以开发跨平台的应⽤,⽐如说同⼀套代码,可以编译成window的应⽤程序,还可以编译成安卓的应⽤程序,Linux等,⽽且它提供了丰富的开发接⼝和说明⽂档;从官⽹上就可以下载免费的个⼈开源版安装包。
打开⼯程后,⾥⾯的⽂件说明如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论