洛谷P5380 [THUPC2019] 鸭棋 题解

洛谷P5380 [THUPC2019] 鸭棋 题解

闲话

其实之前我没想碰大模拟的……这次的起因是 wjy同学 那天提到了要卷点大模拟,而猪国杀感觉太过复杂,于是我就选了鸭棋(

这是我第一道,大概也是最后一道大模拟了……

然后还是对着数据点二一点点改出来的 qwq,调试代码的过程真的好痛苦……当然,发现问题,改正问题的感觉还是蛮欣喜的。同时这次我也懂得了变量命名的重要性,以后会更加小心重复变量的出现。

题解

好了进入正题。首先我想说说我写这道题的思路。因为是模拟,所以我们要先理清整个游戏的流程。这道题比猪国杀简单就是因为它的回合并不复杂,最大的转换就是红蓝角色的变更,因此,很多东西都是相似甚至一样的。我们可以利用这一点进行函数封装,以达到模块化的目的,同时也可以让后期的调试更加便利。

我们发现,每一个回合其实总结下来,就是需要实现以下四个函数:判定移动是否合法,移除棋子,移动棋子,判定将军,伪代码如下:

if(!is_allowed()) puts("Invalid command");
//非法移动
move_a_piece(x, y);
//移除被吃掉的棋子
movexy(x, y, tx, ty);
//移动当前棋子
if(check()) puts("yes");
else puts("no");
//判定是否形成将军局面

然后我们来讨论如何实现。首先,我们可以用一个二维数组来记录棋盘,用编号来代替棋子,再让每个编号映射上种类。

我们可以把种类和编号处理成如下的矩阵(当然得自己打qwq):

5 4 3 2 1 2 3 4 5  1  2  3  4  5  6  7  8  9
0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0
6 0 0 0 0 0 0 0 6  10 0  0  0  0  0  0  0  11
7 0 7 0 7 0 7 0 7  12 0  13 0  14 0  15 0  16
0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0
0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0
7 0 7 0 7 0 7 0 7  17 0  18 0  19 0  20 0  21
6 0 0 0 0 0 0 0 6  22 0  0  0  0  0  0  0  23
0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0
5 4 3 2 1 2 3 4 5  24 25 26 27 28 29 30 31 32

然后就是棋子了。值得注意的是,虽然各个棋子要记录的信息大体相似,但是在移动方式上,我们并不能很方便地去统一封装。这里我选择的是,对每个棋子分别封装。这样做的好处就是特别清晰,方便调试,也方便处理,坏处就是我们没办法去做到映射(因为变量从属不同),所以如果我们要对某个棋子进行操作,只能是把所有的在场同类棋子都扫一遍;同样是因为变量不同,所以我们得写扫七个不同变量的循环……

我们对于每种棋子,都需要记录以下内容:

  • 当前的坐标;
  • 移动坐标要用到的数组 \(dx\)\(dy\)
  • 棋子的编号(这个很重要,因为只有通过这个才能去定位棋子!)

那么,我们要封装什么函数呢?

其实每个棋子只需要两个就够:判定移动是否合法,和判定能否将军。但是有七种棋子,所以其实是要写十四个差不多的函数。由于细节比较多,这里就不在赘述,最后的代码中会有相应注释。

然后,我们来考虑主函数中需要调用的东西。

对于判定非法移动的这个总函数,我们的解决方案是,先把共同的条件判掉,也就是判断起点是否合法(有无棋子和棋子颜色),终点是否合法(棋子颜色),然后去处理每个棋子不同的条件。这里就得把所有的同类棋子扫一遍,找到我们需要判定的棋子,然后调用该棋子对应的函数即可。

对于移动被吃掉棋子这个函数,我们需要加一个数组来标记不在棋盘上的棋子,来防止后边被遍历到,然后注意清空地图上该棋子即可。同时我们要注意记录游戏是否结束(王是否被吃掉)。

对于移动棋子这个函数,我们也是要扫一遍所有棋子,找到我们要移动的棋子,然后直接移动即可(我们已经判断了移动合法)。注意棋盘上的编号和棋子自己记录的 \(x\)\(y\) 都要相应改变。

然后就是将军局面这个东西了。这个看起来挺麻烦,但是因为数据范围不是很大,所以我们直接暴力扫!没错,我们直接扫描棋盘上所有的棋子(这也就是为啥要记录被吃掉的棋子,死人可不能诈尸),然后看他是否会攻击对方的王就行了。注意,这里的攻击也是建立在能合法移动的前提之上的。还有一点,就是游戏结束了就没有将军了。

大模拟的特点就是说起来容易写起来难,上面的思路我相信并不难想,但是想要很好地实现真的需要很大的功夫(我大概花了一晚上和一下午写完的这个题)。下面给出来代码,大概 600 行,可能是我 OI 生涯里写过最长的一份代码了。

友情提醒,该代码过于冗长,博客阅读可能不太方便,建议放到编译器中,把当前不看的函数折叠,一个函数一个函数看,可能会好一点(估计没人会读这份代码hhh)。

代码戳这里👇

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 20;

bool is_end, winner;//游戏是否结束,赢家
bool is_dead[50];//死人标记(
int mp[10][9] = {
	1, 2, 3, 4, 5, 6, 7, 8, 9,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	10,0, 0, 0, 0, 0, 0, 0,11,
	12,0,13, 0,14, 0,15, 0,16,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	17,0,18, 0,19, 0,20, 0,21,
	22,0, 0, 0, 0, 0, 0, 0,23,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	24,25,26,27,28,29,30,31,32
};
int type[50] = {0,5,4,3,2,1,2,3,4,5,6,6,7,7,7,7,7,7,7,7,7,7,6,6,5,4,3,2,1,2,3,4,5};
//棋盘(记录编号)和编号对种类的映射

//这里做一个统一,所有的sx, sy表示起点;tx, ty表示终点
inline int read() {
	int x = 0;
	char ch = getchar();
	while(ch<'0' || ch>'9') ch = getchar();
	while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar();
	return x;
}//都什么题了还写快读(
//—————————————— 棋子↓ ————————————————————
struct Captain {
	int x, y, id, itype;//这里的itype就是不小心重复变量的一个例子:之前itype是type, 而全局变量中有一个type, 导致两个type冲突了。
    //当然,itype并没有什么卵用……
	int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, -1, 1};//方向数组
    //is_available 用来判断移动是否合法,check 用来判断能否将军,以下的所有棋子都按这个规则来命名函数
	bool is_available(int tx, int ty) {//变量和函数名都最好别懒省事了,千万别调试的时候自己都看不懂
		int dir = -1;//记录移动对应的是哪一对 dx dy
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;//发现移动的方式不在记录的方向数组中,说明不合法
		else return 1;
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);//记录当前棋子的阵营
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;//判断移动是否合法
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);//记录目标点棋子的阵营
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;//只有吃掉对方王才算将军(
		}
		return 0;
	}
} captain[5]; //编号1,对应王

