UVa 10196 将军

18 篇文章 0 订阅
6 篇文章 0 订阅
The Problem

Your task is to write a program that reads a chess board configuration and answers if there‘s a king under attack (i.e. "in check"). A king is in check if it‘s in a square which is attacked by an oponnet‘s piece (i.e. it‘s in square which can be taken by an oponnet‘s piece in his next move).


White pieces will be represented by uppercase letters whereas black pieces will be represented by lowercase letters. White side will always be on the bottom of the board and black side will always be on the top of the board.


For those unfamiliar with chess, here are the movements of each piece:


Pawn (p or P): can only move straight ahead, one square at a time. But it takes pieces diagonally (and that‘s what concerns to you in this problem).
Knight (n or N): have a special movement and it‘s the only piece that can jump over other pieces. The knight movement can be viewed as an "L". See the example bellow.
Bishop (b or B): can move any number of squares diagonally (forward or backward).
Rook (r or R): can move any number of squares vertically or horizontally (forward or backward).
Queen (q or Q): can move any number of squares in any direction (diagonally, horizontally or vertically, forward or backward).
King (k or K): can move one square at a time, in any direction (diagonally, horizontally or vertically, forward or backward).


Movements examples (‘*‘ indicates where the piece can take another pieces):


Pawn
........
........
........
........
...p....
..*.*...
........
........

Rook
...*....
...*....
...*....
...*....
***r****
...*....
...*....
...*....

Bishop
.......*
*.....*.
.*...*..
..*.*...
...b....
..*.*...
.*...*..
*.....*.

Queen
...*...*
*..*..*.
.*.*.*..
..***...
***q****
..***...
.*.*.*..
*..*..*.

King
........
........
........
..***...
..*k*...
..***...
........
........

Knight
........
........
..*.*...
.*...*..
...n....
.*...*..
..*.*...
........


    
Remember that the knight is the only piece that can jumper over other pieces. The pawn movement will depend on its side. If it‘s a black pawn, it can only move one square diagonally down the board. If it‘s a white pawn, it can only move one square diagonally up the board. The example above is a black pawn as it‘s a lowercase p (we say "move" meaning the squares where the pawn can move to when it takes another piece).
The Input

There will be an arbitrary number of board configurations on the input. Each board will consist of 8 lines of 8 characters each. A ‘.‘ character will represent an empty square. Upper and lower case letters (as defined above) will represent the pieces. There will be no invalid characters (i.e. pieces) and there won‘t be a configuration where both kings are in check. You must read until you find an empty board (i.e. a board that is formed only of ‘.‘ characters) which should not be processed. There will be an empty line between each pair of board configurations. In all boards (except the last one which is empty) will appear both the white king and the black king (one, and only one of each).
The Output

For each board configuration read you must output one of the following answers:

Game #d: white king is in check.
Game #d: black king is in check.
Game #d: no king is in check.

Where d stands for the game number (starting from 1).
Sample Input

..k.....
ppp.pppp
........
.R...B..
........
........
PPPPPPPP
K.......


rnbqkbnr
pppppppp
........
........
........
........
PPPPPPPP
RNBQKBNR


rnbqk.nr
ppp..ppp
....p...
...p....
.bPP....
.....N..
PP..PPPP
RNBQKB.R


........
........
........
........
........
........
........
........


Sample Output


Game #1: black king is in check.
Game #2: no king is in check.

Game #3: white king is in check.


大致思路:在一个二维数组之间判定两个棋子之间的位置关系

一 关于国际象棋的部分细则

1 分清楚每种棋子有几种将军的情况,其中有些情况可以用绝对值合并。

2 王后的走法其实是车和象的并集。

3 王不能吃王


代码:

#include <stdbool.h>
typedef struct{
    int x;
    int y;
}ChessPiece;
char layout[8][8];

int inputLayout()
{
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
            scanf("%c",&layout[i][j]);
        scanf("%*c");
    }
    return 0;
}
//卒吃王
bool checkP(ChessPiece cp1,ChessPiece cp2)
{//2种情况
    return cp1.x-cp2.x==1&&abs(cp1.y-cp2.y)==1;
}
//马吃王
bool checkN(ChessPiece cp1,ChessPiece cp2)
{//8种情况,不别住马腿
    return (abs(cp1.x-cp2.x)==1&&abs(cp1.y-cp2.y)==2)||
            (abs(cp1.x-cp2.x==2&&abs(cp2.y-cp2.y)==1));
}
//象吃王,象不能跨越棋子
bool checkB(ChessPiece cp1,ChessPiece cp2)
{

    //两子横坐标距离步长
    int step;
    //当前扫描字
    ChessPiece currentPiece=cp1;
    //方向 相对于cp2,是在cp2下还是上
    ChessPiece direct;
    //是否将军,true 为将军
    bool checked=false;
    //两子位于对角线上两点,4个方向
    //从输入上保证了cp1和cp2 不同
    if(abs(cp1.x-cp2.x)==abs(cp1.y-cp2.y))
    {
        //差值大于等于1的情况
        checked=true;
        //以cp1为中心,若cp1在cp2 上方,则为1,否则为-1;
        direct.x=cp1.x<cp2.x?1:-1;//1<2 cp1在cp2的上方,
        direct.y=cp1.y<cp2.y?1:-1;//1<2 ,cp1在cp2的左方

        step=abs(cp1.x-cp2.x);
        //以cp2为圆心,step为半径,由外向内
        //==1的时候必然能吃掉
        while(step>1)
        {
            //当前扫描到的棋子是否是挡子
            currentPiece.x+=direct.x;
            currentPiece.y+=direct.y;

            if(layout[currentPiece.x][currentPiece.y]!='.')
            {
                checked=false;
                break;
            }
            step--;
        }
    }
    return checked;
}
//车吃王
bool checkR(ChessPiece cp1,ChessPiece cp2)
{
    ChessPiece currentPiece=cp1;
    ChessPiece direct;
    int step;
    bool checked=false;
    if(cp1.x==cp2.x||cp1.y==cp2.y)
    {
        checked=true;
        direct.x=cp1.x==cp2.x?(0):(cp1.x<cp2.x?1:-1);
        direct.y=cp1.y==cp2.y?(0):(cp1.y<cp2.y?1:-1);

        step=direct.x==0?abs(cp1.y-cp2.y):abs(cp1.x-cp2.x);
        while(step>1)
        {
            currentPiece.x+=direct.x;
            currentPiece.y+=direct.y;
            if(layout[currentPiece.x][currentPiece.y]!='.')
            {
                checked=false;
                break;
            }
            step--;
        }
    }
    return checked;
}
//后吃王
//实际上是车和象的并集
bool checkQ(ChessPiece cp1,ChessPiece cp2)
{
    return checkB(cp1,cp2)||checkR(cp1,cp2);
}
 王吃王,规则上不允许
