P5380 [THUPC2019]鸭棋
题面
查看题面
题目背景
鸭棋是一种风靡鸭子界的棋类游戏。事实上,它与中国象棋有一些相似之处,但规则不尽相同。在这里,我们将为你介绍鸭棋的规则。
鸭棋在一个 \(10\times 9\)(\(10\) 行 \(9\) 列)的网格棋盘上进行,网格上的每个格点都可以有棋子停留。对弈双方一方执红(red)棋、另一方执蓝(blue)棋,双方轮流执行操作,轮到一位玩家操作时,他必须选择一枚自己的棋子,并按照规则进行一步移动。
鸭棋发明者鸭子德规定一局鸭棋由红方执先手,并设计了初始棋盘布局如下

棋子类型与走子规则
棋子分为 \(7\) 类,下面介绍了它们的名字以及它们的移动规则。介绍移动规则时,我们默认棋子所处位置为 \(\left( x,y\right)\)(表示第 \(x\) 行的第 \(y\) 列,下同),并列出它可以到达的位置:
- 王(captain):可达的位置共 \(4\) 个,包括 \(\left(x\pm 1,y\right)\) 及 \(\left(x,y\pm 1\right)\)。
- 士(guard):可达的位置共 \(4\) 个,包括 \(\left(x\pm 1,y\pm 1\right)\) 及 \(\left(x\pm 1,y\mp 1\right)\)。
- 象(elephant):可达的位置至多 \(4\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:- 如果位置 \(\left(x+s_x\times 1 ,y+ s_y\times 1\right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 2\right)\) 为一个可达的位置。
 
- 马(horse):可达的位置至多 \(8\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:- 如果位置 \(\left(x+s_x\times 1 ,y\right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 1\right)\) 为一个可达的位置。
- 如果位置 \(\left(x ,y+ s_y \times 1 \right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 1,y+s_y \times 2\right)\) 为一个可达的位置。
 
- 车(car):可在不跨越其他棋子的前提下,到达同行或同列的所有其他位置。
- 鸭(duck):可达的位置至多 \(8\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:- 如果位置 \(\left(x+s_x\times 2 ,y+s_y \times 1\right),\left(x+s_x\times 1 ,y\right)\) 上均无任意一方的棋子停留,则 \(\left( x+s_x \times 3,y+s_y \times 2\right)\) 为一个可达的位置。
- 如果位置 \(\left(x+s_x \times 1 ,y+ s_y \times 2 \right),\left(x ,y+ s_y \times 1 \right)\) 上均无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 3\right)\) 为一个可达的位置。
 
- 兵(soldier):可达的位置共 \(8\) 个,包括 \(\left(x\pm 1,y\right)\) 及 \(\left(x,y\pm 1\right)\) 及 \(\left(x\pm 1,y\pm 1\right)\) 及 \(\left(x\pm 1,y\mp 1\right)\)。
除上面描述的规则之外,棋子移动还有如下额外规则:
- 不能将棋子移动到棋盘外的某个位置。
- 玩家不能将棋子移动到已经停留了己方棋子的位置。
- 如果玩家将棋子移动到了一个已经停留了对方棋子的位置,那么原本停留在该位置上的这个对方棋子将被移出游戏。
胜利条件与将军局面
玩家在这个游戏中的目标是将对方的王移出游戏。一旦一方的王被移出游戏,则另一方立即宣告胜利。
对于一个棋盘的状态,如果存在一方有一步合法的操作能够将另一方的王移出游戏,则我们说当前局面是一个将军的局面。需要友情提示的是,根据定义,将军局面的形成包括(但不限于)如下这些可能:
- 一方将一枚棋子移动到可以攻击对方王的位置 
- 在己方王受到威胁时不采取措施躲避 
- 主动将王移动至会受到攻击的位置 
除此之外,需要特别说明的是,游戏结束后,由于双方不可再操作,因此不可能出现将军局面,即便此时另一方王处于被「攻击」的位置。
题目描述
今年的 IDCC(International Duck Chess Competition,国际鸭棋大赛)正在如火如荼地进行着。你观摩了一场精彩绝伦的比赛,但你对对弈过程的记忆已经模糊不清了,只有系统留下的他们的操作序列,序列中的每个操作为当前操作者试图移动某个位置的棋子至另一个位置。你希望用这个序列,来复现出整局棋局的对弈过程。即,对于每步操作,你需要首先判其是否合法,若合法,则进一步求出:
- 这步操作移动了哪个棋子。
- 这步操作后,是否存在棋子被移出游戏,如有则还需求出被移出游戏的棋子。
- 这步操作后,是否形成将军局面。
- 这步操作后,游戏是否结束。
可能包含的不合法情况如下:
- 此步移动的初始位置无己方棋子停留。
- 此步移动的初始位置有己方棋子停留,但移动不符合规则。
- 游戏已经结束。
序列中的不合法操作是需要被忽略的。比如,如果轮到红方移动,此时序列中的当前操作恰好是不合法的,则这个操作将被忽略,序列中的下一步操作将成为红方这步的操作(如仍不合法则继续忽略,直至出现合法的操作)。
输入格式
第一行一个非负整数 \(Q\),表示操作序列的长度。接下来依次描述每个操作。
接下来 \(Q\) 行,每行 \(4\) 个整数 \(x_s, y_s, x_t, y_t\)(\(0\leq x_s,x_t < 10\),\(0\leq y_s,y_t < 9\)),描述一个欲将 \(\left(x_s,y_s\right)\) 处棋子移动到 \(\left(x_t,y_t\right)\) 的操作。在这里,我们规定左下角(即红方车摆放的位置,图见「题目背景」)为 \(\left(0,0\right)\)。
保证 \(Q\leq 1000\)。
输出格式
输出 \(Q\) 行,对于每个操作依次输出复现结果。每行输出一个操作的结果:
- 如果该操作为不合法操作,则请输出 Invalid command。
- 如果为合法操作,则依次回答「题目描述」中的问题 \(1\sim 4\):
- 被移动的棋子用 [颜色] [类型](注意中间包含空格)来描述,请使用它们的英文名称(见「题目背景」)。如,红象为red elephant,蓝王为blue captain。
- 被移出游戏的棋子的描述方式与上面类似。特别地,如果无棋子被移出游戏,则该问题的答案为 NA。
- 用 yes、no分别表示形成、不形成将军局面。
- 用 yes、no分别表示游戏结束、游戏不结束。
- 用 ;(分号)将所有问题的答案隔开。
- 比如,四个问题的答案分别为:被移动的棋子是蓝车,无棋子被移出游戏,形成将军局面,游戏未结束。则该行应输出 blue car;NA;yes;no。
 
- 被移动的棋子用 
版权信息
来自 THUPC(THU Programming Contest,清华大学程序设计竞赛)2019。
其他资源可在 Github 查看。
思路
大模拟。
棋子棋盘表示
棋子我们使用一个数字来表示:
| 棋子名 | 数字 | 棋子名 | 数字 | 
|---|---|---|---|
| 红王 | 11 | 蓝王 | 21 | 
| 红士 | 12 | 蓝士 | 22 | 
| 红象 | 13 | 蓝象 | 23 | 
| 红马 | 14 | 蓝马 | 24 | 
| 红车 | 15 | 蓝车 | 25 | 
| 红鸭 | 16 | 蓝鸭 | 26 | 
| 红兵 | 17 | 蓝兵 | 27 | 
| (空) | 0 | 
这样子表示的优点如下:
- 将十位数取出来就可以知道这个棋子是哪一方的。
- 将个位数取出来就可以知道这个棋子是什么类型的(与哪一方的无关)。
然后需要写一个数字转英文棋子名的函数:
string get_name(int chs){
	// 获得棋子英文名
	string player,type;
	if(chs/10==1) player="red";
	if(chs/10==2) player="blue";
	if(chs%10 == 1) type="captain";
	if(chs%10 == 2) type="guard";
	if(chs%10 == 3) type="elephant";
	if(chs%10 == 4) type="horse";
	if(chs%10 == 5) type="car";
	if(chs%10 == 6) type="duck";
	if(chs%10 == 7) type="soldier";
	return player + " " + type;
}
棋盘简单的使用一个二维数组。不过要注意红方在上,黑方在下。
初始局面代码:
int board[10][9] = {
	{15,14,13,12,11,12,13,14,15},
	{00,00,00,00,00,00,00,00,00},
	{16,00,00,00,00,00,00,00,16},
	{17,00,17,00,17,00,17,00,17},
	{00,00,00,00,00,00,00,00,00},
	{00,00,00,00,00,00,00,00,00},
	{27,00,27,00,27,00,27,00,27},
	{26,00,00,00,00,00,00,00,26},
	{00,00,00,00,00,00,00,00,00},
	{25,24,23,22,21,22,23,24,25}
};// 棋盘
判断棋步(一)
现在我们来实现判断试图将一个坐标的棋子移到另一个坐标的行为是否合法。
首先我们先判断一个棋子是否可以落到棋盘上的某一个位置。这一点在鸭棋中可能用处不大,但在在中国象棋中尤为重要(象有不能过河、将士有不能出九宫的限制)。大致需要判断:
- 是否出界
- 落子的位置是否有己方的棋子。
代码:
int is_landing_legal(int chs,int dx,int dy){
	// 棋子 chs 是否可以落到 (dx,dy) 返回 0:不可以 1:可以 2:可以且吃了子
	if(dx<0||dx>=10||dy<0||dy>=9) return 0;// 出界
	else if(board[dx][dy]==0) return 1;// 没有棋子自然可以放上去
	else if(board[dx][dy]/10 != chs/10) return 2;// 有棋子但不同方可以吃
	else return 0;// 有己方棋子不能走
}
然后就是主判断了。无论怎么样,我们都可以写出一个整体框架:
int is_moving_legal(int chs,int sx,int sy,int dx,int dy){
	// 棋子 chs 从 (sx,sy) 走到 (dx,dy) 是否合法 0:不可以 1:可以 2:可以且吃了子
	if(sx==dx && sy==dy) return 0;
	if(chs==0) return 0;
	int landing = is_landing_legal(chs,dx,dy);
	if(!landing) return 0;
    这里写生成棋子走法,看是不是可以找到走法
    return 0;
}
判断棋步(二)
上一节我们实现了判断棋步是否合法的框架,这一节我们写具体判断逻辑。
王
- 王(
captain):可达的位置共 \(4\) 个,包括 \(\left(x\pm 1,y\right)\) 及 \(\left(x,y\pm 1\right)\)。
由于王的移动比较简单,我们可以写一个偏移值数组 captain_delta:
typedef vector<pair<int,int> > moves;
moves captain_delta = {{1,0},{0,1},{-1,0},{0,-1}};// 王的偏移值
然后遍历所有可能的偏移值,判断是否走的是这一步即可:
if(chs%10 == 1){// 王
	for(pair<int,int> delta : captain_delta){
		if(sx+delta.first==dx && sy+delta.second==dy){
			return landing;
		}
	}
	return 0;
}
士
- 士(
guard):可达的位置共 \(4\) 个,包括 \(\left(x\pm 1,y\pm 1\right)\) 及 \(\left(x\pm 1,y\mp 1\right)\)。
由于士的移动也很简单,我们可以写一个偏移值数组 guard_delta:
moves guard_delta = {{1,1},{1,-1},{-1,1},{-1,-1}};// 士的偏移值
然后遍历所有可能的偏移值,判断是否走的是这一步即可:
if(chs%10 == 2){// 士
	for(pair<int,int> delta : guard_delta){
		if(sx+delta.first==dx && sy+delta.second==dy){
			return landing;
		}
	}
	return 0;
}
象
- 象(
elephant):可达的位置至多 \(4\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:
- 如果位置 \(\left(x+s_x\times 1 ,y+ s_y\times 1\right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 2\right)\) 为一个可达的位置。
有人象也写了偏移值,不过这样又要写象眼的偏移值,非常麻烦,而且容易错。我们可以直接用题目给我们的定义,枚举 \(s_x,s_y\) 判断即可:
if(chs%10 == 3){// 象
	for(int _sx : {1,-1}){
		for(int _sy : {1,-1}){
			if(board[sx+_sx][sy+_sy]!=0) continue;
			if((sx+(_sx<<1))==dx && (sy+(_sy<<1))==dy){
				return landing;
			}
		}
	}
	return 0;
}
马
- 马(
horse):可达的位置至多 \(8\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:
- 如果位置 \(\left(x+s_x\times 1 ,y\right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 1\right)\) 为一个可达的位置。
- 如果位置 \(\left(x ,y+ s_y \times 1 \right)\) 上无任意一方的棋子停留,则 \(\left( x+s_x \times 1,y+s_y \times 2\right)\) 为一个可达的位置。
和象一样,我们也可以直接枚举 \(s_x,s_y\)。然后判断即可。记得判断蹩马腿的情况。
if(chs%10 == 4){// 马
	for(int _sx : {1,-1}){
		for(int _sy : {1,-1}){
			if(board[sx+_sx][sy]==0){
				if((sx+(_sx<<1))==dx && (sy+_sy)==dy){
					return landing;
				}
			}
			if(board[sx][sy+_sy]==0){
				if((sx+_sx)==dx && (sy+(_sy<<1))==dy){
					return landing;
				}
			}
		}
	}
	return 0;
}
车
- 车(
car):可在不跨越其他棋子的前提下,到达同行或同列的所有其他位置。
先判断是否在同一列或同一行,如果同一行,就固定行,看看这之间(记得不包括两边)有没有棋子。同一列同理。
if(chs%10 == 5){// 车
	bool flag=0;
	if(sx==dx){
		for(int i=min(sy,dy)+1;i<max(sy,dy);i++){
			if(board[sx][i]!=0){
				flag=1;
				break;
			}
		}
		if(!flag) return landing;
		else return 0;
	}
	else if(sy==dy){
		for(int i=min(sx,dx)+1;i<max(sx,dx);i++){
			if(board[i][sy]!=0) {
				flag=1;
				break;
			}
		}
		if(!flag) return landing;
		else return 0;
	}
	else return 0;
}
鸭
- 鸭(
duck):可达的位置至多 \(8\) 个,对于任意 \(s_x,s_y\in \left\{ 1,-1\right\}\),分别有:
- 如果位置 \(\left(x+s_x\times 2 ,y+s_y \times 1\right),\left(x+s_x\times 1 ,y\right)\) 上均无任意一方的棋子停留,则 \(\left( x+s_x \times 3,y+s_y \times 2\right)\) 为一个可达的位置。
- 如果位置 \(\left(x+s_x \times 1 ,y+ s_y \times 2 \right),\left(x ,y+ s_y \times 1 \right)\) 上均无任意一方的棋子停留,则 \(\left( x+s_x \times 2,y+s_y \times 3\right)\) 为一个可达的位置。
使用象和马的方法即可,也是枚举 \(s_x,s_y\),然后记得判断鸭爪?
if(chs%10 == 6){// 鸭
	for(int _sx : {1,-1}){
		for(int _sy : {1,-1}){
			if(board[sx+_sx*2][sy+_sy*1]==0 && board[sx+_sx][sy] == 0){
				if((sx+(_sx*3))==dx && (sy+_sy*2)==dy){
					return landing;
				}
			}
			if(board[sx][sy+_sy]==0 && board[sx+_sx*1][sy+_sy*2] == 0){
				if((sx+_sx*2)==dx && (sy+(_sy*3))==dy){
					return landing;
				}
			}
		}
	}
	return 0;
}
兵
- 兵(
soldier):可达的位置共 \(8\) 个,包括 \(\left(x\pm 1,y\right)\) 及 \(\left(x,y\pm 1\right)\) 及 \(\left(x\pm 1,y\pm 1\right)\) 及 \(\left(x\pm 1,y\mp 1\right)\)。
兵的走法比较简单,使用偏移值法。
moves soldier_delta = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}};// 兵的偏移值
if(chs%10 == 7){// 兵
	for(pair<int,int> delta : soldier_delta){
		if(sx+delta.first==dx && sy+delta.second==dy){
			return landing;
		}
	}
	return 0;
}
判断将军
其实有更高效的方法,就是把王当成攻击子力,看能不能攻击到其他子。但这样判断 象眼/马腿/鸭爪 比较麻烦。
我们采用暴力的方法,先找到王的位置,然后暴力枚举所有棋子,看看走到王的位置是否合法。
bool is_checking(int player){
	// 是否将军 player=1 红方被将 player=2 蓝方被将
	int cx=-1,cy=-1;
	for(int i=0;i<10&&(cx==-1);i++){
		for(int j=0;j<9&&(cy==-1);j++){
			if(board[i][j]==(player*10+1)){
				cx=i;cy=j;
			}
		}
	}
	if(cx==-1&&cy==-1) return false;
	for(int i=0;i<10;i++){
		for(int j=0;j<9;j++){
			if(i==cx&&j==cy) continue;
			if(board[i][j]==0) continue;
			if(is_moving_legal(board[i][j],i,j,cx,cy)){
				return true;
			}
		}
	}
	return false;
}
判断结束
如果没有王,那么就结束了。可以暴力扫每一个位置看看是不是王,如果都不是就结束了。
bool is_finished(int player){
	// 是否结束 player=1 蓝方胜利 player=2 红方胜利
	int cx=-1,cy=-1;
	for(int i=0;i<10&&(cx==-1);i++){
		for(int j=0;j<9&&(cy==-1);j++){
			if(board[i][j]==(player*10+1)){
				cx=i;cy=j;
			}
		}
	}
	if(cx==-1&&cy==-1) return true;
	else return false;
}
主程序
然后就是主程序了!其实主程序十分简单,只是要注意:
- 结束后不能走棋。
- 不合法的棋要忽略。
- 记得一方下完后一定是另一方下,否则不合法。
代码:
bool finished = 0;
int nowmove = 1;
signed main(){
	int q;
	cin>>q;
	while(q--){
		int sx,sy,dx,dy;
		cin>>sx>>sy>>dx>>dy;
		int moving = is_moving_legal(board[sx][sy],sx,sy,dx,dy);
		if(!moving||finished||board[sx][sy]/10 != nowmove){cout<<"Invalid command\n";continue;}
		string moved=get_name(board[sx][sy]),ate="NA",checking="no",finishing="no";
		if(moving == 2) ate=get_name(board[dx][dy]);
		board[dx][dy]=board[sx][sy];board[sx][sy]=0;
		if(is_checking(1) || is_checking(2)) checking="yes";
		if(is_finished(1) || is_finished(2)){finishing="yes";finished=1;}
		cout<<moved<<';'<<ate<<';'<<checking<<';'<<finishing<<'\n';
		if(nowmove == 1) nowmove = 2;
		else nowmove = 1;
	}
	return 0;
}
代码
显示代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
// 十位 0:空 1:红 2:蓝
// 个位 王:1 士:2 象:3 马:4 车:5 鸭:6 兵:7
int board[10][9] = {
	{15,14,13,12,11,12,13,14,15},
	{00,00,00,00,00,00,00,00,00},
	{16,00,00,00,00,00,00,00,16},
	{17,00,17,00,17,00,17,00,17},
	{00,00,00,00,00,00,00,00,00},
	{00,00,00,00,00,00,00,00,00},
	{27,00,27,00,27,00,27,00,27},
	{26,00,00,00,00,00,00,00,26},
	{00,00,00,00,00,00,00,00,00},
	{25,24,23,22,21,22,23,24,25}
};// 棋盘
typedef vector<pair<int,int> > moves;
moves captain_delta = {{1,0},{0,1},{-1,0},{0,-1}};// 王的偏移值
moves guard_delta = {{1,1},{1,-1},{-1,1},{-1,-1}};// 士的偏移值
moves soldier_delta = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}};// 兵的偏移值
int is_landing_legal(int chs,int dx,int dy){
	// 棋子是否可以落到 (dx,dy) 返回 0:不可以 1:可以 2:可以且吃了子
	if(dx<0||dx>=10||dy<0||dy>=9) return 0;// 出界
	else if(board[dx][dy]==0) return 1;// 没有棋子自然可以放上去
	else if(board[dx][dy]/10 != chs/10) return 2;// 有棋子但不同方可以吃
	else return 0;// 有己方棋子不能走
}
int is_moving_legal(int chs,int sx,int sy,int dx,int dy){
	// 棋子 chs 从 (sx,sy) 走到 (dx,dy) 是否合法 0:不可以 1:可以 2:可以且吃了子
	if(sx==dx && sy==dy) return 0;
	if(chs==0) return 0;
	int landing = is_landing_legal(chs,dx,dy);
	if(!landing) return 0;
	if(chs%10 == 1){// 王
		for(pair<int,int> delta : captain_delta){
			if(sx+delta.first==dx && sy+delta.second==dy){
				return landing;
			}
		}
		return 0;
	}
	if(chs%10 == 2){// 士
		for(pair<int,int> delta : guard_delta){
			if(sx+delta.first==dx && sy+delta.second==dy){
				return landing;
			}
		}
		return 0;
	}
	if(chs%10 == 3){// 象
		for(int _sx : {1,-1}){
			for(int _sy : {1,-1}){
				if(board[sx+_sx][sy+_sy]!=0) continue;
				if((sx+(_sx<<1))==dx && (sy+(_sy<<1))==dy){
					return landing;
				}
			}
		}
		return 0;
	}
	if(chs%10 == 4){// 马
		for(int _sx : {1,-1}){
			for(int _sy : {1,-1}){
				if(board[sx+_sx][sy]==0){
					if((sx+(_sx<<1))==dx && (sy+_sy)==dy){
						return landing;
					}
				}
				if(board[sx][sy+_sy]==0){
					if((sx+_sx)==dx && (sy+(_sy<<1))==dy){
						return landing;
					}
				}
			}
		}
		return 0;
	}
	if(chs%10 == 5){// 车
		bool flag=0;
		if(sx==dx){
			for(int i=min(sy,dy)+1;i<max(sy,dy);i++){
				if(board[sx][i]!=0){
					flag=1;
					break;
				}
			}
			if(!flag) return landing;
			else return 0;
		}
		else if(sy==dy){
			for(int i=min(sx,dx)+1;i<max(sx,dx);i++){
				if(board[i][sy]!=0) {
					flag=1;
					break;
				}
			}
			if(!flag) return landing;
			else return 0;
		}
		else return 0;
	}
	if(chs%10 == 6){// 鸭
		for(int _sx : {1,-1}){
			for(int _sy : {1,-1}){
				if(board[sx+_sx*2][sy+_sy*1]==0 && board[sx+_sx][sy] == 0){
					if((sx+(_sx*3))==dx && (sy+_sy*2)==dy){
						return landing;
					}
				}
				if(board[sx][sy+_sy]==0 && board[sx+_sx*1][sy+_sy*2] == 0){
					if((sx+_sx*2)==dx && (sy+(_sy*3))==dy){
						return landing;
					}
				}
			}
		}
		return 0;
	}
	if(chs%10 == 7){// 兵
		for(pair<int,int> delta : soldier_delta){
			if(sx+delta.first==dx && sy+delta.second==dy){
				return landing;
			}
		}
		return 0;
	}
	return 0;
}
bool is_checking(int player){
	// 是否将军 player=1 红方被将 player=2 蓝方被将
	int cx=-1,cy=-1;
	for(int i=0;i<10&&(cx==-1);i++){
		for(int j=0;j<9&&(cy==-1);j++){
			if(board[i][j]==(player*10+1)){
				cx=i;cy=j;
			}
		}
	}
	if(cx==-1&&cy==-1) return false;
	for(int i=0;i<10;i++){
		for(int j=0;j<9;j++){
			if(i==cx&&j==cy) continue;
			if(board[i][j]==0) continue;
			if(is_moving_legal(board[i][j],i,j,cx,cy)){
				return true;
			}
		}
	}
	return false;
}
bool is_finished(int player){
	// 是否结束 player=1 蓝方胜利 player=2 红方胜利
	int cx=-1,cy=-1;
	for(int i=0;i<10&&(cx==-1);i++){
		for(int j=0;j<9&&(cy==-1);j++){
			if(board[i][j]==(player*10+1)){
				cx=i;cy=j;
			}
		}
	}
	if(cx==-1&&cy==-1) return true;
	else return false;
}
string get_name(int chs){
	// 获得棋子英文名
	string player,type;
	if(chs/10==1) player="red";
	if(chs/10==2) player="blue";
	if(chs%10 == 1) type="captain";
	if(chs%10 == 2) type="guard";
	if(chs%10 == 3) type="elephant";
	if(chs%10 == 4) type="horse";
	if(chs%10 == 5) type="car";
	if(chs%10 == 6) type="duck";
	if(chs%10 == 7) type="soldier";
	return player + " " + type;
}
bool finished = 0;
int nowmove = 1;
signed main(){
	int q;
	cin>>q;
	while(q--){
		int sx,sy,dx,dy;
		cin>>sx>>sy>>dx>>dy;
		int moving = is_moving_legal(board[sx][sy],sx,sy,dx,dy);
		if(!moving||finished||board[sx][sy]/10 != nowmove){cout<<"Invalid command\n";continue;}
		string moved=get_name(board[sx][sy]),ate="NA",checking="no",finishing="no";
		if(moving == 2) ate=get_name(board[dx][dy]);
		board[dx][dy]=board[sx][sy];board[sx][sy]=0;
		if(is_checking(1) || is_checking(2)) checking="yes";
		if(is_finished(1) || is_finished(2)){finishing="yes";finished=1;}
		cout<<moved<<';'<<ate<<';'<<checking<<';'<<finishing<<'\n';
		if(nowmove == 1) nowmove = 2;
		else nowmove = 1;
	}
	return 0;
}
P5380 [THUPC2019]鸭棋的更多相关文章
- 题解 洛谷P5380 【[THUPC2019]鸭棋】
		就是一道大模拟. 首先,来解释一下复杂的题意: 给你一些棋子,每个棋都有不同的走法,开局是回归原位. 接下来,题目会给你一个虚拟的走子操作(注意不一定真实),你所需要判断当前操作是否正确.若不正确,输 ... 
