2003年广东省赛试题3 国际象棋

本文介绍了一个国际象棋博弈程序的设计与实现,包括棋子移动规则、王车易位、将军与将死判断等核心功能,并通过具体代码展示了如何处理棋谱输入与输出。
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->#include<iostream>
#include
<string>
#include
<cmath>
usingnamespacestd;

enumTResult
{
//结局状态
WHITEWIN=1,//白方赢
BLACKWIN,//黑方赢
STALEMATE,//僵局
DRAW,//和局
DEAD,//过多的输入
PUZZLE,//无法决定移动棋子
ILLEGAL//非法
};
constcharRESULT[8][20]=
{
//结局状态输出表示
"",
"WhiteWin",
"BlackWin",
"Stalemate",
"Draw",
"DeadMoves",
"PuzzleMove",
"IllegalMove"
};
enumTPieceType
{
//棋子类型
SPACE=0,
PAWN,
//
KING,//
QUEEN,//
ROOK,//
BISHOP,//
KNIGHT//
};
enumTSide
{
NONE
=0,
WHITE,
//黑方
BLACK//白方
};
typedef
struct
{
//棋盘每个位置的表示
TSideside;//所属玩家
TPieceTypept;//棋子类型
}TPiece;
constintBOARDSIZE=8;//棋盘大小

typedefTPieceTBoard[BOARDSIZE][BOARDSIZE];
//棋盘
intn;//棋谱步数
TResultresult;//最后结局
/*

*用来进行王车易位的布尔变量
*
*whitecastled:白方是否已经王车易位
*blackcastled:黑方是否已经王车易位
*white0rookMoved:白方号位的车是否已经移动
*white7rookMoved:白方号位的车是否已经移动
*black0rookMoved:黑方号位的车是否已经移动
*black7rookMoved:黑方号位的车是否已经移动
*whitekingMoved:白方王是否已经移动
*blackkingMoved:黑方王是否已经移动
*
*/
boolwhitecastled,blackcastled,white0rookMoved,white7rookMoved,black0rookMoved,black7rookMoved,whitekingMoved,blackkingMoved;

TPieceTypeChessType(
conststring&move)
{
switch(move[0])
{
case'K'://
returnKING;
case'Q'://
returnQUEEN;
case'R'://
returnROOK;
case'B'://
returnBISHOP;
case'N'://
returnKNIGHT;
}
returnPAWN;//
}
TSideOpponent(TSideside)
{
//获取对手类型
if(side==WHITE)
returnBLACK;
returnWHITE;
}
voidclear(TBoardb,intx,inty)
{
//清空棋盘b的(x,y)位置
b[x][y].side=NONE;//所属玩家
b[x][y].pt=SPACE;//棋子类型
}

