您的位置:首页 > 其它

UVa 10196 将军

2017-05-03 17:09 344 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: