软件08-2-宋红博-中国象棋

更新时间:2024-04-02 13:14:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

大 连 科 技 学 院

面向对象程序设计课程设计

题 目 中国象棋

学生姓名 宋红博 专业班级 软件工程08-2

指导教师 李孝贵 职 称 助教

所在单位 信息科学系软件工程教研室

教学部主任 王立娟

完成日期 2011年9月9日

课程设计报告单

学号 0801030201 姓名 考 核 项 目 1 平时工作态度及遵守纪律情况 (10分) 掌握基本理论、关键知识、基本技能的程度和阅读参考资料的水平 (10分) 独立工作能力、综合运用所学知识分析和解决问题能力及实际工作能力提高的程度 (20分) 完成课程设计说明书及软件的情况与水平(小组分工情况、规范性、整洁清楚、叙述完整性、思路清晰程度、工作量及实际运行情况和创新性) (60分) 宋红博 专业班级 评分 软件工程08-2 备注 2 3 4 总评成绩

综 合 评 定:

(优、良、中、及格、不及格)

2011年9月9日

指导教师签字:

《面向对象程序设计(A)课程设计》任务书

一、课程设计任务及要求:

任务:针对小型信息管理系统或若干综合性设计题目,选择一种软件开发模型,完成从需求分析、系统设计、系统实现,软件测试的全过程。

要求:

(1) 根据软件系统开发的一般原则,完成相应系统的功能设计,完成主要功能模块的程序实现并进行测试训练,给出代码运行结果和相应的设计文档。可以分组进行,但所有学生必须经历整个系统的开发全过程,以便加深对系统开发全过程的认识。 (2)提交课程设计报告。

(3)指标: 要求完成课程设计报告3000字以上(约二十页);完成所设计的题目,设计题目的语句行数的和在200行语句以上。

二、工作量

2周(10个工作日)时间

三、计划安排

第1个工作日:查找相关资料、书籍,阅读示例文档,选择题目。 第2个工作日-第4个工作日:设计程序结构、模块图。

第5个工作日-第9个工作日:完成程序的编码,并且自己调试、测试。穿插进行课程设计报告的撰写。

第10个工作日:上交课程设计报告,由教师检查软件测试效果、检查课程设计报告,给出学生成绩。

指导教师签字:

2011年8月29日

目录

题目: ........................................................................................................................................ 1

1.需求分析 ......................................................................................................................... 1 2.概要设计 ......................................................................................................................... 1 3.详细设计 ......................................................................................................................... 2 4.编码 ................................................................................................................................. 3 5.调试分析 ......................................................................................................................... 4 6.测试结果及运行效果 ..................................................................................................... 4 7.系统开发所用到的技术 ................................................................................................. 5 参考文献 .................................................................................................................................... 6 附录 全部代码 .......................................................................................................................... 7

题目:中国象棋分析与设计

1. 需求分析

中国象棋具有悠久的历史,几千年以来,一直被认为是人们所热爱的休闲活动之一。象棋具有独特的规则,主要为车行直路,马走狭日,相行田,士相不离老王边,炮翻山,兵、卒只进不退,过河后方能左右行。程序设计就是把现实中的人与人之间的对弈,改成电脑与人的对弈。电脑的形为仿照人的形为,正确的走棋,“思考”,下棋。任务要求,画出棋盘,实现简单的人机对弈。

2. 概要设计

1、数据表示:主要包括棋盘的表示和棋子的表示。

2、走法的产生:包括车马相士炮等的基本走法和检测是否将军,或被将死,还包括检

查一种棋子是否还有剩余,判断走法是否和法以及枚举可能有的合法的走法。 3、搜索引擎:搜索棋子可能有的走法,并且产生最佳的走法。搜索引擎包括许多算法,如极大极小值、负极大值、深度优先搜索、置换表、历史启发等等搜索算法。

4、估值方法:即对棋子的价值进行评估,如兵为300,车为1000,将帅位无限大等;对棋子的位置进行评估,如过河后越逼近九宫的卒/兵价值越大;对棋子的灵活性进行评估,灵活性越大,价值越大,如一般车的灵活性大于卒等;对棋子间关系进行评估,即棋子受到的威胁越大,价值越低,受到的保护越多,价值越高;还要与搜索算法相结合。

