洛谷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
然后就是棋子了。值得注意的是,虽然各个棋子要记录的信息大体相似,但是在移动方式上,我们并不能很方便地去统一封装。这里我选择的是,对每个棋子分别封装。这样做的好处就是特别清晰,方便调试,也方便处理,坏处就是我们没办法去做到映射(因为变量从属不同),所以如果我们要对某个棋子进行操作,只能是把所有的在场同类棋子都扫一遍;同样是因为变量不同,所以我们得写扫七个不同变量的循环……
我们对于每种棋子,都需要记录以下内容:
- 当前的坐标;
- 移动坐标要用到的数组
和 ; - 棋子的编号(这个很重要,因为只有通过这个才能去定位棋子!)
那么,我们要封装什么函数呢?
其实每个棋子只需要两个就够:判定移动是否合法,和判定能否将军。但是有七种棋子,所以其实是要写十四个差不多的函数。由于细节比较多,这里就不在赘述,最后的代码中会有相应注释。
然后,我们来考虑主函数中需要调用的东西。
对于判定非法移动的这个总函数,我们的解决方案是,先把共同的条件判掉,也就是判断起点是否合法(有无棋子和棋子颜色),终点是否合法(棋子颜色),然后去处理每个棋子不同的条件。这里就得把所有的同类棋子扫一遍,找到我们需要判定的棋子,然后调用该棋子对应的函数即可。
对于移动被吃掉棋子这个函数,我们需要加一个数组来标记不在棋盘上的棋子,来防止后边被遍历到,然后注意清空地图上该棋子即可。同时我们要注意记录游戏是否结束(王是否被吃掉)。
对于移动棋子这个函数,我们也是要扫一遍所有棋子,找到我们要移动的棋子,然后直接移动即可(我们已经判断了移动合法)。注意棋盘上的编号和棋子自己记录的
然后就是将军局面这个东西了。这个看起来挺麻烦,但是因为数据范围不是很大,所以我们直接暴力扫!没错,我们直接扫描棋盘上所有的棋子(这也就是为啥要记录被吃掉的棋子,死人可不能诈尸),然后看他是否会攻击对方的王就行了。注意,这里的攻击也是建立在能合法移动的前提之上的。还有一点,就是游戏结束了就没有将军了。
大模拟的特点就是说起来容易写起来难,上面的思路我相信并不难想,但是想要很好地实现真的需要很大的功夫(我大概花了一晚上和一下午写完的这个题)。下面给出来代码,大概 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; }