1589 - Xiangqi

来源:互联网 发布:怎么跟网络管理员联系 编辑:程序博客网 时间:2024/06/07 03:12

Xiangqi is one of the most popular two-playerboard games in China. The game represents a battle between two armies with thegoal of capturing the enemy's ``general" piece. In this problem, you aregiven a situation of later stage in the game. Besides, the red side has already``delivered a check". Your work is to check whether the situationis ``checkmate".

Now we introduce some basic rules of Xiangqi.Xiangqi is played on a 10 x 9 board and the pieces areplaced on the intersections (points). The top left point is (1,1) and thebottom right point is (10,9). There are two groups of pieces marked by black orred Chinese characters, belonging to the two players separately. During thegame, each player in turn moves one piece from the point it occupies to anotherpoint. No two pieces can occupy the same point at the same time. A piece can bemoved onto a point occupied by an enemy piece, in which case the enemy pieceis``captured" and removed from the board. When the general is in danger ofbeing captured by the enemy player on the enemy player's next move, the enemyplayer is said to have ``delivered a check". If the general'splayer can make no move to prevent the general's capture by next enemy move,the situation is called ``checkmate".


We only use 4 kinds of pieces introducing as follows:

General: the generals can move and capture one point eithervertically or horizontally and cannot leave the ``palace" unlessthe situation called ``flying general" (see the figure above).``Flying general" means that one general can ``fly" across the boardto capture the enemy general if they stand on the same line without interveningpieces.

Chariot: the chariots can move and capture vertically and horizontally byany distance, but may not jump over intervening pieces

Cannon: the cannons move like the chariots, horizontally and vertically,but capture by jumping exactly one piece (whether it isfriendly or enemy) over to its target.

Horse: the horses have 8 kinds of jumps to move and capture shown in theleft figure. However, if there is any pieces lying on a point away from thehorse horizontally or vertically it cannot move or capture in that direction(see the figure below), which is called ``hobbling the horse's leg".

Now you are given a situation only containinga black general, a red general and several red chariots, cannons and horses,and the red side has delivered a check. Now it turns to black side's move. Yourjob is to determine that whether this situation is ``checkmate".

Input 