struct Guard {//和王基本一致
	int x, y, id, itype;
	int dx[4] = {1, 1, -1, -1}, dy[4] = {1, -1, 1, -1};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		else return 1;
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} guard[10]; //编号2,对应士

struct Elephant {
	int x, y, id, itype;
	int dx[4] = {2, 2, -2, -2}, dy[4] = {2, -2, 2, -2};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		return !mp[x+dx[dir]/2][y+dy[dir]/2];//判断路径上是否有其他棋子
	}
	bool check() {//一致
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} elephant[10]; //编号3,对应象

struct Horse {
	int x, y, id, itype;
	int dx[8] = {2, 2, -2, -2, 1, 1, -1, -1};
	int dy[8] = {1, -1, 1, -1, 2, -2, 2, -2};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<8; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		if(dir<4) {//这里小细节,把2*x的移动方式放在数组左侧,方便判断
			return !mp[x+dx[dir]/2][y];
		} else {
			return !mp[x][y+dy[dir]/2];
		}
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {//依然一致
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} horse[10]; //编号4,对应马

struct Car {//注意这个是最特殊的一类棋子了,它没有方向数组,所有两个函数都不太一样
	int x, y, id, itype;
	bool is_available(int tx, int ty) {
		if(tx != x && ty != y) return 0;//车只能横向或竖向移动
		if(tx ^ x) {
			for(int i = min(x, tx)+1; i<max(x, tx); ++i) {//判断起点和终点之间(不包括两端)有没有棋子即可
				if(mp[i][y]) return 0;
			}
			return 1;
		} else {
			for(int i = min(y, ty)+1; i<max(y, ty); ++i) {
				if(mp[x][i]) return 0;
			}
			return 1;
		}
	}
	bool check() {
		int tx, ty;
		bool is_red = (id<=16);
		for(tx = x+1, ty = y; tx<10; ++tx) {//这里要判断车向四个方向移动碰到的第一个棋子是否为对方的王
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x-1, ty = y; tx>=0; --tx) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x, ty = y+1; ty<9; ++ty) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x, ty = y-1; ty>=0; --ty) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		return 0;
	}
} car[10]; //编号5,对应车