- thupc & cts & apio & thusc 游记 (北京17日游记)
		thupc & cts & apio & thusc 游记 (北京17日游记) Day 0 和隔壁校两人py了一下,六个人组了两队,(左哼哼)与(右哼哼),我和Camoufla ... 
- 日记 + sb错误
		置顶消息cpdd 1.29 完了,文化课没了 我是废物 1.28 更新了自己的副标题 前副标题:Future never has to do with past time,but present ti ... 
- THUPC2019/CTS2019/APIO2019/PKUSC2019游记
		THUPC2019/CTS2019/APIO2019/PKUSC2019游记 5.10 中铺,火车好晃啊 5.11 打了THUPC2019的练习赛,华容道好评(四个小兵,杠鸭!) 5.12 打了THU ... 
- [CareerCup] 17.2 Tic Tac Toe 井字棋游戏
		17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ... 
- BZOJ  1076 & 撞鸭递推
		题意: 还是看原题题面好... 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随 机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决 ... 
- 开源战棋 SLG 游戏框架设计思考(一)简介和游戏引擎
		战棋 SLG 游戏 SLG(Simulation Game)游戏是模拟游戏的简称.战棋类的SLG有两种:一种是 War Game 中的兵棋推演分支,常见的游戏有战争艺术3(TOAW3 — The Op ... 
- 隔壁信概大作业xjb写——同化棋ATAXX
		话说泥萌北大信科啊,助教是有多懒...去年黑白棋今年同化棋,顺带打ai都不用自己写标程... 好吧..我知道泥萌重点在各种sb的辅助操作上..什么悲剧的可以随时暂停载入...有毒吧 [据说泥萌上课没讲 ... 
- 原创跑酷小游戏《Cube Duck Run》 - - 方块鸭快跑
		自从unity5出来才开始关注unity,业余时间尝试做了个小游戏: <方块鸭快跑> (Cube Duck Run) 像素风,3d视角,色彩明快,有无尽和关卡两种模式. 应用连接: goo ... 
随机推荐
- NLP之基于Transformer的句子翻译
			Transformer 目录 Transformer 1.理论 1.1 Model Structure 1.2 Multi-Head Attention & Scaled Dot-Produc ... 
- Ansible 批处理实战
			软件简介 Ansible 是一款自动化运维工具,基于 Python 开发,集合了众多运维工具(puppet.chef.func.fabric)的优点,实现了批量系统配置.批量程序部署.批量运行命令等功 ... 
- Sublime Text4(Build 4126) 安装备忘
			Sublime Text4(Build 4126) 安装备忘 sublime text 4126 PJ已测可用 打开浏览器进入网站https://hexed.it 打开sublime text4安装目 ... 
- chrome工具调试
			项目调试的困境 程序开发总会遇到各种各样的问题,为什么实际结果和预期结果不一致? 这个时候如果能深入程序内部抽丝剥茧去一探究竟再好不过! 而chrome工具是前端开发的杀手锏,经常听到的一句话是: 出 ... 
- 支持JDK19虚拟线程的web框架,之五(终篇):兴风作浪的ThreadLocal
			欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos <支持JDK19虚拟线程的web框架>系列 ... 
- perl之grep函数的用法
			转载至 perl中grep的详细用法 grep有2种表达方式: 1 grep BLOCK LIST 2 grep EXPR, LIST BLOCK表示一个code块,通常用{}表示:EXPR表示一个表 ... 
- mindxdl--common--log_record.go
			// Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.// Package common define co ... 
- AArch32/AArch64系统级内存模型(三)
			1. 内存系统架构 1.1 系统级存储系统体系结构的形式 Armv8的a -profile体系结构包括一个虚拟内存系统体系结构(Virtual Memory System Architecture ... 
- orcl substr函数与java substring 的不同
			前天事情急改一个存储过程时遇到了substr方法时,一直用好,然后用其他方法跳过去了,今天有时间回头来验证 才发现和java太不一样了! select substr('为中华之崛起而读书',2,4) ... 
- 【文档资料】Linux、Vi/Vim常用命令、文件夹和文件介绍
			一.Linux 1.系统信息[左1] 查看磁盘空间使用情况:df+参数 查看当前指定文件或目录的大小:du 查看不同硬件信息:cat/proc/xxx 查看系统和空闲内存:free +参数 SSH退出 ... 
