模拟|大模拟 鸭棋(250行超短做法,简单易懂)

题目描述: 洛谷题目传送门戳他!!!
解题思路:

  • 算法介绍:
算法标签上写得很清楚了,这题就是妥妥的大模拟,我们甚至在程序中都不用穿插任何的算法优化就可以稳过这道题,别问我怎么知道的……
众所周知,大模拟题目是一种编程复杂度极高的一种体型,写出大模拟的方法因人而异,这里介绍一下我的方法:
程序中必须要随处加注释吗,这样子既能清晰你对超长程序模块的功能识别,也可以帮助日后翻看程序的时候不至于连这个函数在干什么都看不懂,(别像我之前,硬生生的给自己的程序整出了初赛阅读程序题的感觉!!!)、
  • 解题方法:
【模拟|大模拟 鸭棋(250行超短做法,简单易懂)】先将题目中的几处重点敲出来:
  • 游戏结束以后任何步骤都无法执行
  • 游戏结束的时候不需要判断将军
  • 己方的棋子无法将死己方的王
先预处理出棋盘的布局和棋盘棋子颜色的布局:
char map[10][9]={ 'C','M','X','S','W','S','X','M','C', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'Y',' ',' ',' ',' ',' ',' ',' ','Y', 'B',' ','B',' ','B',' ','B',' ','B', ' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B',' ','B',' ','B',' ','B',' ','B', 'Y',' ',' ',' ',' ',' ',' ',' ','Y', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'C','M','X','S','W','S','X','M','C'}; //棋盘初始布局:C车,M马,X象,S士,W王,Y鸭,B兵char color[10][9]={ 'R','R','R','R','R','R','R','R','R', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'R',' ',' ',' ',' ',' ',' ',' ','R', 'R',' ','R',' ','R',' ','R',' ','R', ' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B',' ','B',' ','B',' ','B',' ','B', 'B',' ',' ',' ',' ',' ',' ',' ','B', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B','B','B','B','B','B','B','B','B'}; //棋盘初始颜色布局:R红,B蓝 string name[26]={ "","soldier","car","","","","","","","","","","horse","","","","","","guard","","","","captain","elephant","duck",""}; //将所有棋子的名称存起来

从每一个数据让我能要求的问题入手,先考虑题目中的第一个问题:当前位置的棋是否能走到目标位置。
这个问题有几个限制:
  • 如果当前位置根本没有棋子,那么很显然走不了
  • 如果当前位置和目标位置是一样的,那么就表示根本没有移动,也是不被允许的。
  • 如果当前位置棋子的颜色不符合当前回合可移动棋子的颜色,那么也不行。
  • 如果当前位置的棋子根本到不了目标位置,那么当然也不行。
很显然,前面三点都是一个特判断的事,那么真正需要敲代码的,就只有判断当前棋子可以走到那些位置上,对每一种棋子的移动方式都做一个纯粹的模拟。
  • 王:
bool Wgo(int sx,int sy,int fx,int fy,char col)//sx,sy为当前棋子坐标,fx,fy为指定位置坐标,col为当前棋子颜色 { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[4]={ 0,0,-1,1},dy[4]={ -1,1,0,0}; for(int i=0; i<4; i++)//枚举出当前 王 可以到达的坐标 {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }

其中函数中的 boom 用于判断将军,也就是说如果有棋子的合法移动可以吃掉对方的王,那么被视为将军局面
  • 士:
bool Sgo(int sx,int sy,int fx,int fy,char col)//sx,sy为当前棋子坐标,fx,fy为指定位置坐标,col为当前棋子颜色 { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[4]={ 1,1,-1,-1},dy[4]={ 1,-1,1,-1}; for(int i=0; i<4; i++)//枚举出当前 士 可以到达的坐标 {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }

  • 象:
这里要注意挡象脚的情况
bool Xgo(int sx,int sy,int fx,int fy,char col)//sx,sy为当前棋子坐标,fx,fy为指定位置坐标,col为当前棋子颜色 { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int zx[4]={ 1,-1,-1,1},zy[4]={ -1,-1,1,1}; //会挡住当前位置象脚的位置 const int dx[4]={ 2,-2,-2,2},dy[4]={ -2,-2,2,2}; //象可以到达的位置 for(int i=0; i<4; i++) {int vx=sx+zx[i],vy=sy+zy[i],nx=sx+dx[i],ny=sy+dy[i]; //vx,vy是挡象脚的位置,nx,ny是可到达位置 if(nx<0||nx>9||ny<0||ny>8) continue; if(map[vx][vy]!=' ') continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }

  • 马:
bool Mgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 int zx[4]={ 1,0,-1,0},zy[4]={ 0,1,0,-1}; //会挡住马脚的位置坐标 int dx[2][4]={ 2,-1,-2,1, 2,1,-2,-1}; int dy[2][4]={ 1,2,-1,-2, -1,2,1,-2}; //马可以走到的八个方向 for(int i=0; i<4; i++) {int vx=sx+zx[i],vy=sy+zy[i]; //挡马脚的位置 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; for(int j=0; j<=1; j++) {int nx=sx+dx[j][i],ny=sy+dy[j][i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } } return false; }

  • 车:
bool Cgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(sx!=fx&&sy!=fy) return false; //如果当前位置和目标位置根本不在同行同列,那么不可能去到 if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; int hx=sx-1,lx=sx+1,ly=sy-1,ry=sy+1; bool hx_,lx_,ly_,ry_; hx_=lx_=ly_=ry_=true; //判断在这条路上是否已经存在障碍物阻挡情况 while(hx_||lx_||ly_||ry_) {if(sy==fy&&hx==fx&&hx_) return true; if(sy==fy&&lx==fx&&lx_) return true; if(sx==fx&&ly==fy&&ly_) return true; if(sx==fx&&ry==fy&&ry_) return true; if(map[sx][ry]=='W'&&color[sx][ry]!=col) boom=true; if(map[sx][ly]=='W'&&color[sx][ly]!=col) boom=true; if(map[lx][sy]=='W'&&color[lx][sy]!=col) boom=true; if(map[hx][sy]=='W'&&color[hx][sy]!=col) boom=true; //要在判断是否为目标点之后才判断障碍物情况 if(hx<0||map[hx][sy]!=' ') hx_=false; if(ly<0||map[sx][ly]!=' ') ly_=false; if(lx>9||map[lx][sy]!=' ') lx_=false; if(ry>8||map[sx][ry]!=' ') ry_=false; if(hx_) hx--; if(ly_) ly--; if(lx_) lx++; if(ry_) ry++; } return false; }

  • 鸭:
bool Ygo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int zx1[4]={ 1,0,-1,0},zy1[4]={ 0,1,0,-1}; //当前位置周围会挡住鸭脚的坐标 const int zx2[2][4]={ 2,-1,-2,1, 2,1,-2,-1}; const int zy2[2][4]={ 1,2,-1,-2, -1,2,1,-2}; //当前位置日字周围会挡住鸭脚的坐标 const int dx[2][4]={ 3,-2,-3,2, 3,2,-3,-2}; const int dy[2][4]={ 2,3,-2,-3, -2,3,2,-3}; //鸭子可以到达的位置 for(int i=0; i<4; i++) {int vx=sx+zx1[i],vy=sy+zy1[i]; //第一个挡鸭脚的地方 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; for(int j=0; j<=1; j++) {vx=sx+zx2[j][i],vy=sy+zy2[j][i]; //第二个挡鸭脚的地方 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; int nx=sx+dx[j][i],ny=sy+dy[j][i]; //可以走到的位置 if(nx<0||nx>9||ny<0||ny>8) continue; if(nx==fx&&ny==fy) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } } return false; }

  • 兵:
bool Bgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[8]={ 1,-1,0,0,1,1,-1,-1}; //兵可以走的八大方向 const int dy[8]={ 0,0,1,-1,-1,1,1,-1}; for(int i=0; i<8; i++) {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(nx==fx&&ny==fy) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }

然后处理第二个问题,是否会被将军:
其实就是便利整个棋盘,看看棋子中的合法移动方案是否会吃掉对方的王
void jiangjun() { int x,y; for(x=0; x<10; x++) for(y=0; y<9; y++) if(map[x][y]!=' ') {boom=false; if(map[x][y]=='W') Wgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='S') Sgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='X') Xgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='C') Cgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='M') Mgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='B') Bgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='Y') Ygo(x,y,-1,-1,color[x][y]); if(boom) {if(gameover==0) cout<<"yes; "; return ; } } cout<<"no; "; }