struct Duck {
	int x, y, id, itype;
	int dx[8] = {3, 3, -3, -3, 2, 2, -2, -2};
	int dy[8] = {2, -2, 2, -2, 3, -3, 3, -3};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<8; ++i) {
			if(x+dx[i] == tx && y+dy[i] == ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		if(dir < 4) {//和马类似
			return (!mp[x+dx[dir]/3*2][y+dy[dir]/2])&&(!mp[x+dx[dir]/3][y]);
		} else {
			return (!mp[x+dx[dir]/2][y+dy[dir]/3*2])&&(!mp[x][y+dy[dir]/3]);
		}
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} duck[10]; //编号6,对应鸭

struct Soldier {
	int x, y, id, itype;
	int dx[8] = {1, -1, 0, 0, 1, -1, 1, -1};
	int dy[8] = {0, 0, 1, -1, 1, -1, -1, 1};
    bool is_available(int tx, int ty){//和王与士基本一致
        int dir = -1;
        for(int i = 0; i<8; ++i){
            if(x+dx[i] == tx && y+dy[i] == ty){
                dir = i;
                break;
            }
        }
        return dir!=-1;
    }
	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} soldier[22]; //编号7,对应兵

//—————————————————————— 函数部分 ↓ ——————————————————
bool is_red(int x) {//棋子是否为红方
	return x<=16;
}

string team[5], nameoftype[10];//记录队伍颜色与种类名称,便于输出。
int SumofCaptain, SumofGuard, SumofElephant, SumofHorse, SumofCar, SumofDuck, SumofSoldier;//各个棋子的数量

void init() {//初始化,注意我们要把所有棋子初始化
    //各个名称
	nameoftype[1] = "captain";
	nameoftype[2] = "guard";
	nameoftype[3] = "elephant";
	nameoftype[4] = "horse";
	nameoftype[5] = "car";
	nameoftype[6] = "duck";
	nameoftype[7] = "soldier";
	team[1] = "red ";//细节空格
	team[0] = "blue ";
	SumofCaptain = 0;
	SumofGuard = 0;
	SumofElephant = 0;
	SumofHorse = 0;
	SumofCar = 0;
	SumofDuck = 0;
	SumofSoldier = 0;//没必要的清零(bush
	for(int i = 0; i<10; ++i) {
		for(int j = 0; j<9; ++j) {
			int id = mp[i][j], ty = type[mp[i][j]];
            //特别注意,这里不小心写了一个ty(可能重复的变量),因为函数里没有用到我才没有改,但这是应该极力避免的。
			if(ty == 1) {//这里写switch明显更清晰,但是这里忘了……下一个函数才想起来
				SumofCaptain++;
				captain[SumofCaptain].x = i, captain[SumofCaptain].y = j;
				captain[SumofCaptain].id = id;
				captain[SumofCaptain].itype = ty;
			} else if(ty == 2) {
				SumofGuard++;
				guard[SumofGuard].x = i, guard[SumofGuard].y = j;
				guard[SumofGuard].id = id;
				guard[SumofGuard].itype = ty;
			} else if(ty == 3) {
				SumofElephant++;
				elephant[SumofElephant].x = i, elephant[SumofElephant].y = j;
				elephant[SumofElephant].id = id;
				elephant[SumofElephant].itype = ty;
			} else if(ty == 4) {
				SumofHorse++;
				horse[SumofHorse].x = i, horse[SumofHorse].y = j;
				horse[SumofHorse].id = id;
				horse[SumofHorse].itype = ty;
			} else if(ty == 5) {
				SumofCar++;
				car[SumofCar].x = i, car[SumofCar].y = j;
				car[SumofCar].id = id;
				car[SumofCar].itype = ty;
			} else if(ty == 6) {
				SumofDuck++;
				duck[SumofDuck].x = i, duck[SumofDuck].y = j;
				duck[SumofDuck].id = id;
				duck[SumofDuck].itype = ty;
			} else if(ty == 7) {
				SumofSoldier++;
				soldier[SumofSoldier].x = i, soldier[SumofSoldier].y = j;
				soldier[SumofSoldier].id = id;
				soldier[SumofSoldier].itype = ty;
			}
		}
	}
}
//需要注意,有操作叫做将军,游戏结束需要真正实现吃掉对方王。

bool is_allowed(int x, int y, int tx, int ty) {
	if(is_end) {
		return 0;
	}
	int id = mp[x][y], typ = type[mp[x][y]];
	switch (typ) {//去对应种类的棋子里找目标棋子
		case 1: {
			int tid;
			for(int i = 1; i<=SumofCaptain; ++i) {
				if(captain[i].id == id) {
					tid = i;
					break;
				}
			}
			return captain[tid].is_available(tx, ty);
			break;
		}
		case 2: {
			int tid;
			for(int i = 1; i<=SumofGuard; ++i) {
				if(guard[i].id == id) {
					tid = i;
					break;
				}
			}
			return guard[tid].is_available(tx, ty);//调用判定函数
			break;
		}
		case 3: {
			int tid;
			for(int i = 1; i<=SumofElephant; ++i) {
				if(elephant[i].id == id) {
					tid = i;
					break;
				}
			}
			return elephant[tid].is_available(tx, ty);
			break;
		}
		case 4: {
			int tid;
			for(int i = 1; i<=SumofHorse; ++i) {
				if(horse[i].id == id) {
					tid = i;
					break;
				}
			}
			return horse[tid].is_available(tx, ty);
			break;
		}
		case 5: {
			int tid;
			for(int i = 1; i<=SumofCar; ++i) {
				if(car[i].id == id) {
					tid = i;
					break;
				}
			}
			return car[tid].is_available(tx, ty);
			break;
		}
		case 6: {
			int tid;
			for(int i = 1; i<=SumofDuck; ++i) {
				if(duck[i].id == id) {
					tid = i;
					break;
				}
			}
			return duck[tid].is_available(tx, ty);
			break;
		}
		case 7: {
			int tid;
			for(int i = 1; i<=SumofSoldier; ++i) {
				if(soldier[i].id == id) {
					tid = i;
					break;
				}
			}
			return soldier[tid].is_available(tx, ty);
			break;
		}
	}
	return 0;
}
void print_mp() {//输出当前局面,用于调试
	for(int i = 0; i<10; ++i, puts("")) {
		for(int j = 0; j<9; ++j) {
			printf("%d ", type[mp[i][j]]);
		}
		putchar(' ');
		for(int j = 0; j<9; ++j){
			printf("%-3d", mp[i][j]);
		}
	}
	putchar('\n');
}

bool check() {//将军判定函数
	if(is_end) return 0;
	for(int i = 1; i<=SumofCaptain; ++i) {
		if(is_dead[captain[i].id]) continue;//死人不会说话(
		if(captain[i].check()) return 1;
	}
	for(int i = 1; i<=SumofGuard; ++i) {
		if(is_dead[guard[i].id]) continue;
		if(guard[i].check()) return 1;
	}
	for(int i = 1; i<=SumofElephant; ++i) {
		if(is_dead[elephant[i].id]) continue;
		if(elephant[i].check()) return 1;
	}
	for(int i = 1; i<=SumofHorse; ++i) {
		if(is_dead[horse[i].id]) continue;
		if(horse[i].check()) return 1;
	}
	for(int i = 1; i<=SumofCar; ++i) {
		if(is_dead[car[i].id]) continue;
		if(car[i].check()) return 1;
	}
	
	for(int i = 1; i<=SumofDuck; ++i) {
		if(is_dead[duck[i].id]) continue;
		if(duck[i].check()) return 1;
	}
	for(int i = 1; i<=SumofSoldier; ++i) {
		if(is_dead[soldier[i].id]) continue;
		if(soldier[i].check()) return 1;
	}
	return 0;
}

bool current_round = 1;//当前轮到哪一方,1为红色,0为蓝色
void movexy(int x, int y, int tx, int ty) {//移动棋子
	int id = mp[x][y], typ = type[mp[x][y]];
	switch (typ) {
		case 1: {
			int tid;
			for(int i = 1; i<=SumofCaptain; ++i) {
				if(captain[i].id == id) {
					tid = i;
					break;
				}
			}
			captain[tid].x = tx;//注意每个棋子的坐标也要同时修改
			captain[tid].y = ty;
			break;
		}
		case 2: {
			int tid;
			for(int i = 1; i<=SumofGuard; ++i) {
				if(guard[i].id == id) {
					tid = i;
					break;
				}
			}
			guard[tid].x = tx;
			guard[tid].y = ty;
			break;
		}
		case 3: {
			int tid;
			for(int i = 1; i<=SumofElephant; ++i) {
				if(elephant[i].id == id) {
					tid = i;
					break;
				}
			}
			elephant[tid].x = tx;
			elephant[tid].y = ty;
			break;
		}
		case 4: {
			int tid;
			for(int i = 1; i<=SumofHorse; ++i) {
				if(horse[i].id == id) {
					tid = i;
					break;
				}
			}
			horse[tid].x = tx;
			horse[tid].y = ty;
			break;
		}
		case 5: {
			int tid;
			for(int i = 1; i<=SumofCar; ++i) {
				if(car[i].id == id) {
					tid = i;
					break;
				}
			}
			car[tid].x = tx;
			car[tid].y = ty;
			break;
		}
		case 6: {
			int tid;
			for(int i = 1; i<=SumofDuck; ++i) {
				if(duck[i].id == id) {
					tid = i;
					break;
				}
			}
			duck[tid].x = tx;
			duck[tid].y = ty;
			break;
		}
		case 7: {
			int tid;
			for(int i = 1; i<=SumofSoldier; ++i) {
				if(soldier[i].id == id) {
					tid = i;
					break;
				}
			}
			soldier[tid].x = tx;
			soldier[tid].y = ty;
			break;
		}
	}
	mp[tx][ty] = id;//更新棋盘状态
	mp[x][y] = 0;
}

void move_a_piece(int x, int y, bool red_round) { //移走x,y处的棋子并输出结果。
	int id = mp[x][y], typ = type[mp[x][y]];
	if(typ == 1) {//判定是否游戏结束
		is_end = 1;
		winner = red_round;
	}
	cout << team[red_round^1] << nameoftype[typ]<<";";
	mp[x][y] = 0;//更新棋盘状态
	is_dead[id] = 1;//标记吃掉的棋子
}

//—————————————— 主函数 ↓——————————————————
int Q;
int main() {
	init();
	Q = read();
	for(int round = 1; round<=Q; ++round) {
		int sx = read(), sy = read(), tx = read(), ty = read();
		bool red_round = (current_round&1);
        //判定移动是否合法
		if((!mp[sx][sy]) || (is_red(mp[sx][sy])^red_round) ||((is_red(mp[tx][ty])^(red_round^1))&&mp[tx][ty]) ) {//起点合法与终点合法(终点注意要有棋子才能继续判断)
			puts("Invalid command");
			continue;
		}
		int CurrentType = type[mp[sx][sy]];
		if(!is_allowed(sx, sy, tx, ty)) {
			puts("Invalid command");
			continue;
		}

		//输出当前移动棋子是什么
		cout << team[red_round] << nameoftype[CurrentType] <<";";
		if(!mp[tx][ty]) cout << "NA;";
		else move_a_piece(tx, ty, red_round);//移除棋子

		movexy(sx, sy, tx, ty);//移动棋子

		if(check()) cout << "yes;";//判断将军
		else cout <<"no;";

		if(is_end) puts("yes");//判断游戏结束与否
		else puts("no");
		current_round^=1;//只有合法操作之后才会切换红蓝
	}
	return 0;
}//完结撒花!加上注释610行的代码,也感谢您能读到这里www。

啊啊啊累死了累死了 qwq以后再不写大模拟了 xwx。

updated 2023/7/11

这里给出 鸭棋Virtual 的代码~可以与小伙伴对战辣(很粗糙就是了,仅仅是在原题基础上搞了个输出 xwx)。

点击查看代码
#include<iostream>
#include<windows.h>
#define RED 4
#define PINK 13
#define WHITE 7
#define YELLOW 6
#define B_YELLOW 14
#define BLUE 1
#define B_BLUE 9
#define BB_BLUE 11 
using namespace std;
const int N = 20;

bool is_end, winner;
bool is_dead[50];
int mp[10][9] = {
	1, 2, 3, 4, 5, 6, 7, 8, 9,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	10,0, 0, 0, 0, 0, 0, 0,11,
	12,0,13, 0,14, 0,15, 0,16,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	17,0,18, 0,19, 0,20, 0,21,
	22,0, 0, 0, 0, 0, 0, 0,23,
	0, 0, 0, 0, 0, 0, 0, 0, 0,
	24,25,26,27,28,29,30,31,32
};
int type[50] = {0,5,4,3,2,1,2,3,4,5,6,6,7,7,7,7,7,7,7,7,7,7,6,6,5,4,3,2,1,2,3,4,5};

inline int read() {
	int x = 0;
	char ch = getchar();
	while(ch<'0' || ch>'9') ch = getchar();
	while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar();
	return x;
}
struct Captain {
	int x, y, id, itype;
	int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, -1, 1};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		else return 1;
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} captain[5]; //1

struct Guard {
	int x, y, id, itype;
	int dx[4] = {1, 1, -1, -1}, dy[4] = {1, -1, 1, -1};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		else return 1;
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} guard[10]; //2

struct Elephant {
	int x, y, id, itype;
	int dx[4] = {2, 2, -2, -2}, dy[4] = {2, -2, 2, -2};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<4; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		return !mp[x+dx[dir]/2][y+dy[dir]/2];
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<4; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} elephant[10]; //3

struct Horse {
	int x, y, id, itype;
	int dx[8] = {2, 2, -2, -2, 1, 1, -1, -1};
	int dy[8] = {1, -1, 1, -1, 2, -2, 2, -2};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<8; ++i) {
			if(x+dx[i]==tx && y+dy[i]==ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		if(dir<4) {
			return !mp[x+dx[dir]/2][y];
		} else {
			return !mp[x][y+dy[dir]/2];
		}
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} horse[10]; //4

struct Car {
	int x, y, id, itype;
	bool is_available(int tx, int ty) {
		if(tx != x && ty != y) return 0;
		if(tx ^ x) {
			for(int i = min(x, tx)+1; i<max(x, tx); ++i) {
				if(mp[i][y]) return 0;
			}
			return 1;
		} else {
			for(int i = min(y, ty)+1; i<max(y, ty); ++i) {
				if(mp[x][i]) return 0;
			}
			return 1;
		}
	}
	bool check() {
		int tx, ty;
		bool is_red = (id<=16);
		for(tx = x+1, ty = y; tx<10; ++tx) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x-1, ty = y; tx>=0; --tx) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x, ty = y+1; ty<9; ++ty) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		for(tx = x, ty = y-1; ty>=0; --ty) {
			if(mp[tx][ty]) {
				bool enemy = (mp[tx][ty]<=16);
				if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
				break;
			}
		}
		return 0;
	}
} car[10]; //5

struct Duck {
	int x, y, id, itype;
	int dx[8] = {3, 3, -3, -3, 2, 2, -2, -2};
	int dy[8] = {2, -2, 2, -2, 3, -3, 3, -3};
	bool is_available(int tx, int ty) {
		int dir = -1;
		for(int i = 0; i<8; ++i) {
			if(x+dx[i] == tx && y+dy[i] == ty) {
				dir = i;
				break;
			}
		}
		if(dir == -1) return 0;
		if(dir < 4) {
			return (!mp[x+dx[dir]/3*2][y+dy[dir]/2])&&(!mp[x+dx[dir]/3][y]);
		} else {
			return (!mp[x+dx[dir]/2][y+dy[dir]/3*2])&&(!mp[x][y+dy[dir]/3]);
		}
	}
	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} duck[10]; //6

struct Soldier {
	int x, y, id, itype;
	int dx[8] = {1, -1, 0, 0, 1, -1, 1, -1};
	int dy[8] = {0, 0, 1, -1, 1, -1, -1, 1};
    bool is_available(int tx, int ty){
        int dir = -1;
        for(int i = 0; i<8; ++i){
            if(x+dx[i] == tx && y+dy[i] == ty){
                dir = i;
                break;
            }
        }
        return dir!=-1;
    }