The input contains no more than 40 testcases. For each test case, the first line contains three integers representingthe number of red pieces N ( 2N7) and the position of theblack general. The following N lines contain details of N redpieces. For each line, there are a char and two integers representing the typeand position of the piece (type char `G' for general, `R' for chariot, `H' forhorse and `C' for cannon). We guarantee that the situation is legal and the redside has delivered the check.

There is a blank line between two test cases.The input ends by `0 0 0'.

Output 

For each test case, if the situation ischeckmate, output a single word `YES', otherwise output the word `NO'.


Hint: In the first situation, the black general is checked by chariot and``flying general''. In the second situation, the black general can move to (1,4) or (1, 6) to stop check. See the figure below.

Sample Input 

 

2 1 4

G 10 5

R 6 4

 

3 1 5

H 4 5

G 10 5

C 7 5

 

0 0 0

Sample Output 

 

YES

NO

参考答案:

构造一个Xiangqi类来求解。首先黑子会动很麻烦,因此要把动态问题改成静态.如果题目只是给你一个局面,问你当前红方动,能不能把黑方吃掉是不是简单多了?所以要生成一个Xiangqi对象A,按input数据初始化。然后只要黑将不跟红帅面对面直接吃掉,他至多有四种移动方案,用A来生成黑将移动后的Xiangqi对象B。如上,B是一个静态问题。那么现在关键是Xiangqi类的书写,棋盘存到二维数组board中不做修改红帅和黑将是棋盘的核心,所以要定义ax,ay,bx,by存储它们所在的坐标,坐标也从1开始编号,不容易混乱思路,而且留有边界board[0],一些操作也会很方便。车、将、炮吃子的本质是相同的。都是要在同一横线或竖线,但中间隔的棋子一种是0个,一种是1个。这种操作可以定义一个基础函数Cnt,可以计算(x,y)与黑将是否在同一横线或竖线,不满足则返回-1。否则返回两坐标间隔的棋子数。注意这里的技巧,不是计算任意两点,而是任意一点到黑将,因为所有的子都是围绕黑将展开的,都是要去吃它。这样就能简化函数节省代码量。马的吃子看似麻烦,其实符合很特别的数量规律。记其行列偏移量分别为dx和dy,有没注意到dx*dy的绝对值一定是2?“蹩马腿”的技巧也是一样,详见函数H的代码。

#include<algorithm>

#include<cmath>

#include<cstdio>

#include<cstring>

#include<iostream>

using namespacestd;

 

struct Xiangqi

{

    int board[11][10];

    int ax, ay, bx, by; // a是红方的帅,b是黑方的将; x,y是坐标

 

    // 构造函数遵循题目的输入格式

    Xiangqi(int n, int _bx, int _by): bx(_bx),by(_by)

    {

        memset(board, 0, sizeof(board));

        board[bx][by] = 'Y';    // 用字母Y代表黑将

        char type[5];

        int x, y;

        for (int i = 0; i < n; i++)

        {

            scanf("%s%d%d", type,&x, &y);

            board[x][y] = type[0];

        }

    }

 

    // 黑将做(dx,dy)的移动,移动成功则返回1,否则0

    int go(int dx, int dy)

    {

        if (bx+dx>0 && bx+dx<4&& by+dy>3 && by+dy<7)

        {

            board[bx][by] = 0;

            bx += dx;

            by += dy;

            board[bx][by] = 'Y';

            return 1;

        }

        return 0;

    }

 

    // 判断(x,y)到(bx,by)中间一共有多少棋子,重叠与不在同一竖直、水平线返回-1

    int Cnt(int x, int y)

    {

        int cnt = -1, i, j;

        if (x == bx && y != by)

            {

                for (cnt = 0, j = min(y,by)+1; j< max(y,by); j++)

                {

                    if (board[x][j]) cnt++;

                }

            }

        if (x != bx && y == by)

            {

                for (cnt = 0, i = min(x,bx)+1;i < max(x,bx); i++)

                {

                    if (board[i][y]) cnt++;

                }

            }

        return cnt;

    }

 

    // 判断在(x,y)的马能不能吃掉黑将

    int H(int x, int y)

    {

        int dx = bx - x, dy = by - y;

        if (abs(dx*dy) != 2)

        {

            return 0;

        }

        if (abs(dx)==2)

        {

            if (board[x+dx/2][y])

            {

                return 0;

            }

        }

        if (abs(dy)==2)

        {

            if (board[x][y+dy/2])

            {

                return 0;

            }

        }

        return 1;

    }

 

    // 判断如果当前棋盘红方移动,黑方是否被将死

    int isBlackLost()

    {

        for (int i = 1; i <= 10; i++) for(int j = 1; j <= 9; j++)

            {

                switch (board[i][j])

                {

                case 'G':

                case 'R':

                    if (Cnt(i,j)==0)

                    {

                        return 1;

                    }

                    break;

                case 'H':

                    if (H(i,j))

                    {

                        return 1;

                    }

                    break;

                case 'C':

                    if (Cnt(i,j)==1)

                    {

                        return 1;

                    }

                }

            }

        return 0;

    }

 

    void out()      // 用于输出棋盘进行调试的函数

    {

        printf("**123456789\n");

        for (int i = 1; i <= 10; i++)

        {

            printf("%2d", i);

            for (int j = 1; j <= 9; j++)

            {

               putchar(board[i][j]?board[i][j]:' ');

            }

            putchar('\n');

        }

        putchar('\n');

    }

};

 

intisCheckmate(Xiangqi& A)

{

    int dx[4] = {-1,1,0,0}, dy[4] = {0,0,1,-1};

    for (int i = 0; i < 4; i++)

    {

        Xiangqi B(A);  // 用复制构造函数拷贝副本

        if (B.go(dx[i],dy[i]) &&!B.isBlackLost()) return 0;

    }

    return 1;

}

 

int main()

{

    int n, bx, by;

    while (scanf("%d%d%d", &n,&bx, &by), n)

    {

        Xiangqi A(n, bx, by);

        printf("%s\n",isCheckmate(A)?"YES":"NO");

    }

    return 0;

}

0 0
原创粉丝点击