P5380 [THUPC2019]鸭棋 做题记录
文章背景
“快过年了,给大家A个水题庆祝一下” ——2022.1.26
于是,在小半个下午的码代码和一个上午的debug后,有了这篇文章
题目大意
有一个神奇的游戏鸭棋,类似中国象棋。给出若干条移动规则,判断其是否合法,合法的话输出:移动哪颗子,吃了哪颗子,是否将军,游戏是否结束。
梳理题意
清晰的头脑真的有利于写代码
棋盘与初始布局
棋盘是\(10\times9\)的网格,棋子只能放在网格线交点处,左下角为(0,0),初始布局如下图。
棋子与走子规则
王(captain->king)
由于王(captain)与车(car)的首字母都是c,我用k(king)来代表王。
- 王初始位于\(\color{rgb(255,0,42)}{(0,4)}\)和\(\color{rgb(0,160,232)}{(9,4)}\)处。
- 可到达4个位置:\((x\pm1,y),(x,y\pm1)\)。
士(guard)
- 士初始位于\(\color{rgb(255,0,42)}{(0,3)}、\color{rgb(255,0,42)}{(0,5)}、\color{rgb(0,160,232)}{(9,3)}\)和\(\color{rgb(0,160,232)}{(9,5)}\)处。
- 可到达4个位置:\((x\pm1,y\pm1)\)和\((x\pm1,y\mp1)\)
象(elephant)
- 象初始位于\(\color{rgb(255,0,42)}{(0,2)}、\color{rgb(255,0,42)}{(0,6)}、\color{rgb(0,160,232)}{(9,2)}\)和\(\color{rgb(0,160,232)}{(9,6)}\)处。
- 可到达最多4个位置:\(\forall x_1,y_1\in\left\{1,-1\right\}\),若\((x+x_1,y+y_1)\)上无棋子,则可以到达\((x+2\times x_1,y+2\times y_1)\)
(“田”字格,中心不能有棋子)
(粉色为一种便于理解和记忆的路线)
马(horse)
- 马初始位于\(\color{rgb(255,0,42)}{(0,1)}、\color{rgb(255,0,42)}{(0,7)}、\color{rgb(0,160,232)}{(9,1)}\)和\(\color{rgb(0,160,232)}{(9,7)}\)处。
- 可到达最多8个位置:\(\forall x_1,y_1\in\left\{1,-1\right\}\),若\((x+x_1,y)\)上无棋子,则可以到达\((x+2\times x_1,y+y_1)\);若\((x,y+y_1)\)上无棋子,则可以到达\((x+x_1,y+2\times y_1)\)。
(“日”字格,长边中点不能有棋子)
车(car)
- 车初始位于\(\color{rgb(255,0,42)}{(0,0)}、\color{rgb(255,0,42)}{(0,8)}、\color{rgb(0,160,232)}{(9,0)}\)和\(\color{rgb(0,160,232)}{(9,8)}\)处。
- 在不跨越棋子的条件下,可以到达同行同列的所有格子。
鸭(duck)
- 鸭初始位于\(\color{rgb(255,0,42)}{(2,0)}、\color{rgb(255,0,42)}{(2,8)}、\color{rgb(0,160,232)}{(7,0)}\)和\(\color{rgb(0,160,232)}{(7,8)}\)处。
- 可到达最多8个位置:\(\forall x_1,y_1\in\left\{1,-1\right\}\),若\((x+x_1,y)\)和\((x+2\times x_1,y+y_1)\)上无棋子,则可以到达\((x+3\times x_1,y+2\times y_1)\);若\((x,y+y_1)\)和\((x+x_1,y+2\times y_1)\)上无棋子,则可以到达\((x+2\times x_1,y+3\times y_1)\)。
(“目”字格,长边靠近起始点的三等分点和两短边中点连线靠近终点的三等分点不能有棋子)
兵(soldier)
- 兵初始位于\(\color{rgb(255,0,42)}{(3,p)}、\color{rgb(0,160,232)}{(6,p)}(p=2q,q\in[0,4])\)处。
- 可到达最多8个位置:\((x\pm 1,y)\)、\((x,y\pm1)\)、\((x\pm1,y\pm1)\)及\((x\pm1,y\mp1)\)。
所有棋子
- 不能移到棋盘外;
- 不能移到有己方棋子的格子;
- 可以移到有敌方棋子的格子且该敌方棋子会被吃掉(移出棋盘,不参与后续棋局)。
将军与胜利条件
当有一颗棋子落在能吃掉对方王的位置时,就形成了将军局面。将军局面包括(但不限于):
- 一方将棋子落在能吃掉对方王的位置;
- 己方王被威胁但是不躲避;
- 将王移到会被敌方棋子攻击的位置送死。
将军局面后,若一方不能及时解决,另一方就能用棋子吃掉对方的王,此时吃掉对方王的一方立即宣告胜利,且之后的所有操作无效且这一步结束后不算形成将军局面。
主要思路
一句话:大模拟。
声明:我的做法一定不是最优的,看看就好。
棋盘棋子
我选择了用二维数组来表示棋盘,用字符串表示棋子,其中,第一位'b''r'表示阵营(blue/red),第二位'k''g''e''h''c''d''s'(king/guard/elephant/horse/car/duck/soldier)表示兵种。
char map[15][15][3]={//初始棋盘
{"rc","rh","re","rg","rk","rg","re","rh","rc"},
{"0","0","0","0","0","0","0","0","0"},
{"rd","0","0","0","0","0","0","0","rd"},
{"rs","0","rs","0","rs","0","rs","0","rs"},
{"0","0","0","0","0","0","0","0","0"},
{"0","0","0","0","0","0","0","0","0"},
{"bs","0","bs","0","bs","0","bs","0","bs"},
{"bd","0","0","0","0","0","0","0","bd"},
{"0","0","0","0","0","0","0","0","0"},
{"bc","bh","be","bg","bk","bg","be","bh","bc"}
};
是否合法
如何检验输入的四个参数是否合法?(合法性的名字都是我编的)
操作合法性
不合法情况可能有(不限于):
- 游戏已经结束。
这不难,只要用一个变量判断是否结束即可。
if(gameover){
printf("Invalid command\n");
continue;
}
端点合法性
不合法情况可能有(不限于):
- 初始位置无己方棋子;
- 终点位置有己方棋子;
- 走出棋盘。
对于前两个问题,我们可以先设置变量side表示执子方,开始设为'r'(red),每进行一次合法操作后(不合法操作进行后执子方不变),即:
if(不合法){
对应操作;
}else{
对应操作;
side=(side=='r'?'b':'r');
}
于是,我们通过找起止点的棋子阵营来判断两点是否合法:
bool checkpoint(int xs,int ys,int xt,int yt){//检查输入的两点是否合法
if(!(xs>=0&&xs<=9&&xt>=0&&xt<=9&&ys>=0&&ys<=8&&yt>=0&&yt<=8)) return 0;//是否在棋盘内
if(map[xs][ys][0]!=side||map[xt][yt][0]==side) return 0;//棋是否是己方的,落点是否是己方的
if(xs==xt&&ys==yt) return 0;//原地踏步(写不写没关系)(属于路径不合法)
return 1;
}
…
if(!checkpoint(xs,ys,xt,yt)) {printf("Invalid command\n");continue;}//检查输入的两点是否合法
路径合法性
不合法情况可能有(不限于):
- 移动不符合规则。
对于这种情况,我们只能逐个判断了。
- 对于王,只能上下左右走,故横纵坐标能且只能变化1;
- 对于士,只能斜着走,所以横纵坐标变化量均为1;
- 对于象,横纵坐标变化量均为2,且绊脚的位置刚好是起止点的中点;
- 对于马,横纵坐标之差一个为1,一个为2,分类讨论。且绊脚的地方为长边的中点;
- 对于车,起止点横坐标和纵坐标有一个相等,不等的循环判断中间有没有障碍物;
- 对于鸭,直接暴力分8类讨论;
- 对于兵,相当于王+士。
bool checkpath(int xs,int ys,int xt,int yt){//判断移动路径是否合法
if(map[xs][ys][1]=='k'){//王
if(!(abs(xs-xt)+abs(ys-yt)==1)) return 0;
}else if(map[xs][ys][1]=='g'){//士
if(!(abs(xs-xt)==1&&abs(ys-yt)==1)) return 0;
}else if(map[xs][ys][1]=='e'){//象
if(!(abs(xs-xt)==2&&abs(ys-yt)==2&&map[(xs+xt)/2][(ys+yt)/2][0]=='0')) return 0;
}else if(map[xs][ys][1]=='h'){//马
if(!((abs(xs-xt)==2&&abs(ys-yt)==1&&map[(xs+xt)/2][ys][0]=='0')
||(abs(ys-yt)==2&&abs(xs-xt)==1&&map[xs][(ys+yt)/2][0]=='0'))) return 0;
}else if(map[xs][ys][1]=='c'){//车
if(xs==xt){
if(ys>yt) {for(int i=ys-1;i>yt;i--) {if(map[xs][i][0]!='0') {return 0;}}}
if(ys<yt) {for(int i=ys+1;i<yt;i++) {if(map[xs][i][0]!='0') {return 0;}}}
}else if(ys==yt){
if(xs>xt) {for(int i=xs-1;i>xt;i--) {if(map[i][ys][0]!='0') {return 0;}}}
if(xs<xt) {for(int i=xs+1;i<xt;i++) {if(map[i][ys][0]!='0') {return 0;}}}
}else return 0;
}else if(map[xs][ys][1]=='d'){//鸭
if(!((abs(xs-xt)==2&&abs(ys-yt)==3&&ys<yt
&&map[xs][ys+1][0]=='0'&&map[(xs+xt)/2][ys+2][0]=='0')
||(abs(xs-xt)==2&&abs(ys-yt)==3&&ys>yt
&&map[xs][ys-1][0]=='0'&&map[(xs+xt)/2][ys-2][0]=='0')
||(abs(xs-xt)==3&&abs(ys-yt)==2&&xs<xt
&&map[xs+1][ys][0]=='0'&&map[xs+2][(ys+yt)/2][0]=='0')
||(abs(xs-xt)==3&&abs(ys-yt)==2&&xs>xt
&&map[xs-1][ys][0]=='0'&&map[xs-2][(ys+yt)/2][0]=='0'))) return 0;
}else if(map[xs][ys][1]=='s'){//兵
if(!((abs(xs-xt)==1&&abs(ys-yt)==1)
||(abs(xs-xt)==1&&abs(ys-yt)==0)||(abs(xs-xt)==0&&abs(ys-yt)==1))) return 0;
}
return 1;
}
…
if(!checkpath(xs,ys,xt,yt)) {printf("Invalid command\n");continue;}//判断移动路径是否合法
输出棋子
这个没什么好说的。
前两问在判断合法性后就可以输出了。
void print(int xs,int ys){//输出棋子
if(map[xs][ys][0]=='b') printf("blue ");//从属于哪方
else if(map[xs][ys][0]=='r') printf("red ");
if(map[xs][ys][1]=='k') printf("captain");//兵种
else if(map[xs][ys][1]=='g') printf("guard");
else if(map[xs][ys][1]=='e') printf("elephant");
else if(map[xs][ys][1]=='h') printf("horse");
else if(map[xs][ys][1]=='c') printf("car");
else if(map[xs][ys][1]=='d') printf("duck");
else if(map[xs][ys][1]=='s') printf("soldier");
}
……
print(xs,ys);printf(";");//输出移动棋子
if(map[xt][yt][0]=='0') printf("NA;"); else {print(xt,yt);printf(";");}//输出被吃棋子
移动棋子
在判断将军之前,我们先要把棋子移动。
void move(int xs,int ys,int xt,int yt){//下棋
if(map[xt][yt][1]=='k') {gameover=1;return;}//若王被吃了结束游戏
map[xt][yt][0]=map[xs][ys][0];map[xt][yt][1]=map[xs][ys][1];//终点更新
map[xs][ys][0]='0';map[xs][ys][1]='0';//起点更新
}
……
move(xs,ys,xt,yt);//下棋
判断将军
和判断路径一样,暴力枚举每一个点,若有棋子,暴力枚举所有落点即可。
一定要注意,将军最容易判断错。
bool general(int xs,int ys){//是否将军
if(map[xs][ys][0]!='0'){
if(map[xs][ys][1]=='k'){//王
if((map[xs-1][ys][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys][0])
||(map[xs][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs][ys-1][0])
||(map[xs+1][ys][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys][0])
||(map[xs][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs][ys+1][0])) return 1;
}else if(map[xs][ys][1]=='g'){//士
if((map[xs-1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys-1][0])
||(map[xs+1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys-1][0])
||(map[xs+1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys+1][0])
||(map[xs-1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys+1][0])) return 1;
}else if(map[xs][ys][1]=='e'){//象
if((map[xs+2][ys+2][1]=='k'&&map[xs+1][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys+2][0])
||(map[xs+2][ys-2][1]=='k'&&map[xs+1][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys-2][0])
||(map[xs-2][ys+2][1]=='k'&&map[xs-1][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys+2][0])
||(map[xs-2][ys-2][1]=='k'&&map[xs-1][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys-2][0])) return 1;
}else if(map[xs][ys][1]=='h'){//马
if((map[xs+2][ys+1][1]=='k'&&map[xs+1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys+1][0])
||(map[xs+2][ys-1][1]=='k'&&map[xs+1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys-1][0])
||(map[xs-2][ys+1][1]=='k'&&map[xs-1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys+1][0])
||(map[xs-2][ys-1][1]=='k'&&map[xs-1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys-1][0])
||(map[xs+1][ys-2][1]=='k'&&map[xs][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs+1][ys-2][0])
||(map[xs+1][ys+2][1]=='k'&&map[xs][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs+1][ys+2][0])
||(map[xs-1][ys-2][1]=='k'&&map[xs][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs-1][ys-2][0])
||(map[xs-1][ys+2][1]=='k'&&map[xs][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs-1][ys+2][0]))return 1;
}else if(map[xs][ys][1]=='c'){//车
for(int i=xs-1;i>=0;i--)
if(map[i][ys][0]!='0')
{if(map[i][ys][1]=='k'&&map[xs][ys][0]!=map[i][ys][0]) {return 1;} break;}
for(int i=xs+1;i<=9;i++)
if(map[i][ys][0]!='0')
{if(map[i][ys][1]=='k'&&map[xs][ys][0]!=map[i][ys][0]) {return 1;} break;}
for(int i=ys-1;i>=0;i--)
if(map[xs][i][0]!='0')
{if(map[xs][i][1]=='k'&&map[xs][ys][0]!=map[xs][i][0]) {return 1;} break;}
for(int i=ys+1;i<9;i++)
if(map[xs][i][0]!='0')
{if(map[xs][i][1]=='k'&&map[xs][ys][0]!=map[xs][i][0]) {return 1;} break;}
}else if(map[xs][ys][1]=='d'){//鸭
if((map[xs+3][ys+2][1]=='k'&&map[xs][ys][0]!=map[xs+3][ys+2][0]
&&map[xs+1][ys][0]=='0'&&map[xs+2][ys+1][0]=='0')
||(map[xs+3][ys-2][1]=='k'&&map[xs][ys][0]!=map[xs+3][ys-2][0]
&&map[xs+1][ys][0]=='0'&&map[xs+2][ys-1][0]=='0')
||(map[xs-3][ys+2][1]=='k'&&map[xs][ys][0]!=map[xs-3][ys+2][0]
&&map[xs-1][ys][0]=='0'&&map[xs-2][ys+1][0]=='0')
||(map[xs-3][ys-2][1]=='k'&&map[xs][ys][0]!=map[xs-3][ys-2][0]
&&map[xs-1][ys][0]=='0'&&map[xs-2][ys-1][0]=='0')
||(map[xs+2][ys+3][1]=='k'&&map[xs][ys][0]!=map[xs+2][ys+3][0]
&&map[xs][ys+1][0]=='0'&&map[xs+1][ys+2][0]=='0')
||(map[xs+2][ys-3][1]=='k'&&map[xs][ys][0]!=map[xs+2][ys-3][0]
&&map[xs][ys-1][0]=='0'&&map[xs+1][ys-2][0]=='0')
||(map[xs-2][ys+3][1]=='k'&&map[xs][ys][0]!=map[xs-2][ys+3][0]
&&map[xs][ys+1][0]=='0'&&map[xs-1][ys+2][0]=='0')
||(map[xs-2][ys-3][1]=='k'&&map[xs][ys][0]!=map[xs-2][ys-3][0]
&&map[xs][ys-1][0]=='0'&&map[xs-1][ys-2][0]=='0')) return 1;
}else if(map[xs][ys][1]=='s'){//兵
if((map[xs-1][ys][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys][0])
||(map[xs][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs][ys-1][0])
||(map[xs+1][ys][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys][0])
||(map[xs][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs][ys+1][0])
||(map[xs-1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys-1][0])
||(map[xs+1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys-1][0])
||(map[xs+1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys+1][0])
||(map[xs-1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys+1][0])) return 1;
}
}
return 0;
}
bool genecheck(){
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
if(general(i,j)) {return 1;}
return 0;
}
……
if(genecheck()) {printf("yes;");}//判断是否将军
else printf("no;");
printf("no\n");
完整代码
最后一起来欣赏一下完整代码吧:
#include<iostream>
#include<cstdio>
using namespace std;
char map[15][15][3]={//初始棋盘
{"rc","rh","re","rg","rk","rg","re","rh","rc"},
{"0","0","0","0","0","0","0","0","0"},
{"rd","0","0","0","0","0","0","0","rd"},
{"rs","0","rs","0","rs","0","rs","0","rs"},
{"0","0","0","0","0","0","0","0","0"},
{"0","0","0","0","0","0","0","0","0"},
{"bs","0","bs","0","bs","0","bs","0","bs"},
{"bd","0","0","0","0","0","0","0","bd"},
{"0","0","0","0","0","0","0","0","0"},
{"bc","bh","be","bg","bk","bg","be","bh","bc"}
};
int Q,xs,ys,xt,yt;//步数及其参数
char side;//轮到哪方
bool gameover=0;//是否结束
bool checkpoint(int xs,int ys,int xt,int yt){//检查输入的两点是否合法
if(!(xs>=0&&xs<=9&&xt>=0&&xt<=9&&ys>=0&&ys<=8&&yt>=0&&yt<=8)) return 0;//是否在棋盘内
if(map[xs][ys][0]!=side||map[xt][yt][0]==side) return 0;//棋是否是己方的,落点是否是己方的
if(xs==xt&&ys==yt) return 0;//原地踏步
return 1;
}
int abs(int x) {return x<0?(-x):x;}
bool checkpath(int xs,int ys,int xt,int yt){//判断移动路径是否合法
if(map[xs][ys][1]=='k'){//王
if(!(abs(xs-xt)+abs(ys-yt)==1)) return 0;
}else if(map[xs][ys][1]=='g'){//士
if(!(abs(xs-xt)==1&&abs(ys-yt)==1)) return 0;
}else if(map[xs][ys][1]=='e'){//象
if(!(abs(xs-xt)==2&&abs(ys-yt)==2&&map[(xs+xt)/2][(ys+yt)/2][0]=='0')) return 0;
}else if(map[xs][ys][1]=='h'){//马
if(!((abs(xs-xt)==2&&abs(ys-yt)==1&&map[(xs+xt)/2][ys][0]=='0')
||(abs(ys-yt)==2&&abs(xs-xt)==1&&map[xs][(ys+yt)/2][0]=='0'))) return 0;
}else if(map[xs][ys][1]=='c'){//车
if(xs==xt){
if(ys>yt) {for(int i=ys-1;i>yt;i--) {if(map[xs][i][0]!='0') {return 0;}}}
if(ys<yt) {for(int i=ys+1;i<yt;i++) {if(map[xs][i][0]!='0') {return 0;}}}
}else if(ys==yt){
if(xs>xt) {for(int i=xs-1;i>xt;i--) {if(map[i][ys][0]!='0') {return 0;}}}
if(xs<xt) {for(int i=xs+1;i<xt;i++) {if(map[i][ys][0]!='0') {return 0;}}}
}else return 0;
}else if(map[xs][ys][1]=='d'){//鸭
if(!((abs(xs-xt)==2&&abs(ys-yt)==3&&ys<yt
&&map[xs][ys+1][0]=='0'&&map[(xs+xt)/2][ys+2][0]=='0')
||(abs(xs-xt)==2&&abs(ys-yt)==3&&ys>yt
&&map[xs][ys-1][0]=='0'&&map[(xs+xt)/2][ys-2][0]=='0')
||(abs(xs-xt)==3&&abs(ys-yt)==2&&xs<xt
&&map[xs+1][ys][0]=='0'&&map[xs+2][(ys+yt)/2][0]=='0')
||(abs(xs-xt)==3&&abs(ys-yt)==2&&xs>xt
&&map[xs-1][ys][0]=='0'&&map[xs-2][(ys+yt)/2][0]=='0'))) return 0;
}else if(map[xs][ys][1]=='s'){//兵
if(!((abs(xs-xt)==1&&abs(ys-yt)==1)
||(abs(xs-xt)==1&&abs(ys-yt)==0)||(abs(xs-xt)==0&&abs(ys-yt)==1))) return 0;
}
return 1;
}
void print(int xs,int ys){//输出棋子
if(map[xs][ys][0]=='b') printf("blue ");//从属于哪方
else if(map[xs][ys][0]=='r') printf("red ");
if(map[xs][ys][1]=='k') printf("captain");//兵种
else if(map[xs][ys][1]=='g') printf("guard");
else if(map[xs][ys][1]=='e') printf("elephant");
else if(map[xs][ys][1]=='h') printf("horse");
else if(map[xs][ys][1]=='c') printf("car");
else if(map[xs][ys][1]=='d') printf("duck");
else if(map[xs][ys][1]=='s') printf("soldier");
}
void move(int xs,int ys,int xt,int yt){//下棋
if(map[xt][yt][1]=='k') {gameover=1;return;}//若王被吃了结束游戏
map[xt][yt][0]=map[xs][ys][0];map[xt][yt][1]=map[xs][ys][1];//终点更新
map[xs][ys][0]='0';map[xs][ys][1]='0';//起点更新
}
bool general(int xs,int ys){//是否将军
if(map[xs][ys][0]!='0'){
if(map[xs][ys][1]=='k'){//王
if((map[xs-1][ys][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys][0])
||(map[xs][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs][ys-1][0])
||(map[xs+1][ys][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys][0])
||(map[xs][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs][ys+1][0])) return 1;
}else if(map[xs][ys][1]=='g'){//士
if((map[xs-1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys-1][0])
||(map[xs+1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys-1][0])
||(map[xs+1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys+1][0])
||(map[xs-1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys+1][0])) return 1;
}else if(map[xs][ys][1]=='e'){//象
if((map[xs+2][ys+2][1]=='k'&&map[xs+1][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys+2][0])
||(map[xs+2][ys-2][1]=='k'&&map[xs+1][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys-2][0])
||(map[xs-2][ys+2][1]=='k'&&map[xs-1][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys+2][0])
||(map[xs-2][ys-2][1]=='k'&&map[xs-1][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys-2][0])) return 1;
}else if(map[xs][ys][1]=='h'){//马
if((map[xs+2][ys+1][1]=='k'&&map[xs+1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys+1][0])
||(map[xs+2][ys-1][1]=='k'&&map[xs+1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs+2][ys-1][0])
||(map[xs-2][ys+1][1]=='k'&&map[xs-1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys+1][0])
||(map[xs-2][ys-1][1]=='k'&&map[xs-1][ys][0]=='0'
&&map[xs][ys][0]!=map[xs-2][ys-1][0])
||(map[xs+1][ys-2][1]=='k'&&map[xs][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs+1][ys-2][0])
||(map[xs+1][ys+2][1]=='k'&&map[xs][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs+1][ys+2][0])
||(map[xs-1][ys-2][1]=='k'&&map[xs][ys-1][0]=='0'
&&map[xs][ys][0]!=map[xs-1][ys-2][0])
||(map[xs-1][ys+2][1]=='k'&&map[xs][ys+1][0]=='0'
&&map[xs][ys][0]!=map[xs-1][ys+2][0]))return 1;
}else if(map[xs][ys][1]=='c'){//车
for(int i=xs-1;i>=0;i--)
if(map[i][ys][0]!='0')
{if(map[i][ys][1]=='k'&&map[xs][ys][0]!=map[i][ys][0]) {return 1;} break;}
for(int i=xs+1;i<=9;i++)
if(map[i][ys][0]!='0')
{if(map[i][ys][1]=='k'&&map[xs][ys][0]!=map[i][ys][0]) {return 1;} break;}
for(int i=ys-1;i>=0;i--)
if(map[xs][i][0]!='0')
{if(map[xs][i][1]=='k'&&map[xs][ys][0]!=map[xs][i][0]) {return 1;} break;}
for(int i=ys+1;i<9;i++)
if(map[xs][i][0]!='0')
{if(map[xs][i][1]=='k'&&map[xs][ys][0]!=map[xs][i][0]) {return 1;} break;}
}else if(map[xs][ys][1]=='d'){//鸭
if((map[xs+3][ys+2][1]=='k'&&map[xs][ys][0]!=map[xs+3][ys+2][0]
&&map[xs+1][ys][0]=='0'&&map[xs+2][ys+1][0]=='0')
||(map[xs+3][ys-2][1]=='k'&&map[xs][ys][0]!=map[xs+3][ys-2][0]
&&map[xs+1][ys][0]=='0'&&map[xs+2][ys-1][0]=='0')
||(map[xs-3][ys+2][1]=='k'&&map[xs][ys][0]!=map[xs-3][ys+2][0]
&&map[xs-1][ys][0]=='0'&&map[xs-2][ys+1][0]=='0')
||(map[xs-3][ys-2][1]=='k'&&map[xs][ys][0]!=map[xs-3][ys-2][0]
&&map[xs-1][ys][0]=='0'&&map[xs-2][ys-1][0]=='0')
||(map[xs+2][ys+3][1]=='k'&&map[xs][ys][0]!=map[xs+2][ys+3][0]
&&map[xs][ys+1][0]=='0'&&map[xs+1][ys+2][0]=='0')
||(map[xs+2][ys-3][1]=='k'&&map[xs][ys][0]!=map[xs+2][ys-3][0]
&&map[xs][ys-1][0]=='0'&&map[xs+1][ys-2][0]=='0')
||(map[xs-2][ys+3][1]=='k'&&map[xs][ys][0]!=map[xs-2][ys+3][0]
&&map[xs][ys+1][0]=='0'&&map[xs-1][ys+2][0]=='0')
||(map[xs-2][ys-3][1]=='k'&&map[xs][ys][0]!=map[xs-2][ys-3][0]
&&map[xs][ys-1][0]=='0'&&map[xs-1][ys-2][0]=='0')) return 1;
}else if(map[xs][ys][1]=='s'){//兵
if((map[xs-1][ys][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys][0])
||(map[xs][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs][ys-1][0])
||(map[xs+1][ys][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys][0])
||(map[xs][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs][ys+1][0])
||(map[xs-1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys-1][0])
||(map[xs+1][ys-1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys-1][0])
||(map[xs+1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs+1][ys+1][0])
||(map[xs-1][ys+1][1]=='k'&&map[xs][ys][0]!=map[xs-1][ys+1][0])) return 1;
}
}
return 0;
}
bool genecheck(){
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
if(general(i,j)) {return 1;}
return 0;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d",&Q);
side='r';
while(Q--){
scanf("%d%d%d%d",&xs,&ys,&xt,&yt);
if(gameover) {printf("Invalid command\n");continue;}//是否已(fu)经(yu)结(wan)束(kang)
if(!checkpoint(xs,ys,xt,yt)) {printf("Invalid command\n");continue;}//检查输入的两点是否合法
if(!checkpath(xs,ys,xt,yt)) {printf("Invalid command\n");continue;}//判断移动路径是否合法
print(xs,ys);printf(";");//输出移动棋子
if(map[xt][yt][0]=='0') printf("NA;"); else {print(xt,yt);printf(";");}//输出被吃棋子
move(xs,ys,xt,yt);//下棋
if(gameover) {printf("no;yes\n");continue;}//结束~啦
if(genecheck()) {printf("yes;");}//判断是否将军
else printf("no;");
printf("no\n");
side=(side=='r'?'b':'r');//更换下棋方
}
return 0;
}
告诫后人
自此,我们已经写完了所有代码,下面是我出错的亿些地方:
- 码风好一点,括号记得打,由于压行过度导致只有25分;
- 每次判断将军前记得清空记录的变量,也可以像我一样一气之下把它封装成函数;
- 将军判断到一个后就可以break了(虽然没必要),但是不要像我一样打成了continue;
- 记得写注释,不然自己看不懂自己的代码;
- 一方吃了对方的王(即游戏结束后)后所有的操作都是不合法的;
- 操作不合法执子方不变;
- 各种你想不到的情况都有可能发生,比如王去送死、用自己的棋跘马脚等;
- …………
写在最后
祝大家早日A了这题,新年快乐!