	bool check() {
		int tx, ty;
		for(int i = 0; i<8; ++i) {
			tx = x+dx[i];
			ty = y+dy[i];
			bool is_red = (id<=16);
			if(tx<0 || tx>=10 || ty<0 || ty>=9) continue;
			if(!is_available(tx, ty)) continue;
			bool enemy = (mp[tx][ty]<=16);
			if((type[mp[tx][ty]]==1)&&(is_red^enemy)) return 1;
		}
		return 0;
	}
} soldier[22]; //7

bool is_red(int x) {
	return x<=16;
}

string team[5], nameoftype[10], ch_name[10];
int SumofCaptain, SumofGuard, SumofElephant, SumofHorse, SumofCar, SumofDuck, SumofSoldier;
void init() {
	nameoftype[1] = "王";
	nameoftype[2] = "士";
	nameoftype[3] = "象";
	nameoftype[4] = "马";
	nameoftype[5] = "车";
	nameoftype[6] = "鸭";
	nameoftype[7] = "兵";
	team[1] = "红方 ";
	team[0] = "蓝方 ";
	SumofCaptain = 0;
	SumofGuard = 0;
	SumofElephant = 0;
	SumofHorse = 0;
	SumofCar = 0;
	SumofDuck = 0;
	SumofSoldier = 0;
	for(int i = 0; i<10; ++i) {
		for(int j = 0; j<9; ++j) {
			int id = mp[i][j], ty = type[mp[i][j]];
			if(ty == 1) {
				SumofCaptain++;
				captain[SumofCaptain].x = i, captain[SumofCaptain].y = j;
				captain[SumofCaptain].id = id;
				captain[SumofCaptain].itype = ty;
			} else if(ty == 2) {
				SumofGuard++;
				guard[SumofGuard].x = i, guard[SumofGuard].y = j;
				guard[SumofGuard].id = id;
				guard[SumofGuard].itype = ty;
			} else if(ty == 3) {
				SumofElephant++;
				elephant[SumofElephant].x = i, elephant[SumofElephant].y = j;
				elephant[SumofElephant].id = id;
				elephant[SumofElephant].itype = ty;
			} else if(ty == 4) {
				SumofHorse++;
				horse[SumofHorse].x = i, horse[SumofHorse].y = j;
				horse[SumofHorse].id = id;
				horse[SumofHorse].itype = ty;
			} else if(ty == 5) {
				SumofCar++;
				car[SumofCar].x = i, car[SumofCar].y = j;
				car[SumofCar].id = id;
				car[SumofCar].itype = ty;
			} else if(ty == 6) {
				SumofDuck++;
				duck[SumofDuck].x = i, duck[SumofDuck].y = j;
				duck[SumofDuck].id = id;
				duck[SumofDuck].itype = ty;
			} else if(ty == 7) {
				SumofSoldier++;
				soldier[SumofSoldier].x = i, soldier[SumofSoldier].y = j;
				soldier[SumofSoldier].id = id;
				soldier[SumofSoldier].itype = ty;
			}
		}
	}
}

