我第一次写的时候只写了 80 分钟吧,发现读入完全不一样就扔了,第二次重构甚至只用 40 分钟重构,剩下时间都是调的,还有 5 分钟在调调试函数。
写大模拟就要写这种题意清清楚楚的大模拟。有益于身体健康,锻炼码力,理顺思维。实际上这道题不通过加注释就能完成。
捋一捋流程:
- 先手红棋;
- 如果游戏结束,输出
Invalid command
; - 否则根据输入选一个格子 ((s,t)),将上面的棋子移到 ((x,y)),以以下流程判断是否可行:
- 如果 ((s,t)) 没有当前执棋家的棋,不可行;
- 如果 ((x,y)) 有当前执棋家的棋,不可行;
- 如果 ((x,y)) 这个位置不合法,不可行;
- 否则判断当前棋子能否通过合法方案从 ((s,t)) 移至 ((x,y))。
- 如果不可行,输出
Invalid command
; - 否则,将棋子从 ((s,t)) 移至 ((x,y));
- 如果 ((x,y)) 有对家的棋子:
- 如果 ((x,y)) 是对方的王,打上游戏结束标记;
- 吃掉 ((x,y)) 上面的,对家的棋子。
- 判断当前局面是否是将军;
- 判断游戏已经结束。
流程捋顺了,具体讲解。
首先讲一下大题的框架:
const char chessName[10][15]={"","captain","guard","elephant","horse","car","duck","soldier"};//存储各个棋子编号对应的棋子名称
const char colorOutput[2][10]={"red","blue"};//执棋家颜色
const char checkOutput[2][10]={"no","yes"};//真还是假
const int sx[3]={0,1,-1},sy[3]={0,1,-1};//如象,马,鸭移动方法描述,这里是蠢了开了两个,实际上两个一样显然可以共用
class Duckchess{
bool Occupy(int x,int y,int c);//执棋家 c 有没有棋子在 (x,y) 上 E
bool Occupy(int x,int y);//有没有棋子在 (x,y) 上 E
bool Outside(int x,int y);//(x,y) 是否在棋盘内 E
bool captainMoveCor(int s,int t,int x,int y);//王从 (s,t) 移动至 (x,y) 是否合法,下同
bool guardMoveCor(int s,int t,int x,int y);
bool elephantMoveCor(int s,int t,int x,int y);
bool duckMoveCor(int s,int t,int x,int y);
bool soldierMoveCor(int s,int t,int x,int y);
bool moveCorrect(int op,int s,int t,int x,int y);//对于棋子 op,从 (s,t) 移动至 (x,y) 是否合法
bool attack(int x,int y,int c);//有没有 c 家的棋子能攻击到 (x,y)
public:
int board[12][12][2];//棋盘
bool gameOver;//游戏结束标记
Duckchess(){}//构造函数,用于构造棋盘
~Duckchess(){}//析构函数,可以不要,为了封装的完整性留下来了
bool isMoveSuc(int s,int t,int x,int y,int c);//执棋家为 c 时,棋子从 (s,t) 移动到 (x,y) 是否合法
void moveChess(int s,int t,int x,int y,int c);//将 c 家的棋子从 (s,t) 移动到 (x,y)
void chessDelete(int s,int t,int c);//删除 c 家在 (s,t) 的棋子
bool isGeneral();//判断将军局面
}game;
注:实际上为了将 class
封装得更好看,可以使用 enum
,指针,或者是更多的函数去实现。但是我拒绝。
没问题?继续看主函数。
int main(){
int control=0,T=read();//先手红棋
while(T-->0)
{
int s=read(),t=read(),x=read(),y=read();
if(game.isMoveSuc(s,t,x,y,control) && !game.gameOver)//如果移动合法且游戏未结束
{
int k=game.board[s][t][control];//得到当前棋子
printf("%s %s;",colorOutput[control],chessName[k]);//输出
game.moveChess(s,t,x,y,control);//移动棋子
game.chessDelete(x,y,control);//删除对方棋子
printf("%s;%s
",checkOutput[game.isGeneral()],checkOutput[game.gameOver]);//输出是否将军,是否结束
control^=1;//两家交换执棋
}
else puts("Invalid command");//无效操作
}
return 0;
}
接下来的工作就是把剩下的函数全部填下来。啥?这还要我讲?
实际的实现中并没有用到注释。写每一个函数使得你写代码的过程相互独立,可以让你的思维很清晰,实现模块化编程。
#include<bits/stdc++.h>
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x*f;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const char chessName[10][15]={"","captain","guard","elephant","horse","car","duck","soldier"};
const char colorOutput[2][10]={"red","blue"};
const char checkOutput[2][10]={"no","yes"};
const int sx[3]={0,1,-1},sy[3]={0,1,-1};
class Duckchess{
bool Occupy(int x,int y,int c){return bool(board[x][y][c]);}
bool Occupy(int x,int y){return bool(board[x][y][0] || board[x][y][1]);}
bool Outside(int x,int y){return !(x>=0 && y>=0 && x<=9 && y<=8);}
bool captainMoveCor(int s,int t,int x,int y){return abs(s-x)+abs(t-y)==1;}
bool guardMoveCor(int s,int t,int x,int y){return abs(s-x)==1 && abs(t-y)==1;}
bool elephantMoveCor(int s,int t,int x,int y)
{
for(int dx=1;dx<=2;++dx)
{
for(int dy=1;dy<=2;++dy)
{
int p=s+sx[dx]*2,q=t+sy[dy]*2;
if(Outside(p,q)) continue;
if(p==x && q==y)
{
if(!Occupy(s+sx[dx],t+sy[dy])) return true;
return false;
}
}
}
return false;
}
bool horseMoveCor(int s,int t,int x,int y)
{
for(int dx=1;dx<=2;++dx)
{
for(int dy=1;dy<=2;++dy)
{
int p=s+sx[dx]*2,q=t+sy[dy];
if(Outside(p,q)) continue;
if(p==x && q==y)
{
if(!Occupy(s+sx[dx],t)) return true;
return false;
}
}
}
for(int dx=1;dx<=2;++dx)
{
for(int dy=1;dy<=2;++dy)
{
int p=s+sx[dx],q=t+sy[dy]*2;
if(Outside(p,q)) continue;
if(p==x && q==y)
{
if(!Occupy(s,t+sy[dy])) return true;
return false;
}
}
}
return false;
}
bool carMoveCor(int s,int t,int x,int y)
{
if(s!=x && t!=y) return false;
if(s==x)
{
if(t>y)
{
for(int i=t-1;i>y;--i) if(Occupy(s,i)) return false;
}
else
{
for(int i=t+1;i<y;++i) if(Occupy(s,i)) return false;
}
return true;
}
else
{
if(s>x)
{
for(int i=s-1;i>x;--i) if(Occupy(i,t)) return false;
}
else
{
for(int i=s+1;i<x;++i) if(Occupy(i,t)) return false;
}
return true;
}
}
bool duckMoveCor(int s,int t,int x,int y)
{
for(int dx=1;dx<=2;++dx)
{
for(int dy=1;dy<=2;++dy)
{
int p=s+sx[dx]*3,q=t+sy[dy]*2;
if(Outside(p,q)) continue;
if(p==x && q==y)
{
if(Occupy(s+2*sx[dx],t+sy[dy]) || Occupy(s+sx[dx],t)) return false;
return true;
}
}
}
for(int dx=1;dx<=2;++dx)
{
for(int dy=1;dy<=2;++dy)
{
int p=s+sx[dx]*2,q=t+sy[dy]*3;
if(Outside(p,q)) continue;
if(p==x && q==y)
{
if(Occupy(s+sx[dx],t+2*sy[dy]) || Occupy(s,t+sy[dy])) return false;
return true;
}
}
}
return false;
}
bool soldierMoveCor(int s,int t,int x,int y){return abs(s-x)<=1 && abs(t-y)<=1;}
bool moveCorrect(int op,int s,int t,int x,int y)
{
if(op==1) return captainMoveCor(s,t,x,y);
else if(op==2) return guardMoveCor(s,t,x,y);
else if(op==3) return elephantMoveCor(s,t,x,y);
else if(op==4) return horseMoveCor(s,t,x,y);
else if(op==5) return carMoveCor(s,t,x,y);
else if(op==6) return duckMoveCor(s,t,x,y);
else return soldierMoveCor(s,t,x,y);
}
bool attack(int x,int y,int c)
{
for(int i=0;i<=9;++i) for(int j=0;j<=8;++j) if(board[i][j][c] && moveCorrect(board[i][j][c],i,j,x,y)) return true;
return false;
}
public:
int board[12][12][2];
bool gameOver;
Duckchess()
{
gameOver=false;
board[0][4][0]=board[9][4][1]=1;
board[0][3][0]=board[9][3][1]=board[0][5][0]=board[9][5][1]=2;
board[0][2][0]=board[9][2][1]=board[0][6][0]=board[9][6][1]=3;
board[0][1][0]=board[9][1][1]=board[0][7][0]=board[9][7][1]=4;
board[0][0][0]=board[9][0][1]=board[0][8][0]=board[9][8][1]=5;
board[2][0][0]=board[7][0][1]=board[2][8][0]=board[7][8][1]=6;
board[3][0][0]=board[3][2][0]=board[3][4][0]=board[3][6][0]=board[3][8][0]=7;
board[6][0][1]=board[6][2][1]=board[6][4][1]=board[6][6][1]=board[6][8][1]=7;
}
~Duckchess(){memset(board,0,sizeof board);}
bool isMoveSuc(int s,int t,int x,int y,int c)
{
if(!Occupy(s,t,c)) return false;
if(Occupy(x,y,c)) return false;
if(Outside(x,y)) return false;
int chessid=board[s][t][c];
return moveCorrect(chessid,s,t,x,y);
}
void moveChess(int s,int t,int x,int y,int c)
{
board[x][y][c]=board[s][t][c];
board[s][t][c]=0;
}
void chessDelete(int s,int t,int c)
{
if(board[s][t][c^1])
{
printf("%s %s",colorOutput[c^1],chessName[board[s][t][c^1]]);
if(board[s][t][c^1]==1) gameOver=true;
board[s][t][c^1]=0;
}
else printf("NA");
putchar(';');
}
bool isGeneral()
{
if(gameOver) return false;
for(int i=0;i<=9;++i)
{
for(int j=0;j<=8;++j)
{
if(board[i][j][0]==1 && attack(i,j,1)) return true;
if(board[i][j][1]==1 && attack(i,j,0)) return true;
}
}
return false;
}
}game;
int main(){
int control=0,T=read();
while(T-->0)
{
int s=read(),t=read(),x=read(),y=read();
if(game.isMoveSuc(s,t,x,y,control) && !game.gameOver)
{
int k=game.board[s][t][control];
printf("%s %s;",colorOutput[control],chessName[k]);
game.moveChess(s,t,x,y,control);
game.chessDelete(x,y,control);
printf("%s;%s
",checkOutput[game.isGeneral()],checkOutput[game.gameOver]);
control^=1;
}
else puts("Invalid command");
}
return 0;
}