国际象棋C++.docx
《国际象棋C++.docx》由会员分享,可在线阅读,更多相关《国际象棋C++.docx(25页珍藏版)》请在冰豆网上搜索。
国际象棋C++
#include
#include
#include
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//白方
};
typedefstruct
{//棋盘每个位置的表示
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;ifor(j=0;j{
clear(b,i,j);
}
//摆放各个棋子
for(i=0;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{
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(x2dx=-1;
else
dx=1;
if(y2dy=-1;
else
dy=1;
//x方向上移动
for(i=1;i{
yy=y+i*dy;
if(b[x][yy].side!
=NONE)
{//中间有棋子阻挡
returnfalse;
}
}
//y方向上移动
for(i=1;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(x2dx=-1;
else
dx=1;
if(y2dy=-1;
else
dy=1;
for(i=1;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)
{
returnCanMovePawn(b,x,y,x2,y2,flag);
returnCanMoveKing(b,x,y,x2,y2);
returnCanMoveQueen(b,x,y,x2,y2);
returnCanMoveRook(b,x,y,x2,y2);
returnCanMoveBishop(b,x,y,x2,y2);
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{
for(j=0;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{
for(j=0;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{
if(b[row][i].side!
=NONE)
{//王车之间是否有棋子,若有则不能易位
returnfalse;
}
}
for(i=4;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{
for(j=0;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;
GetKingPos