voidinit(TBoardb)
{
//初始化棋盘
inti,j;
//清空整个棋盘
for(i=0;i<BOARDSIZE;++i)
for(j=0;j<BOARDSIZE;++j)
{
clear(b,i,j);
}
//摆放各个棋子
for(i=0;i<BOARDSIZE;++i)
{
//棋盘前两行是白方
b[0][i].side=WHITE;
b[
1][i].side=WHITE;
b[
1][i].pt=PAWN;//上面第二行是白方的兵
//棋盘最后两行是黑方
b[6][i].side=BLACK;
b[
7][i].side=BLACK;
b[
6][i].pt=PAWN;//倒数第二行是黑方的兵
}
b[
0][0].pt=b[0][7].pt=b[7][0].pt=b[7][7].pt=ROOK;//初始化车的位置
b[0][1].pt=b[0][6].pt=b[7][1].pt=b[7][6].pt=KNIGHT;//初始化马的位置
b[0][2].pt=b[0][5].pt=b[7][2].pt=b[7][5].pt=BISHOP;//初始化象的位置
b[0][3].pt=b[7][3].pt=QUEEN;//初始化后的位置
b[0][4].pt=b[7][4].pt=KING;//初始化王的位置
//初始化王车易位使用的布尔变量
whitecastled=false;
blackcastled
=false;
white0rookMoved
=false;
white7rookMoved
=false;
black0rookMoved
=false;
black7rookMoved
=false;
whitekingMoved
=false;
blackkingMoved
=false;
}
voidSkipInput(intk)
{
//棋局已经结束,忽略剩余的输入
inti;
charmv[20];
for(i=k;i<n;++i)
{
scanf_s(
"%s",mv);
}
}
voidGetPosition(conststring&move,int&x,int&y)
{
//从输入的移动步骤中获取棋子的目标位置
intk=0;
if(move[0]<'a')//首字母是大写字母
k=1;
x
=move[k+1]-'1';//
y=move[k]-'a';//
}
boolOutOfBoard(intx,inty)
{
//棋子是否超出棋盘界限
if(x<0||y<0)
{
returntrue;
}
if(x>BOARDSIZE||y>BOARDSIZE)
{
returntrue;
}
returnfalse;
}
boolCanMovePawn(TBoardb,intx,inty,intx2,inty2,intflag)
{
//判断能否把兵从(x,y)移动到(x2,y2),当flag=1时,表示(x,y)直接移动到(x2,y2),flag为其他表示从(x,y)吃子到(x2,y2)
if(flag==1)
{
//直接移动,即兵直线前进一格
if(y!=y2||b[x2][y2].side!=NONE)
{
//y坐标不能改变,无法前进
returnfalse;
}
if(b[x][y].side==WHITE)
{
//下棋的是白方
if(x==1)
{
//白方的兵是第一次移动
returnx2==2||(x2==3&&b[2][y].side==NONE);//第一次移动兵可以移动格或格
}
else
{
returnx2==x+1;//不是第一次移动,就只能向前移动格
}
}
else
{
//下棋的是黑方
if(x==6)
{
//黑方的兵是第一次移动
returnx2==5||(x2==4&&b[5][y].side==NONE);//第一次移动兵可以移动格或格
}
else
{
returnx2==x-1;//不是第一次移动,就只能向前移动格
}
}
}
else
{
//吃子判断,吃子时,x向前格,y坐标改变格
if(b[x][y].side==WHITE)
{
//要吃子的是白方
return(x2==x+1&&abs(y2-y)==1);
}
else
{
//要吃子的是黑方
return(x2==x-1&&abs(y2-y)==1);
}
}
returnfalse;
}

boolCanMoveKing(TBoardb,intx,inty,intx2,inty2)
{
//判断能否把王从(x,y)移动到(x2,y2)
return(abs(x-x2)<=1&&abs(y-y2)<=1);
}
boolCanMoveRook(TBoardb,intx,inty,intx2,inty2)
{
//判断能否把车从(x,y)移动到(x2,y2)
intdx,dy,i,xx,yy;
//判断移动是否是直线
if(x!=x2&&y!=y2)
{
returnfalse;
}
//直线方向增量
if(x2<x)
dx
=-1;
else
dx
=1;
if(y2<y)
dy
=-1;
else
dy
=1;
//x方向上移动
for(i=1;i<abs(y-y2);++i)
{
yy
=y+i*dy;
if(b[x][yy].side!=NONE)
{
//中间有棋子阻挡
returnfalse;
}
}
//y方向上移动
for(i=1;i<abs(x-x2);++i)
{
xx
=x+i*dx;
if(b[xx][y].side!=NONE)
{
//中间有棋子阻挡
returnfalse;
}
}
returntrue;
}