5、界面设计:主要有棋盘、棋子、拖动实现走棋、悔棋、还原、搜素引擎(包括算法和搜索深度)设置等。一些美化可以直接使用网络上的美化资源,消息响应函数与处理函数等的实现。

1

3. 详细设计

主程序模块窗口模块摆棋子绘制棋盘规则定义模块电脑智能模块

图3-1模块设计图

开始搜索算法定义搜索深度depth,本方最优值best对depth,best,worst进行search搜索判断深度depth是否小于0调用局面评估函数分析局面红方走棋判断value 是否大于bestBest=value判断 depth是否等于MaxdepthBestmove = 当前走法

图3-2算法流程图

2

4. 编码

1棋盘

BITMAP BitMap;

m_BoardBmp.LoadBitmap(IDB_CHESSBOARD);

m_BoardBmp.GetBitmap(&BitMap); //取BitMap 对象 m_nBoardWidth=BitMap.bmWidth; //棋盘宽度 m_nBoardHeight=BitMap.bmHeight;//棋盘高度

m_BoardBmp.DeleteObject();

memcpy(m_byChessBoard,InitChessBoard,90);//初始化棋盘 memcpy(m_byShowChessBoard,InitChessBoard,90); memcpy(m_byBackupChessBoard,InitChessBoard,90);

m_pSE->SetSearchDepth(3); //设定搜索层数为3

m_pSE->SetMoveGenerator(m_pMG);//给搜索引擎设定走法产生器 m_pSE->SetEveluator(m_pEvel); //给搜索引擎设定估值核心 m_pSE->SetUserChessColor(m_nUserChessColor);

m_MoveChess.nChessID=NOCHESS;//将移动的棋子清空

return TRUE; // return TRUE unless you set the focus to a control 2颜色 public:

void SetTextColor(COLORREF color){m_clrText=color;} void SetBkColor(COLORREF color){m_clrBkGround=color;} void SetStartColor(COLORREF color){m_clrStart=color;} void SetEndColor(COLORREF color){m_clrEnd=color;} void ShowPercent(BOOL

void ShowText(CString str,bool

//设定用户为黑方或红方 //设定进度条

m_pSE->SetThinkProgress(&m_progressThink);

bShowPercent=TRUE){m_bShowPercent=bShowPercent;} bIsShowText){m_strShow=str,m_bIsShowText=bIsShowText;};

3

5. 调试分析

不需要安装,直接打开Source Code文件夹,双击Release文件夹,再双击其中的象棋图标,就可以运行程序

6. 测试结果及运行效果

COLORREF GetTextColor(void){return m_clrText;} COLORREF GetBkColor(void){return m_clrBkGround;} COLORREF GetStartColor(void){return m_clrStart;} COLORREF GetEndColor(void){return m_clrEnd;} int SetPos(int nPos); int SetStep(int nStep); int StepIt();

void SetRange(int nLower,int nUpper);

图6-1程序运行效果

4

7. 系统开发所用到的技术 Visual C++ 6.0 应用语言C++

注释:C++是在C语言引入了面向机制而形成的一种程序设计语言,程序结构灵活,代码简洁清晰,可移植性强,支持数据抽象,面向对象程序设计和泛型程序设计。所以它是一种应用广泛的系统语言。

5

参考文献

[1] C++面向对象程序设计 西安电子科技大学出版社 李兰 任凤华

[2] 蒋鹏, 雷贻祥,陈园园. C\\C++中国象棋程序入门与提高. 电子工业出版社, 2009 [3] 刘路放. Visual C++与面向对象程序设计教程(第二版). 高等教育出版社,2007.8 [4] 钱能.C++程序设计教程(第2版).北京:清华大学出版社,2005.8

[5] Matt Tells《高级编程指南—C++ Builder》[M]. 中国水利水电出版社 1998年

6

附录 全部代码

1//鼠标左键响应消息

void CChessDlg::OnLButtonDown(UINT nFlags, CPoint point) {

// TODO: Add your message handler code here and/or call default if(m_iChessSort==CS_CCCHESS) {

m_staticTip.SetWindowText(m_strWelcome); return; }

