#include <iostream>
#include <string>
#include <cmath>
using namespace std;
enum TResult
{//结局状态
WHITEWIN = 1,//白方赢
BLACKWIN,//黑方赢
STALEMATE,//僵局
DRAW,//和局
DEAD,//过多的输入
PUZZLE,//无法决定移动棋子
ILLEGAL //非法
};
const char RESULT[8][20]=
{//结局状态输出表示
"",
"White Win",
"Black Win",
"Stalemate",
"Draw",
"Dead Moves",
"Puzzle Move",
"Illegal Move"
};
enum TPieceType
{//棋子类型
SPACE = 0,
PAWN,//兵
KING,//王
QUEEN,//后
ROOK,//车
BISHOP,//象
KNIGHT //马
};
enum TSide
{
NONE = 0,
WHITE,//黑方
BLACK //白方
};
typedef struct
{//棋盘每个位置的表示
TSide side;//所属玩家
TPieceType pt;//棋子类型
}TPiece;
const int BOARDSIZE = 8;//棋盘大小
typedef TPiece TBoard[BOARDSIZE][BOARDSIZE];//棋盘
int n;//棋谱步数
TResult result;//最后结局
/*
*用来进行王车易位的布尔变量
*
* whitecastled:白方是否已经王车易位
* blackcastled:黑方是否已经王车易位
* white0rookMoved: 白方号位的车是否已经移动
* white7rookMoved: 白方号位的车是否已经移动
* black0rookMoved: 黑方号位的车是否已经移动
* black7rookMoved: 黑方号位的车是否已经移动
* whitekingMoved: 白方王是否已经移动
* blackkingMoved: 黑方王是否已经移动
*
*/
bool whitecastled,blackcastled,white0rookMoved,white7rookMoved,black0rookMoved,black7rookMoved,whitekingMoved,blackkingMoved;
TPieceType ChessType(const string& move)
{
switch(move[0])
{
case 'K'://王
return KING;
case 'Q'://后
return QUEEN;
case 'R'://车
return ROOK;
case 'B'://象
return BISHOP;
case 'N'://马
return KNIGHT;
}
return PAWN;//兵
}
TSide Opponent(TSide side)
{//获取对手类型
if (side==WHITE)
return BLACK;
return WHITE;
}
void clear(TBoard b,int x,int y)
{//清空棋盘b的(x,y)位置
b[x][y].side = NONE;//所属玩家
b[x][y].pt = SPACE;//棋子类型
}
void init(TBoard b)
{//初始化棋盘
int i,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;
}
void SkipInput(int k)
{//棋局已经结束,忽略剩余的输入
int i;
char mv[20];
for(i=k;i<n;++i)
{
scanf_s("%s",mv);
}
}
void GetPosition(const string& move,int &x,int &y)
{//从输入的移动步骤中获取棋子的目标位置
int k = 0;
if(move[0]<'a')//首字母是大写字母
k = 1;
x = move[k+1]-'1';//行
y = move[k]-'a';//列
}
bool OutOfBoard(int x,int y)
{//棋子是否超出棋盘界限
if (x<0||y<0)
{
return true;
}
if (x>BOARDSIZE||y>BOARDSIZE)
{
return true;
}
return false;
}
bool CanMovePawn(TBoard b,int x,int y,int x2,int y2,int flag)
{//判断能否把兵从(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坐标不能改变,无法前进
return false;
}
if (b[x][y].side==WHITE)
{//下棋的是白方
if (x==1)
{//白方的兵是第一次移动
return x2==2 || (x2==3&&b[2][y].side==NONE);//第一次移动兵可以移动格或格
}
else
{
return x2==x+1;//不是第一次移动,就只能向前移动格
}
}
else
{//下棋的是黑方
if (x==6)
{//黑方的兵是第一次移动
return x2==5 || (x2==4&&b[5][y].side==NONE);//第一次移动兵可以移动格或格
}
else
{
return x2==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);
}
}
return false;
}
bool CanMoveKing(TBoard b,int x,int y,int x2,int y2)
{//判断能否把王从(x,y)移动到(x2,y2)
return (abs(x-x2)<=1&&abs(y-y2)<=1);
}
bool CanMoveRook(TBoard b,int x,int y,int x2,int y2)
{//判断能否把车从(x,y)移动到(x2,y2)
int dx,dy,i,xx,yy;
//判断移动是否是直线
if (x!=x2 && y!=y2)
{
return false;
}
//直线方向增量
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)
{//中间有棋子阻挡
return false;
}
}
//y方向上移动
for (i=1;i<abs(x-x2);++i)
{
xx = x+i*dx;
if (b[xx][y].side!=NONE)
{//中间有棋子阻挡
return false;
}
}
return true;
}
bool CanMoveBishop(TBoard b,int x,int y,int x2,int y2)
{//判断能否把象从(x,y)移动到(x2,y2)
int dx,dy,i,xx,yy;
//是否斜向移动
if (abs(x-x2)!=abs(y-y2))
{
return false;
}
//直线方向增量
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)
{//中间有棋子阻挡
return false;
}
}
return true;
}
bool CanMoveQueen(TBoard b,int x,int y,int x2,int y2)
{//判断能否把王从(x,y)移动到(x2,y2)
return CanMoveRook(b,x,y,x2,y2) || CanMoveBishop(b,x,y,x2,y2);//王后等于车+象
}
bool CanMoveKnight(int x,int y,int x2,int y2)
{//判断马能否从(x,y)移动到(x2,y2)
int xx,yy;
xx = abs(x-x2);
yy = abs(y-y2);
return (xx+yy==3 && (xx==1 || yy==1));//马行日,x或者y这两者之一移动格,另一方向移动格
}
bool CanMove(TBoard b,int x,int y,int x2,int y2,int flag)
{//判断一个棋子能否从(x,y)移动到(x2,y2),当flag=1时,直接移动,flag=2时,表示把(x2,y2)处的棋子给吃掉
//判断是否越界
if (OutOfBoard(x,y)||OutOfBoard(x2,y2))
{
return false;
}
//判断原位置是否有棋子
if (b[x][y].side==NONE)
{
return false;
}
//根据原来位置上棋子的不同类型判断是否合法
switch (b[x][y].pt)
{
case PAWN://兵
return CanMovePawn(b,x,y,x2,y2,flag);
case KING://王
return CanMoveKing(b,x,y,x2,y2);
case QUEEN://后
return CanMoveQueen(b,x,y,x2,y2);
case ROOK://车
return CanMoveRook(b,x,y,x2,y2);
case BISHOP://象
return CanMoveBishop(b,x,y,x2,y2);
case KNIGHT://马
return CanMoveKnight(x,y,x2,y2);
}
return false;
}
void GetSourcePosition(TBoard b,int x2,int y2,int &x,int &y,TPieceType ct,TSide side)
{/*从给出的位置(x2,y2),类型ct和玩家side,求出移动的棋子的原来位置(x,y),,
* 当x=-2时,表示有重复移动方案(Puzzle),x=-1时表示没有移动可能(illegal)
*/
int i,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;
}
}
}
}
}
}
void MarkRookMove(TSide side,int x,int y)
{
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;//黑方号车已经移动
}
}
}
void ChessMove(TBoard b,int x,int y,int x2,int y2)
{//棋子从(x,y)移动到(x2,y2)
b[x2][y2].side = b[x][y].side;
b[x2][y2].pt = b[x][y].pt;
clear(b,x,y);//清空原位置
}
void MakeMove(TBoard b,const string& move,TSide side)
{//根据输入的步骤mv,玩家side移动棋子
int x,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;
}
else if (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);//移动棋子
}
bool GridBeAttack(TBoard b,int x,int y,TSide byWho)
{//判断位置(x,y)的棋子能否被吃掉
int i,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))
{//会被对手吃掉的
return true;
}
}
}
return false;
}
bool CanCastle(TBoard b,TSide side,int flag)
{//判断是否能够进行王车易位
int row,i;
if (side==WHITE)
{//白方王车易位
if (whitekingMoved==true)
{//王已经动了,不能王车易位
return false;
}
if (flag==3&&white7rookMoved==true)
{//目标车已经动了,不能王车易位
return false;
}
if (flag==5&&white0rookMoved==true)
{//目标车已经动了,不能王车易位
return false;
}
}
else
{//黑方王车易位
if (blackkingMoved==true)
{//王已经动了
return false;
}
if (flag==3 && black7rookMoved==true)
{//目标车已经动了,不能王车易位
return false;
}
if (flag==5 && black0rookMoved==true)
{//目标车已经动了,不能王车易位
return false;
}
}
if (side==WHITE)
row = 0;
else
row = 7;
if (flag==5)
{
for (i=1;i<4;++i)
{
if (b[row][i].side!=NONE)
{//王车之间是否有棋子,若有则不能易位
return false;
}
}
for (i=0;i<5;++i)
{
if (GridBeAttack(b,row,i,Opponent(side))==true)
{//在目标位置上会被对手吃掉,不能王车易位
return false;
}
}
}
else
{
for (i=5;i<BOARDSIZE-1;++i)
{
if (b[row][i].side!=NONE)
{//王车之间是否有棋子,若有则不能易位
return false;
}
}
for (i=4;i<BOARDSIZE;++i)
{
if (GridBeAttack(b,row,i,Opponent(side)))
{//在目标位置上会被对手吃掉,不能王车易位
return false;
}
}
}
return true;//检查符合要求,可以王车易位
}
void Castle(TBoard b,TSide side,int flag)
{//进行王车易位,flag=3,表示靠近王的车King-side castle,flag=5时,表示Queen-side castle
int row;
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;
}
}
void GetKingPosition(TBoard b,TSide side,int &x,int &y)
{//寻找国王的位置
int i,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;
}
}
}
}
bool BeCheck(TBoard b,TSide side)
{//判断是否被“将军"
int x,y,i,j;
TSide oppSide;
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表示此步是吃子,
return true;
}
}
}
return false;
}
void CopyBoard(TBoard desBoard,TBoard srcBoard)
{//复制棋盘
int i,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;
}
}
}
bool NoMoveAvailable(TBoard b,TSide side)
{//判断是否是僵局
int x,y,x2,y2;
TBoard b2;
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))
{//判断位置是否被”将军“,没有就不是僵局
return false;
}
}
else
{
return false;
}
}
}
}
}
}
}
return true;
}
bool CheckMate(TBoard b,TSide side)
{//判断是否已经结束(即是否某一方被将死)
int x,y,x2,y2;
TBoard b2;
if (!BeCheck(b,side))
{//没有被将死
return false;
}
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)
{//移动后没有被"将军"
return false;
}
}
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))
{
return false;
}
}
}
}
}
}
}
}
return true;
}
void run(TBoard b)
{//下棋过程
string move;//当前步
TSide side;
side = WHITE;//起手是白方先走
int i;
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;
}
}
int main()
{
TBoard board;//棋盘
//输入输出重定向
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;
}
return 0;
}
复制代码
本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/11/04/1326527.html,如需转载请自行联系原作者