bool is_allowed(int x, int y, int tx, int ty) {
	if(is_end) {
		return 0;
	}
	int id = mp[x][y], typ = type[mp[x][y]];
	switch (typ) {
		case 1: {
			int tid;
			for(int i = 1; i<=SumofCaptain; ++i) {
				if(captain[i].id == id) {
					tid = i;
					break;
				}
			}
			return captain[tid].is_available(tx, ty);
			break;
		}
		case 2: {
			int tid;
			for(int i = 1; i<=SumofGuard; ++i) {
				if(guard[i].id == id) {
					tid = i;
					break;
				}
			}
			return guard[tid].is_available(tx, ty);
			break;
		}
		case 3: {
			int tid;
			for(int i = 1; i<=SumofElephant; ++i) {
				if(elephant[i].id == id) {
					tid = i;
					break;
				}
			}
			return elephant[tid].is_available(tx, ty);
			break;
		}
		case 4: {
			int tid;
			for(int i = 1; i<=SumofHorse; ++i) {
				if(horse[i].id == id) {
					tid = i;
					break;
				}
			}
			return horse[tid].is_available(tx, ty);
			break;
		}
		case 5: {
			int tid;
			for(int i = 1; i<=SumofCar; ++i) {
				if(car[i].id == id) {
					tid = i;
					break;
				}
			}
			return car[tid].is_available(tx, ty);
			break;
		}
		case 6: {
			int tid;
			for(int i = 1; i<=SumofDuck; ++i) {
				if(duck[i].id == id) {
					tid = i;
					break;
				}
			}
			return duck[tid].is_available(tx, ty);
			break;
		}
		case 7: {
			int tid;
			for(int i = 1; i<=SumofSoldier; ++i) {
				if(soldier[i].id == id) {
					tid = i;
					break;
				}
			}
			return soldier[tid].is_available(tx, ty);
			break;
		}
	}
	return 0;
}
void print_mp() {
	for(int i = 0; i<10; ++i, puts("")) {
		for(int j = 0; j<9; ++j) {
			printf("%d ", type[mp[i][j]]);
		}
		putchar(' ');
		for(int j = 0; j<9; ++j){
			printf("%-3d", mp[i][j]);
		}
	}
	putchar('\n');
}

bool check() {
	if(is_end) return 0;
	for(int i = 1; i<=SumofCaptain; ++i) {
		if(is_dead[captain[i].id]) continue;
		if(captain[i].check()) return 1;
	}
	for(int i = 1; i<=SumofGuard; ++i) {
		if(is_dead[guard[i].id]) continue;
		if(guard[i].check()) return 1;
	}
	for(int i = 1; i<=SumofElephant; ++i) {
		if(is_dead[elephant[i].id]) continue;
		if(elephant[i].check()) return 1;
	}
	for(int i = 1; i<=SumofHorse; ++i) {
		if(is_dead[horse[i].id]) continue;
		if(horse[i].check()) return 1;
	}
	for(int i = 1; i<=SumofCar; ++i) {
		if(is_dead[car[i].id]) continue;
		if(car[i].check()) return 1;
	}
	
	for(int i = 1; i<=SumofDuck; ++i) {
		if(is_dead[duck[i].id]) continue;
		if(duck[i].check()) return 1;
	}
	for(int i = 1; i<=SumofSoldier; ++i) {
		if(is_dead[soldier[i].id]) continue;
		if(soldier[i].check()) return 1;
	}
	return 0;
}