其余的问题都很简单,这里就不在赘述了。
CODE:
#include #include using namespace std; char map[10][9]={ 'C','M','X','S','W','S','X','M','C', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'Y',' ',' ',' ',' ',' ',' ',' ','Y', 'B',' ','B',' ','B',' ','B',' ','B', ' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B',' ','B',' ','B',' ','B',' ','B', 'Y',' ',' ',' ',' ',' ',' ',' ','Y', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'C','M','X','S','W','S','X','M','C'}; //棋盘初始布局:C车,M马,X象,S士,W王,Y鸭,B兵char color[10][9]={ 'R','R','R','R','R','R','R','R','R', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'R',' ',' ',' ',' ',' ',' ',' ','R', 'R',' ','R',' ','R',' ','R',' ','R', ' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B',' ','B',' ','B',' ','B',' ','B', 'B',' ',' ',' ',' ',' ',' ',' ','B', ' ',' ',' ',' ',' ',' ',' ',' ',' ', 'B','B','B','B','B','B','B','B','B'}; //棋盘初始颜色布局:R红,B蓝 string name[26]={ "","soldier","car","","","","","","","","","","horse","","","","","","guard","","","","captain","elephant","duck",""}; //将所有棋子的名称存起来 bool boom=false; // 判断是否将军 int gameover=0; // 判断游戏是否结束 ,未结束为0,完成终结操作为1,已结束为2 char Color='R'; // 回合颜色存储 int n,SX,SY,FX,FY; //Wgo 判断 王 是否能走到当前指定位置 //Sgo 判断 士 是否能走到当前指定位置 //Xgo 判断 象 是否能走到当前指定位置 //Mgo 判断 马 是否能走到当前指定位置 //Cgo 判断 车 是否能走到当前指定位置 //Ygo 判断 鸭 是否能走到当前指定位置 //Bgo 判断 兵 是否能走到当前指定位置 //getout 将棋子移动 //change 回合颜色轮换 //jiangjun 判断是否存在将军局面 void getout(int sx,int sy,int fx,int fy) {if(map[fx][fy]!=' ') {if(color[fx][fy]=='R') cout<<"red "; else cout<<"blue "; cout<=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[4]={ 0,0,-1,1},dy[4]={ -1,1,0,0}; for(int i=0; i<4; i++)//枚举出当前 王 可以到达的坐标 {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; } bool Sgo(int sx,int sy,int fx,int fy,char col)//sx,sy为当前棋子坐标,fx,fy为指定位置坐标,col为当前棋子颜色 { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[4]={ 1,1,-1,-1},dy[4]={ 1,-1,1,-1}; for(int i=0; i<4; i++)//枚举出当前 士 可以到达的坐标 {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }bool Xgo(int sx,int sy,int fx,int fy,char col)//sx,sy为当前棋子坐标,fx,fy为指定位置坐标,col为当前棋子颜色 { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int zx[4]={ 1,-1,-1,1},zy[4]={ -1,-1,1,1}; //会挡住当前位置象脚的位置 const int dx[4]={ 2,-2,-2,2},dy[4]={ -2,-2,2,2}; //象可以到达的位置 for(int i=0; i<4; i++) {int vx=sx+zx[i],vy=sy+zy[i],nx=sx+dx[i],ny=sy+dy[i]; //vx,vy是挡象脚的位置,nx,ny是可到达位置 if(nx<0||nx>9||ny<0||ny>8) continue; if(map[vx][vy]!=' ') continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }bool Mgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 int zx[4]={ 1,0,-1,0},zy[4]={ 0,1,0,-1}; //会挡住马脚的位置坐标 int dx[2][4]={ 2,-1,-2,1, 2,1,-2,-1}; int dy[2][4]={ 1,2,-1,-2, -1,2,1,-2}; //马可以走到的八个方向 for(int i=0; i<4; i++) {int vx=sx+zx[i],vy=sy+zy[i]; //挡马脚的位置 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; for(int j=0; j<=1; j++) {int nx=sx+dx[j][i],ny=sy+dy[j][i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(fx==nx&&fy==ny) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } } return false; }bool Cgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(sx!=fx&&sy!=fy) return false; //如果当前位置和目标位置根本不在同行同列,那么不可能去到 if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; int hx=sx-1,lx=sx+1,ly=sy-1,ry=sy+1; bool hx_,lx_,ly_,ry_; hx_=lx_=ly_=ry_=true; //判断在这条路上是否已经存在障碍物阻挡情况 while(hx_||lx_||ly_||ry_) {if(sy==fy&&hx==fx&&hx_) return true; if(sy==fy&&lx==fx&&lx_) return true; if(sx==fx&&ly==fy&&ly_) return true; if(sx==fx&&ry==fy&&ry_) return true; if(map[sx][ry]=='W'&&color[sx][ry]!=col) boom=true; if(map[sx][ly]=='W'&&color[sx][ly]!=col) boom=true; if(map[lx][sy]=='W'&&color[lx][sy]!=col) boom=true; if(map[hx][sy]=='W'&&color[hx][sy]!=col) boom=true; //要在判断是否为目标点之后才判断障碍物情况 if(hx<0||map[hx][sy]!=' ') hx_=false; if(ly<0||map[sx][ly]!=' ') ly_=false; if(lx>9||map[lx][sy]!=' ') lx_=false; if(ry>8||map[sx][ry]!=' ') ry_=false; if(hx_) hx--; if(ly_) ly--; if(lx_) lx++; if(ry_) ry++; } return false; }bool Ygo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int zx1[4]={ 1,0,-1,0},zy1[4]={ 0,1,0,-1}; //当前位置周围会挡住鸭脚的坐标 const int zx2[2][4]={ 2,-1,-2,1, 2,1,-2,-1}; const int zy2[2][4]={ 1,2,-1,-2, -1,2,1,-2}; //当前位置日字周围会挡住鸭脚的坐标 const int dx[2][4]={ 3,-2,-3,2, 3,2,-3,-2}; const int dy[2][4]={ 2,3,-2,-3, -2,3,2,-3}; //鸭子可以到达的位置 for(int i=0; i<4; i++) {int vx=sx+zx1[i],vy=sy+zy1[i]; //第一个挡鸭脚的地方 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; for(int j=0; j<=1; j++) {vx=sx+zx2[j][i],vy=sy+zy2[j][i]; //第二个挡鸭脚的地方 if(vx<0||vx>9||vy<0||vy>8) continue; if(map[vx][vy]!=' ') continue; int nx=sx+dx[j][i],ny=sy+dy[j][i]; //可以走到的位置 if(nx<0||nx>9||ny<0||ny>8) continue; if(nx==fx&&ny==fy) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } } return false; }bool Bgo(int sx,int sy,int fx,int fy,char col) { if(fx>=0&&fx<=9&&fy>=0&&fy<=8) if(map[fx][fy]!=' '&&color[fx][fy]==col) return false; //如果目标位置是自己的棋,那么就过不去 const int dx[8]={ 1,-1,0,0,1,1,-1,-1}; //兵可以走的八大方向 const int dy[8]={ 0,0,1,-1,-1,1,1,-1}; for(int i=0; i<8; i++) {int nx=sx+dx[i],ny=sy+dy[i]; if(nx<0||nx>9||ny<0||ny>8) continue; if(nx==fx&&ny==fy) return true; if(map[nx][ny]=='W'&&color[nx][ny]!=col) boom=true; } return false; }void jiangjun() { int x,y; for(x=0; x<10; x++) for(y=0; y<9; y++) if(map[x][y]!=' ') {boom=false; if(map[x][y]=='W') Wgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='S') Sgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='X') Xgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='C') Cgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='M') Mgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='B') Bgo(x,y,-1,-1,color[x][y]); if(map[x][y]=='Y') Ygo(x,y,-1,-1,color[x][y]); if(boom) {if(gameover==0) cout<<"yes; "; return ; } } cout<<"no; "; }int main() { cin>>n; for(int i=1; i<=n; i++) {cin>>SX>>SY>>FX>>FY; if(color[SX][SY]!=Color)//判断当前移动的棋子是否属于当前回合的颜色 {cout<<"Invalid command"<1||SX<0||SX>9||SY<0||SY>8||FX<0||FX>9||FY<0||FY>8)//如果目标位置就是当前位置,则为不移动,因此不合法 ,如果游戏已结束,那么不存在操作 {cout<<"Invalid command"<

    推荐阅读