UVA1589
曾经想过两种不同的思路:
思路1:对红方的每一个棋子,把他们的必杀区域(能吃掉对方的棋子的区域)都用*代替,之后对黑方的帅,试着移动四个方位,如果四个方位都会碰到'*',那么红方将死对方。就是之前要检查一下红方是否会被黑方飞帅直线击杀。
思路2:与思路1相反,先移动黑方的帅,对每一个可能移动的方位,遍历所有红方的棋子,看红方棋子能否击杀黑方。如果对四个可能的移动方位,黑方都必死,那么红方将死黑方,否则,将不死。
思路1有个问题,那就是如果黑方吃掉红方一个棋子,可能会失效。
我第一次用思路1做,测了很多测试数据,发现思路1的问题的解决实际上就是要用思路2.
代码如下图:
其中Red是红方棋子的数组,print函数是为了能可视化打印出棋盘。
采用思路2,之后,发现几个陷阱:
1.continue之前记得还原棋盘
2.continue和break有时容易混淆
3.把判断边界单独弄成一个函数
4.对不同的单位,可以用dx【n】,dy【n】抽象表示,接下来便是能用一个循环表示,简化代码
5.先编写主程序框架,遇到难写的先用一个函数代替。先保证主要精力再框架的正确性,编写函数时也是采用这样的思路
#include
#include
#include
#include
#include
#include
int field[12][12];
int N,b_x,b_y;
using namespace std;
class Chess{
public:
char ch;
int x;
int y;
};
bool isInPalace(int x,int y)
{
return 1<=x && x<=3 && 4<=y && y<=6;
}
bool isInBorder(int x,int y)
{
if(1<=x && x<=10 && 1<=y && y<=9)
return true;
else
return false;
}
bool catched_by(const Chess& chess,int bx,int by)
{
//nx,ny 是对方棋子的postion
/* 如果自己已经被吃掉,那就肯定不能吃掉对方 */
if(chess.x==bx && chess.y==by)
{
return false;
}
//判断chess的种类
//如果是车或者帅
if(chess.ch=='R'|| chess.ch=='G')
{
//方位控制
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
for(int i=0;i<4;i++)
{
int nx=chess.x;
int ny=chess.y;
//对该方位不断直线搜索
while(true)
{
nx+=dx[i];
ny+=dy[i];
// 如果越界或者遇到红方棋子
if(!isInBorder(nx,ny)||isupper(field[nx][ny]) )
break;
else if(field[nx][ny]=='b')//吃掉对方
return true;
}
}
}
else if(chess.ch=='H')
{
//马的8种可能方位
int dx[8]={2,1,-2,-1, 2,1,-2,-1};
int dy[8]={1,2, 1, 2,-1,-2,-1,-2};
//对每一种方位
for(int i=0;i<8;i++)
{
int nx=chess.x;
int ny=chess.y;
//如果没有磐马角
if(isInBorder(nx+(dx[i]/2),ny+(dy[i]/2)) && field[nx+(dx[i]/2)][ny+(dy[i]/2)]==0)
{
nx+=dx[i];ny+=dy[i];
//如果吃掉黑方的帅
if(isInBorder(nx,ny)&& field[nx][ny]=='b')
return true;
}
}
}
else if(chess.ch=='C')
{
//炮的四种打击方向
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
//针对每一个方向
for(int i=0;i<4;i++)
{
int nx=chess.x;
int ny=chess.y;
//找到第一个炮台
enum found{isOut=1,isBlack,isFriend};
found paoTai=isOut;
while(true)
{
nx+=dx[i];
ny+=dy[i];
//如果找到炮台,就跳出循环
if(!isInBorder(nx,ny))
{
paoTai=isOut;
break;
}
else
{
if(field[nx][ny]=='b')
{
paoTai=isBlack;
break;
}
else if(isupper(field[nx][ny]))
{
paoTai=isFriend;
break;
}
}
}
//如果paotai== isFriend 表示找到炮台
if(paoTai!=isFriend)
continue;
//找黑方
while(true)
{
nx+=dx[i];
ny+=dy[i];
if(!isInBorder(nx,ny))
{
break;
}
else
{
if(field[nx][ny]=='b')
{
return true;
}
else if(isupper(field[nx][ny]))
{
break;
}
}
}
}
}
return false;
}
bool catched_by(const vector& Red,int nx,int ny)
{
for(int i=0;i>N>>b_x>>b_y&&N)
{
//初始化field数组
memset(field,0,sizeof(field));
vector Red(N);
for(int i=0;i>Red[i].ch>>Red[i].x>>Red[i].y;
field[Red[i].x][Red[i].y]=Red[i].ch;
}
//draw plot
field[b_x][b_y]='b';
//test
//print();
if(black_win())
{
printf("NO\n");
continue;
}
field[b_x][b_y]=0;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
bool Black_Servive=false;
for(int i=0;i<4;i++)
{
//更新画图
int nx=b_x+dx[i];
int ny=b_y+dy[i];
int temp=field[nx][ny];
field[nx][ny]='b';
// print();
//test
if(!isInPalace(nx,ny))//黑方帅不再皇宫中
{
//continue 之前要还原图
field[nx][ny]=temp;
continue;
}
else if(!catched_by(Red,nx,ny))
{
Black_Servive=true;
break;
}
//还原画图
field[nx][ny]=temp;
}
if(Black_Servive)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}