bool current_round = 1;
void movexy(int x, int y, int tx, int ty) {
	int id = mp[x][y], typ = type[mp[x][y]];
	switch (typ) {
		case 1: {
			int tid;
			for(int i = 1; i<=SumofCaptain; ++i) {
				if(captain[i].id == id) {
					tid = i;
					break;
				}
			}
			captain[tid].x = tx;
			captain[tid].y = ty;
			break;
		}
		case 2: {
			int tid;
			for(int i = 1; i<=SumofGuard; ++i) {
				if(guard[i].id == id) {
					tid = i;
					break;
				}
			}
			guard[tid].x = tx;
			guard[tid].y = ty;
			break;
		}
		case 3: {
			int tid;
			for(int i = 1; i<=SumofElephant; ++i) {
				if(elephant[i].id == id) {
					tid = i;
					break;
				}
			}
			elephant[tid].x = tx;
			elephant[tid].y = ty;
			break;
		}
		case 4: {
			int tid;
			for(int i = 1; i<=SumofHorse; ++i) {
				if(horse[i].id == id) {
					tid = i;
					break;
				}
			}
			horse[tid].x = tx;
			horse[tid].y = ty;
			break;
		}
		case 5: {
			int tid;
			for(int i = 1; i<=SumofCar; ++i) {
				if(car[i].id == id) {
					tid = i;
					break;
				}
			}
			car[tid].x = tx;
			car[tid].y = ty;
			break;
		}
		case 6: {
			int tid;
			for(int i = 1; i<=SumofDuck; ++i) {
				if(duck[i].id == id) {
					tid = i;
					break;
				}
			}
			duck[tid].x = tx;
			duck[tid].y = ty;
			break;
		}
		case 7: {
			int tid;
			for(int i = 1; i<=SumofSoldier; ++i) {
				if(soldier[i].id == id) {
					tid = i;
					break;
				}
			}
			soldier[tid].x = tx;
			soldier[tid].y = ty;
			break;
		}
	}
	mp[tx][ty] = id;
	mp[x][y] = 0;
}
void move_a_piece(int x, int y, bool red_round) { //移走x,y处的棋子并输出结果。
	int id = mp[x][y], typ = type[mp[x][y]];
	if(typ == 1) {
		is_end = 1;
		winner = red_round;
	}
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), BB_BLUE);
	cout <<"吃掉" <<team[red_round^1] << nameoftype[typ]<<";";
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),WHITE);
	mp[x][y] = 0;
	is_dead[id] = 1;
}
int Q;
void print_now(){
	printf("   ");
	for(int i = 0; i<9; ++i) printf("%-2d ", i);
	printf("y轴"); 
	putchar('\n');
	for(int i = 0; i<10; ++i, puts("")){
		printf("%-2d ", i);
		for(int j = 0; j<9; ++j){
//			printf("%-2d ", mp[i][j]);
			if(mp[i][j] && (!is_dead[mp[i][j]])){
				if(mp[i][j]<=16){
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4);
					cout <<  nameoftype[type[mp[i][j]]] << " " ;
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
				}
				else {
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),1);
					cout <<  nameoftype[type[mp[i][j]]] << " " ;
				    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
				}
			}
			else printf("0  ");
		}
	}
	puts("x");
	puts("轴") ;
	putchar('\n');
	if(!is_end){
		if(current_round) puts("-----------红方回合-----------"); 
		else puts("-----------蓝方回合-----------");
	}
}
int main() {
	init();
	Q = read();
	for(int round = 1; round<= Q; ++round) {
		print_now(); 
		int sx = read(), sy = read(), tx = read(), ty = read();
		bool red_round = (current_round&1);
		if((!mp[sx][sy]) || (is_red(mp[sx][sy])^red_round) ||((is_red(mp[tx][ty])^(red_round^1))&&mp[tx][ty]) ) {
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), B_YELLOW);
			puts("操作不合法!");
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),WHITE);
			continue;
		}
		int CurrentType = type[mp[sx][sy]];
		if(!is_allowed(sx, sy, tx, ty)) {
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), B_YELLOW);
			puts("操作不合法!");
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),WHITE);
			continue;
		}
		cout << team[red_round] << nameoftype[CurrentType] <<";";
		if(mp[tx][ty]) move_a_piece(tx, ty, red_round);
		movexy(sx, sy, tx, ty);

		if(check()) cout << "将军!;";
		putchar('\n');
		if(is_end){
			print_now();
			putchar('\n');
			putchar('\n');
			puts("游戏结束!");
			if(winner){
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), RED);
				puts("红方胜利!");
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),WHITE);
			} else{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), BLUE);
				puts("蓝方胜利!");
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),WHITE);
			}
			system("pause");
			return 0;
		}
		current_round^=1;
		
	}
	return 0;
}
posted @ 2023-06-27 20:20  霜木_Atomic  阅读(66)  评论(4编辑  收藏  举报