boolCanMoveBishop(TBoardb,intx,inty,intx2,inty2)
{
//判断能否把象从(x,y)移动到(x2,y2)
intdx,dy,i,xx,yy;
//是否斜向移动
if(abs(x-x2)!=abs(y-y2))
{
returnfalse;
}
//直线方向增量
if(x2<x)
dx
=-1;
else
dx
=1;
if(y2<y)
dy
=-1;
else
dy
=1;
for(i=1;i<abs(x-x2);++i)
{
xx
=x+i*dx;
yy
=y+i*dy;
if(b[xx][yy].side!=NONE)
{
//中间有棋子阻挡
returnfalse;
}
}
returntrue;
}
boolCanMoveQueen(TBoardb,intx,inty,intx2,inty2)
{
//判断能否把王从(x,y)移动到(x2,y2)
returnCanMoveRook(b,x,y,x2,y2)||CanMoveBishop(b,x,y,x2,y2);//王后等于车+象
}
boolCanMoveKnight(intx,inty,intx2,inty2)
{
//判断马能否从(x,y)移动到(x2,y2)
intxx,yy;
xx
=abs(x-x2);
yy
=abs(y-y2);
return(xx+yy==3&&(xx==1||yy==1));//马行日,x或者y这两者之一移动格,另一方向移动格
}
boolCanMove(TBoardb,intx,inty,intx2,inty2,intflag)
{
//判断一个棋子能否从(x,y)移动到(x2,y2),当flag=1时,直接移动,flag=2时,表示把(x2,y2)处的棋子给吃掉
//判断是否越界
if(OutOfBoard(x,y)||OutOfBoard(x2,y2))
{
returnfalse;
}
//判断原位置是否有棋子
if(b[x][y].side==NONE)
{
returnfalse;
}
//根据原来位置上棋子的不同类型判断是否合法
switch(b[x][y].pt)
{
casePAWN://
returnCanMovePawn(b,x,y,x2,y2,flag);
caseKING://
returnCanMoveKing(b,x,y,x2,y2);
caseQUEEN://
returnCanMoveQueen(b,x,y,x2,y2);
caseROOK://
returnCanMoveRook(b,x,y,x2,y2);
caseBISHOP://
returnCanMoveBishop(b,x,y,x2,y2);
caseKNIGHT://
returnCanMoveKnight(x,y,x2,y2);
}
returnfalse;
}
voidGetSourcePosition(TBoardb,intx2,inty2,int&x,int&y,TPieceTypect,TSideside)
{
/*从给出的位置(x2,y2),类型ct和玩家side,求出移动的棋子的原来位置(x,y),,
*当x=-2时,表示有重复移动方案(Puzzle),x=-1时表示没有移动可能(illegal)
*/
inti,j,flag=1;
if(b[x2][y2].side!=NONE)//目标位置是对手的棋子,则此步为吃子方案
flag=2;
for(i=0;i<BOARDSIZE;++i)
{
for(j=0;j<BOARDSIZE;++j)
{
if(b[i][j].side==side&&b[i][j].pt==ct)
{
//原位置合法并且是同一个子
if(CanMove(b,i,j,x2,y2,flag))
{
if(x==-1)
{
//能够移动并且不重复,找到原来棋子的位置
x=i;
y
=j;
}
else
{
//能够移动并且有方案,说明有重复
x=-2;
return;
}
}
}
}
}
}
voidMarkRookMove(TSideside,intx,inty)
{
if(side==WHITE)
{
if(x==0)
{
if(y==0)
{
white0rookMoved
=true;//白方号车已经移动
}
if(y==7)
{
white7rookMoved
=true;//白方号车已经移动
}
}
return;
}
if(x==7)
{
if(y==0)
{
black0rookMoved
=true;//黑方号车已经移动
}
if(y==7)
{
black7rookMoved
=true;//黑方号车已经移动
}
}
}

voidChessMove(TBoardb,intx,inty,intx2,inty2)
{
//棋子从(x,y)移动到(x2,y2)
b[x2][y2].side=b[x][y].side;
b[x2][y2].pt
=b[x][y].pt;
clear(b,x,y);
//清空原位置
}
voidMakeMove(TBoardb,conststring&move,TSideside)
{
//根据输入的步骤mv,玩家side移动棋子
intx,y,x2,y2;
GetPosition(move,x2,y2);
//目标位置
if(b[x2][y2].side==side)
{
//目标位置处已经有我方的棋子了,此步非法
result=ILLEGAL;
return;
}
x
=-1;
GetSourcePosition(b,x2,y2,x,y,ChessType(move),side);
//尝试寻找原位置
if(x==-1)
{
//非法状态
result=ILLEGAL;
return;
}
elseif(x==-2)
{
//重复状态
result=PUZZLE;
return;
}
//移动的棋子是车时,设置王车易位布尔变量
if(b[x][y].pt==ROOK)
{
MarkRookMove(side,x,y);
}
//移动的棋子是王时,设置王车易位布尔变量
if(b[x][y].pt==KING)
{
if(side==WHITE)//白方王移动了
whitekingMoved=true;
else//黑方王移动了
blackkingMoved=true;
}
ChessMove(b,x,y,x2,y2);
//移动棋子
}
boolGridBeAttack(TBoardb,intx,inty,TSidebyWho)
{
//判断位置(x,y)的棋子能否被吃掉
inti,j;
for(i=0;i<BOARDSIZE;++i)
{
for(j=0;j<BOARDSIZE;++j)
{
if(b[i][j].side==byWho&&CanMove(b,i,j,x,y,2))
{
//会被对手吃掉的
returntrue;
}
}
}
returnfalse;
}
boolCanCastle(TBoardb,TSideside,intflag)
{
//判断是否能够进行王车易位
introw,i;
if(side==WHITE)
{
//白方王车易位
if(whitekingMoved==true)
{
//王已经动了,不能王车易位
returnfalse;
}
if(flag==3&&white7rookMoved==true)
{
//目标车已经动了,不能王车易位
returnfalse;
}
if(flag==5&&white0rookMoved==true)
{
//目标车已经动了,不能王车易位
returnfalse;
}
}
else
{
//黑方王车易位
if(blackkingMoved==true)
{
//王已经动了
returnfalse;
}
if(flag==3&&black7rookMoved==true)
{
//目标车已经动了,不能王车易位
returnfalse;
}
if(flag==5&&black0rookMoved==true)
{
//目标车已经动了,不能王车易位
returnfalse;
}
}
if(side==WHITE)
row
=0;
else
row
=7;
if(flag==5)
{
for(i=1;i<4;++i)
{
if(b[row][i].side!=NONE)
{
//王车之间是否有棋子,若有则不能易位
returnfalse;
}
}
for(i=0;i<5;++i)
{
if(GridBeAttack(b,row,i,Opponent(side))==true)
{
//在目标位置上会被对手吃掉,不能王车易位
returnfalse;
}
}
}
else
{
for(i=5;i<BOARDSIZE-1;++i)
{
if(b[row][i].side!=NONE)
{
//王车之间是否有棋子,若有则不能易位
returnfalse;
}
}
for(i=4;i<BOARDSIZE;++i)
{
if(GridBeAttack(b,row,i,Opponent(side)))
{
//在目标位置上会被对手吃掉,不能王车易位
returnfalse;
}
}
}
returntrue;//检查符合要求,可以王车易位
}
voidCastle(TBoardb,TSideside,intflag)
{
//进行王车易位,flag=3,表示靠近王的车King-sidecastle,flag=5时,表示Queen-sidecastle
introw;
if(side==WHITE)
{
if(whitecastled==true)
{
//白方是否已经易位,已经易过位,不能再易了
result=ILLEGAL;
return;
}
else
whitecastled
=true;//设置易位变量
}
else
{
if(blackcastled==true)
{
//黑方是否已经易位,已经易过位,不能再易了
result=ILLEGAL;
return;
}
else
blackcastled
=true;
}
if(CanCastle(b,side,flag)==true)
{
//判断是否能够易位
if(side==WHITE)
{
row
=0;
}
else
{
row
=7;
}
if(flag==3)
{
//进行王车易位
ChessMove(b,row,4,row,6);
ChessMove(b,row,
7,row,5);
}
else
{
ChessMove(b,row,
4,row,2);
ChessMove(b,row,
0,row,3);
}
}
else
{
//无法王车易位,此步非法
result=ILLEGAL;
}
}
voidGetKingPosition(TBoardb,TSideside,int&x,int&y)
{
//寻找国王的位置
inti,j;
for(i=0;i<BOARDSIZE;++i)
{
for(j=0;j<BOARDSIZE;++j)
{
if(b[i][j].pt==KING&&b[i][j].side==side)
{
//找到指定方的王
x=i;
y
=j;
return;
}
}
}
}
boolBeCheck(TBoardb,TSideside)
{
//判断是否被“将军"
intx,y,i,j;
TSideoppSide;
GetKingPosition(b,side,x,y);
//寻找玩家side的王
oppSide=Opponent(side);//对手
for(i=0;i<BOARDSIZE;++i)
{
for(j=0;j<BOARDSIZE;++j)
{
if(b[i][j].side==oppSide&&CanMove(b,i,j,x,y,2)==true)
{
//判断对手是否能否将军,flag=2表示此步是吃子,
returntrue;
}
}
}
returnfalse;
}
voidCopyBoard(TBoarddesBoard,TBoardsrcBoard)
{
//复制棋盘
inti,j;
for(i=0;i<BOARDSIZE;++i)
{
for(j=0;j<BOARDSIZE;++j)
{
desBoard[i][j].pt
=srcBoard[i][j].pt;
desBoard[i][j].side
=srcBoard[i][j].side;
}
}
}
boolNoMoveAvailable(TBoardb,TSideside)
{
//判断是否是僵局
intx,y,x2,y2;
TBoardb2;
for(x=0;x<BOARDSIZE;++x)
{
for(y=0;y<BOARDSIZE;++y)
{
if(b[x][y].side==side)
{
for(x2=0;x2<BOARDSIZE;++x2)
{
for(y2=0;y2<BOARDSIZE;++y2)
{
//判断side方的王能否从(x,y)走到(x2,y2)
if((x2!=x||y2!=y)&&b[x][y].side!=b[x2][y2].side&&CanMove(b,x,y,x2,y2,1))
{
if(b[x][y].pt==KING)
{
CopyBoard(b2,b);
ChessMove(b2,x,y,x2,y2);
if(!BeCheck(b2,side))
{
//判断位置是否被”将军“,没有就不是僵局
returnfalse;
}
}
else
{
returnfalse;
}
}
}
}
}
}
}
returntrue;
}
boolCheckMate(TBoardb,TSideside)
{
//判断是否已经结束(即是否某一方被将死)
intx,y,x2,y2;
TBoardb2;
if(!BeCheck(b,side))
{
//没有被将死
returnfalse;
}
for(x=0;x<BOARDSIZE;++x)
{
for(y=0;y<BOARDSIZE;++y)
{
if(b[x][y].side==side)
{
for(x2=0;x2<BOARDSIZE;++x2)
{
for(y2=0;y2<BOARDSIZE;++y2)
{
if((x!=x2||y!=y2)&&b[x2][y2].side!=side)
{
//王能否从(x,y)移动到(x2,y2)
if(CanMove(b,x,y,x2,y2,1)==true)
{
CopyBoard(b2,b);
ChessMove(b2,x,y,x2,y2);
if(!BeCheck(b2,side)==true)
{
//移动后没有被"将军"
returnfalse;
}
}
if(b[x][y].pt==PAWN&&CanMove(b,x,y,x2,y2,2)==true)
{
CopyBoard(b2,b);
ChessMove(b2,x,y,x2,y2);
if(!BeCheck(b2,side))
{
returnfalse;
}
}
}
}
}
}
}
}
returntrue;
}
voidrun(TBoardb)
{
//下棋过程
stringmove;//当前步
TSideside;
side
=WHITE;//起手是白方先走
inti;
for(i=0;i<n;++i)
{
if(result==WHITEWIN||result==BLACKWIN||result==STALEMATE)
{
//棋局已经结束,但还有输入没处理完,状态为DEAD
result=DEAD;
SkipInput(i);
//忽略其余输入
return;
}
cin
>>move;//输入棋子移动步骤
if(move[0]!='O')
{
//不是王车易位
MakeMove(b,move,side);//根据输入的步骤mv,玩家side移动棋子
}
else
{
//王车易位
Castle(b,side,move.length());
}
if(BeCheck(b,side)==true)
{
//移动棋子后被对手"将军"
result=ILLEGAL;
}
if(result==PUZZLE||result==ILLEGAL)
{
//非法输入或不清楚原来的棋子,则跳过数据
SkipInput(i+1);
return;
}
if(CheckMate(b,Opponent(side)))
{
//被”将死“时,判断获胜方
if(side==WHITE)
{
result
=WHITEWIN;
}
else
{
result
=BLACKWIN;
}

}
side
=Opponent(side);//换到对方下了
}
if(result==DRAW&&NoMoveAvailable(b,side)==true)
{
//是否是僵局
result=STALEMATE;
}
}
intmain()
{
TBoardboard;
//棋盘
//输入输出重定向
freopen("chess.in","r",stdin);
freopen(
"chess.out","w",stdout);
while(cin>>n&&n!=0)
{
init(board);
//初始化棋盘
result=DRAW;//一开始假设结果为和局
run(board);//下棋过程
cout<<RESULT[result]<<endl;
}
return0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值