if(m_Status==Previewing) {

m_staticTip.SetWindowText(\现在处于预览状态,如要下棋,请弹出右键菜单点 预览完毕\

return; }

if(m_bIsGameOver) {

m_staticTip.SetWindowText(\老兄,这盘棋下完了\

return; }

if(m_bIsThinking)//电脑正在想 return;

int x,y;

//将坐标换算成棋盘上的格子 y=(point.y-14)/GRILLEHEIGHT; x=(point.x-15)/GRILLEWIDTH;

//判断鼠标是否在棋盘内,并且点中了用户棋子 if(y>=0 && y<10 && x>=0 && x<9 &&

(m_nUserChessColor==REDCHESS?IsRed(m_byChessBoard[y][x]):IsBlack(m_byChessBoard[y][x]))) {

memcpy(m_byBackupChessBoard,m_byChessBoard,90);//备份棋盘

//将当前棋子的信息装入,记录移动棋子的结构中

7

m_ptMoveChess.x=x; m_ptMoveChess.y=y;

m_MoveChess.nChessID=m_byChessBoard[y][x];

//将该棋子原位置棋子去掉

m_byChessBoard[y][x]=NOCHESS; m_byShowChessBoard[y][x]=NOCHESS;

//让棋子中点坐标位于鼠标所在点 point.x-=18; point.y-=18;

m_MoveChess.ptMovePoint=point; //重绘屏幕

InvalidateRect(NULL,FALSE); UpdateWindow();

SetCapture();//独占鼠标焦点 } else

if(m_Status==Chessing)

if(y>=0 && y<10 && x>=0 && x<9 &&

(m_nUserChessColor!=REDCHESS?IsRed(m_byChessBoard[y][x]):IsBlack(m_byChessBoard[y][x])))

m_staticTip.SetWindowText(\不好意思,这是我的棋子,请你不要乱动\

else

m_staticTip.SetWindowText(\老兄,那又没有棋子,你瞎点什么啊\

CDialog::OnLButtonDown(nFlags, point); }

2//响应鼠标左键弹起的消息

void CChessDlg::OnLButtonUp(UINT nFlags, CPoint point) {

// TODO: Add your message handler code here and/or call default if(m_bIsGameOver) {

m_staticTip.SetWindowText(\老兄,这盘棋下完了\ return; }

if(m_bIsThinking || m_Status!=Chessing) return;

BOOL bTurnSide=FALSE;

8

int x,y;

CString str;

//将坐标换算成棋盘上的格子 y=(point.y-14)/GRILLEHEIGHT; x=(point.x-15)/GRILLEWIDTH;

//判断是否有移动棋子,并且该棋子的移动是一个合法走法 // if(m_MoveChess.nChessID &&

CMoveGenerator::IsValidMove(m_byBackupChessBoard,m_ptMoveChess.x,m_ptMoveChess.y,x,y,m_nUserChessColor)) if(m_MoveChess.nChessID &&

m_pMG->IsValidMove(m_byBackupChessBoard,m_ptMoveChess.x,m_ptMoveChess.y,x,y,m_nUserChessColor)) {

//---------将用户走法压栈--------- m_cmBestMove.From.x=m_ptMoveChess.x; m_cmBestMove.From.y=m_ptMoveChess.y; m_cmBestMove.To.x=x; m_cmBestMove.To.y=y;

m_cmBestMove.nChessID=m_MoveChess.nChessID; m_umUndoMove.cmChessMove=m_cmBestMove;

m_umUndoMove.nChessID=m_byChessBoard[y][x]; m_stackUndoMove.push(m_umUndoMove); //--------------------------------

m_btnUndo.EnableWindow(1);//激活悔棋按钮

if(m_nUserChessColor==REDCHESS) m_iBout++;

this->AddChessRecord(m_ptMoveChess.x+1,m_ptMoveChess.y+1,x+1,y+1,m_nUserChessColor,m_MoveChess.nChessID);

m_byChessBoard[y][x]=m_MoveChess.nChessID;

m_byShowChessBoard[y][x]=m_MoveChess.nChessID; bTurnSide=TRUE; }

else//否则恢复移动前的棋盘状态 {

memcpy(m_byShowChessBoard,m_byBackupChessBoard,90); memcpy(m_byChessBoard,m_byBackupChessBoard,90); }

m_MoveChess.nChessID=NOCHESS;//将移动的棋子清空

9

//重绘屏幕

InvalidateRect(NULL,FALSE); UpdateWindow();

ReleaseCapture();//释放鼠标焦点

if(m_iChessSort==CS_PPCHESS) {

m_iWhoChess=m_iWhoChess%2+1; return; }

if(bTurnSide==TRUE) {

m_btnStop.EnableWindow(1);

m_hHandle=::CreateThread(0,0,ThinkProc,this,0,&m_dwThreadID); } else

m_staticTip.SetWindowText(m_strWelcome);

CDialog::OnLButtonUp(nFlags,point); }

3//响应鼠标移动 函数

void CChessDlg::OnMouseMove(UINT nFlags, CPoint point) {

// TODO: Add your message handler code here and/or call default if(m_bIsThinking) return;

if(m_MoveChess.nChessID) {

if(m_Status==Chessing) {

//防止将棋子拖出棋盘 if(point.x<15)//左边 point.x=15;

if(point.y<15)//上边 point.y=15;

if(point.x>m_nBoardWidth-15)//右边 point.x=m_nBoardWidth-15;

if(point.y>m_nBoardHeight-15)//下边 point.y=m_nBoardHeight-15;

10

//让棋子中心位于鼠标所在处 point.x-=18; point.y-=18;

m_MoveChess.ptMovePoint=point;//保存移动棋子的坐标 } else {

//让棋子中心位于鼠标所在处 point.x-=18; point.y-=18;

m_MoveChess.ptMovePoint=point;//保存移动棋子的坐标

//棋子拖出棋盘时将该棋子删掉

if(point.x<15 || point.y<15 || point.x>m_nBoardWidth-15 || point.y>m_nBoardHeight-15)

m_byChessBoard[m_ptMoveChess.y][m_ptMoveChess.x]=NOCHESS; }

InvalidateRect(NULL,FALSE);//刷新窗口 UpdateWindow();//立即执行刷新 }

CDialog::OnMouseMove(nFlags, point); }

4//统计红黑两方总分

int nRedValue=0;int nBlackValue=0; for(i=0;i<10;i++) for(j=0;j<9;j++) {

nChessType=position[i][j]; if(nChessType!=NOCHESS) {

if(IsRed(nChessType))

nRedValue+=m_chessValue[i][j]; //把红棋的值加总 else

nBlackValue+=m_chessValue[i][j];//把红棋的值加总 } }

if(nUserChessColor==REDCHESS) {

11

if(bIsRedTurn)

return nRedValue-nBlackValue;//如果轮到红棋走返回估值

return nBlackValue-nRedValue;//如果轮到黑棋走返回负估值 }

if(bIsRedTurn)

return nBlackValue-nRedValue;//如果轮到黑棋走返回负估值

return nRedValue-nBlackValue;//如果轮到红棋走返回估值 }

int CEveluation::GetRelatePiece(BYTE position[][9], int j, int i) {

nPosCount=0; BYTE nChessID; BYTE flag; int x,y;

nChessID=position[i][j];

switch(nChessID) {

case R_KING://红帅 case B_KING://黑将

//循环检查九宫之内哪些位置可到达/保护 //扫描两边就宫包含了照像的情况 for(y=0;y<3;y++) for(x=3;x<6;x++)

if(CanTouch(position,j,i,x,y))//能否到达

AddPoint(x,y);//可达到/保护的位置加入数组

//循环检查九宫之内哪些位置可到达/保护 //扫描两边就宫包含了照像的情况 for(y=7;y<10;y++) for(x=3;x<6;x++)

if(CanTouch(position,j,i,x,y))//能否到达

AddPoint(x,y);//可达到/保护的位置加入数组

break;

case R_BISHOP://红士

//循环检查九宫之内哪些位置可到达/保护 for(y=7;y<10;y++)

12

for(x=3;x<6;x++)

if(CanTouch(position,j,i,x,y))

AddPoint(x,y);//可达到/保护的位置加入数组

break;

case B_BISHOP://黑士

//循环检查九宫之内哪些位置可到达/保护 for(y=0;y<3;y++) for(x=3;x<6;x++)

if(CanTouch(position,j,i,x,y))

AddPoint(x,y);//可达到/保护的位置加入数组

break;

case R_ELEPHANT://红相 case B_ELEPHANT://黑象 //右下 x=j+2; y=i+2;

if(x<9 && y<10 && CanTouch(position,j,i,x,y)) AddPoint(x,y);

//右上 x=j+2; y=i-2;

if(x<9 && y>=0 && CanTouch(position,j,i,x,y)) AddPoint(x,y);

//左下 x=j-2; y=i+2;

if(x>=0 && y<10 && CanTouch(position,j,i,x,y)) AddPoint(x,y);

//左上 x=j-2; y=i-2;

if(x>=0 && y>=0 && CanTouch(position,j,i,x,y)) AddPoint(x,y); break;

case R_HORSE://红马

13

case B_HORSE://黑马

//检查右下方能否到达/保护 x=j+2; y=i+1;

if((x<9 && y<10)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查右上方能否到达/保护 x=j+2; y=i-1;

if((x<9 && y>=0)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查左下方能否到达/保护 x=j-2; y=i+1;

if((x>=0 && y<10)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查左上方能否到达/保护 x=j-2; y=i-1;

if((x>=0 && y>=0)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查右下方能否到达/保护 x=j+1; y=i+2;

if((x<9 && y<10)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查右上方能否到达/保护 x=j+1; y=i-2;

if((x<9 && y>=0)&&CanTouch(position,j,i,x,y)) AddPoint(x,y);

//检查左下方能否到达/保护 x=j-1; y=i+2;

if((x>=0 && y<10)&&CanTouch(position,j,i,x,y)) AddPoint(x,y); //检查左上方能否到达/保护

14

x=j-1; y=i-2;

if((x>=0 && y>=0)&&CanTouch(position,j,i,x,y)) AddPoint(x,y); break;

case R_CAR://红车 case B_CAR://黑车

//检查向右能否到达/保护 x=j+1; y=i;

while(x<9) {

if(NOCHESS==position[y][x])//空白 AddPoint(x,y); else{

//碰到第一个棋子 AddPoint(x,y);

break;//后面的位置不能走了 } x++; }

//检查向左能否到达/保护 x=j-1; y=i;

while(x>=0) {

if(NOCHESS==position[y][x])//空白 AddPoint(x,y); else{

//碰到第一个棋子 AddPoint(x,y);

break;//后面的位置不能走了 } x--; }

//检查向下能否到达/保护 x=j; y=i+1;

while(y<10) {

15

}

if(NOCHESS==position[y][x])//空白 AddPoint(x,y); else{

//碰到第一个棋子 AddPoint(x,y);

break;//后面的位置不能走了 } y++;

//检查向上能否到达/保护 x=j; y=i-1;

while(y>=0) {

if(NOCHESS==position[y][x])//空白 AddPoint(x,y); else{

//碰到第一个棋子 AddPoint(x,y);

break;//后面的位置不能走了 } y--; } break;

case R_PAWN://红兵 //观看向前是否到底 y=i-1; x=j;

if(y>=0)

AddPoint(x,y);//没到底,可走 if(i<5) {

//如已过河 y=i;

x=j+1;//向右 if(x<9)

AddPoint(x,y);//未到右边,可走 x=j-1;//向左 if(x>=0)

AddPoint(x,y);//未到左边,可走 }

16

break;

case B_PAWN://黑卒 //观看向前是否到底 y=i+1; x=j;

if(y<10)

AddPoint(x,y);//没到底,可走 if(i>4) {

//如已过河 y=i;

x=j+1;//向右 if(x<9)

AddPoint(x,y);//未到右边,可走 x=j-1;//向左 if(x>=0)

AddPoint(x,y);//未到左边,可走 }

break;

case B_CANON://黑炮 case R_CANON://红炮

//检查向右能否到达/保护的位置 x=j+1; y=i;

flag=FALSE; while(x<9) {

if(NOCHESS==position[y][x]) {

//空白位置 if(!flag)

AddPoint(x,y); } else {

if(!flag)

flag=TRUE;//是第一个棋子 else {

//是第二个棋子

17

}

AddPoint(x,y); break; } }

x++;//继续向右

//检查向左能否到达/保护的位置 x=j-1; y=i;

flag=FALSE; while(x>=0) {

if(NOCHESS==position[y][x]) {

//空白位置 if(!flag)

AddPoint(x,y); } else {

if(!flag)

flag=TRUE;//是第一个棋子 else {

//是第二个棋子 AddPoint(x,y); break; } }

x--;//继续向左 }

//检查向下能否到达/保护的位置 x=j; y=i+1;

flag=FALSE; while(y<10) {

if(NOCHESS==position[y][x]) {

//空白位置 if(!flag)

AddPoint(x,y);

18

}

} else {

if(!flag)

flag=TRUE;//是第一个棋子 else {

//是第二个棋子 AddPoint(x,y); break; } }

y++;//继续向下

//检查向上能否到达/保护的位置 x=j; y=i-1;

flag=FALSE; while(y>=0) {

if(NOCHESS==position[y][x]) {

//空白位置 if(!flag)

AddPoint(x,y); } else {

if(!flag)

flag=TRUE;//是第一个棋子 else {

//是第二个棋子 AddPoint(x,y); break; } }

y--;//继续向上 } break;

default:

19

break; }

return nPosCount; }

5//棋子移动

//define.h #ifndef define_h_ #define define_h_

#define BLACKCHESS 1//黑方 #define REDCHESS 2//红方

//深度方式DepthSort #define DS_DEFAULTSET 1 #define DS_USERDEFINE 2

#define CS_PCCHESS 1//人机对弈 #define CS_PPCHESS 2//人人对弈#define CS_CCCHESS 3//机机对弈 #define CS_HASHCHESS 4//混杂对弈

//--------棋子--------

#define NOCHESS 0 //没有棋子

#define B_KING 1 //黑帅 #define B_CAR 2 //黑车 #define B_HORSE 3 //黑马 #define B_CANON 4 //黑炮 #define B_BISHOP 5 //黑士 #define B_ELEPHANT 6 //黑象 #define B_PAWN 7 //黑卒 #define B_BEGIN B_KING #define B_END B_PAWN

#define R_KING 8 //红将 #define R_CAR 9 //红车 #define R_HORSE 10//红马 #define R_CANON 11//红炮 #define R_BISHOP 12//红士 #define R_ELEPHANT 13//红相 #define R_PAWN 14//红兵

20

#define R_BEGIN R_KING #define R_END R_PAWN //--------------------

#define IsBlack(x) (x>=B_BEGIN && x<=B_END)//判断某个棋子是不是黑色 #define IsRed(x) (x>=R_BEGIN && x<=R_END)//判断某个棋子是不是红色

//判断两个棋子是不是同色

#define IsSameSide(x,y) ((IsBlack(x) && IsBlack(y)) || (IsRed(x) && IsRed(y)))

//棋子位置 typedef struct {

BYTE x; BYTE y; }CHESSMANPOS;

//棋子走法 typedef struct {

short nChessID; //表明是什么棋子 CHESSMANPOS From;//起始位置

CHESSMANPOS To; //走到什么位置 int Score; //走法的分数 }CHESSMOVE;

//悔棋时需要的数据结构 typedef struct {

CHESSMOVE cmChessMove;

short nChessID;//被吃掉的棋子 }UNDOMOVE;

#endif

21

#define R_BEGIN R_KING #define R_END R_PAWN //--------------------

#define IsBlack(x) (x>=B_BEGIN && x<=B_END)//判断某个棋子是不是黑色 #define IsRed(x) (x>=R_BEGIN && x<=R_END)//判断某个棋子是不是红色

//判断两个棋子是不是同色

#define IsSameSide(x,y) ((IsBlack(x) && IsBlack(y)) || (IsRed(x) && IsRed(y)))

//棋子位置 typedef struct {

BYTE x; BYTE y; }CHESSMANPOS;

//棋子走法 typedef struct {

short nChessID; //表明是什么棋子 CHESSMANPOS From;//起始位置

CHESSMANPOS To; //走到什么位置 int Score; //走法的分数 }CHESSMOVE;

//悔棋时需要的数据结构 typedef struct {

CHESSMOVE cmChessMove;

short nChessID;//被吃掉的棋子 }UNDOMOVE;

#endif

21

本文来源:https://www.bwwdw.com/article/n6hr.html

Top