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

简介:
#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,如需转载请自行联系原作者
目录
相关文章
|
C++
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解
175 0
|
存储 C++
2020 第十一届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解
2020 第十一届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解
98 0
|
算法
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
111 0
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
|
人工智能 Dart 算法
【算法题解】2022河南萌新联赛第(四)场:郑州轻工业大学
【算法题解】2022河南萌新联赛第(四)场:郑州轻工业大学
【算法题解】2022河南萌新联赛第(四)场:郑州轻工业大学
试题历届真题跑步锻炼【第十一届】【省赛】【B组】(C++)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 小蓝每天都锻炼身体。正常情况下,小蓝每天跑 11 千米。如果某天是周一或者月初(11 日),为了激励自己,小蓝要跑 22 千米。如果同时是周一或月初,小蓝也是跑 22 千米。 小蓝跑步已经坚持了很长时间,从 20002000 年 11 月 11 日周六(含)到 20202020 年 1010 月 11 日周四(含)。请问这段时间小蓝总共跑步多少千米?
119 0
1275: [蓝桥杯2015决赛]五星填数
五星图案节点填上数字:1~12,除去7和11。要求每条直线上数字和相等。
1275: [蓝桥杯2015决赛]五星填数
|
Web App开发 监控 网络安全
第六届蓝盾杯山东赛区省赛-比赛反思
版权声明:转载请注明出处:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79396663 本来是确定好三个人去参赛的,其中一个web主力因为私事,没能去,我只好顶替。
933 0