「THUPC2019」鸭棋

我第一次写的时候只写了 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\n",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\n",checkOutput[game.isGeneral()],checkOutput[game.gameOver]);
			control^=1;
		}
		else	puts("Invalid command");
	}
	return 0;
}
posted @ 2020-10-10 21:29  SyadouHayami  阅读(211)  评论(0编辑  收藏  举报

My Castle Town.