//bool checkK(ChessPiece cp1,ChessPiece cp2)
//{
//    return (cp1.x-cp2.x==cp1.y-cp2.y)||(cp1.x==cp2.x&&abs(cp1.y-cp2.y)==1)||
//            (cp1.y==cp2.y&&abs(cp1.x-cp2.x)==1);
//}
int check(int time)
{
    bool blackCheck,whiteCheck;
    ChessPiece blackKing,whiteKing;
    blackKing.x=-1,blackKing.y=-1;
    whiteKing.x=-1,whiteKing.y=-1;
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            if(layout[i][j]=='k')
            {
                blackKing.x=i;
                blackKing.y=j;
            }
            if(layout[i][j]=='K')
            {
                whiteKing.x=i;
                whiteKing.y=j;
            }
        }
    }
    if(blackKing.x==-1)
        exit (0);
    printf("Game#%d: ",time);
    ChessPiece currentPiece;
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            currentPiece.x=i;
            currentPiece.y=j;
            switch(layout[i][j])
            {
                case 'p':
                    whiteCheck=checkP(whiteKing,currentPiece);
                    break;
                case 'P':
                    blackCheck=checkP(blackKing,currentPiece);
                    break;
                case 'n':
                    whiteCheck=checkN(whiteKing,currentPiece);
                    break;
                case 'N':
                    blackCheck=checkN(blackKing,currentPiece);
                    break;
                case 'b':
                    whiteCheck=checkB(whiteKing,currentPiece);
                    break;
                case 'B':
                    blackCheck=checkB(blackKing,currentPiece);
                    break;
                case 'r':
                    whiteCheck=checkR(whiteKing,currentPiece);
                    break;
                case 'R':
                    blackCheck=checkR(blackKing,currentPiece);
                    break;
                case 'q':
                    whiteCheck=checkQ(whiteKing,currentPiece);
                    break;
                case 'Q':
                    blackCheck=checkQ(currentPiece,blackKing);
                    break;
                default:
                    break;
            }
            // 在for循环里直接检查 whitecheck和blackcheck,因为若检查放在双循环外,对于接下来的棋子排布,可能改变whitecheck和blackcheck,程序正确也会改变,没有将军就是false呗
            //一开始的思路是怎样用break跳出两层循环,其实跳出双循环的目的就是直接进行check的条件判断,所以有另一种解决方法,就是把条件判断放到for循环内执行
            if(whiteCheck==true)
            {
                printf("white king is in check");
                return 1;
            }
            if(blackCheck==true)
            {
                printf("black king is in check");
                return 1;
            }
        }
    }
    printf("no king is in check");
    return 0;
}
int process()
{
    int time=1;
    while(1)
    {
        inputLayout();
        check(time);
        time++;
    }
    return 0;
}

二 规则实现

1 判断两子在对角线实际上是 二子的横、纵坐标各自差值的绝对值相同。

2 判断两子之间是否有挡子,其实是判断对角线上是否为’ .’,

3 从一个子向外的对角线其实有4条,分4个方向,这就需要判断两个棋子的相对位置。根据相对位置来确定对角线的每个格子的坐标。

4 只要发现有将军的情况,判定谁赢之后,就结束程序,不再向下继续扫描棋盘。

三代码编写总结:

1 exit(0)与return的区别,在只有一个函数的程序中,二者没有区别,在有函数调用的时候,前者确实是退出程序,后者是把执行权移交给函数上一级。

2 在嵌套循环中,在内循环符合某个条件时,执行完与符合的条件相对应的语句后想退出程序,具体到本程序,

   /在for循环里直接检查whitecheck和blackcheck,因为若检查放在双循环外,接下来的棋子排布就可能改变whitecheck和blackcheck的值,

           一开始的思路是怎样用break跳出两层循环,其实跳出双循环的目的就是直接进行check的条件判断,所以有另一种解决方法,就是把条件判断放到for循环内执行。

3 本程序对于各个棋子的走步规则子函数不分颜色,只是在扫描棋盘判定的时候,设置两个布尔变量,也就是黑方胜负和白方胜负,根据字母大小写判定是黑棋是白棋。

4 判定no king is in check:在判定函数中把两方的王初始坐标设置为-1,如果扫描棋局后只要有坐标是-1,就是no king is in check,也就是棋面上没有王就说明棋面不完整。

5 代码参考自 寂静山林 寂静山林的博客http://blog.csdn.net/metaphysis/article/details/6432094
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值