算法习题---4-3黑白棋(UVa220)
一:题目
系统提示当前旗手W/B(白/黑)下子,例如W下子,那么W下的位置必须是夹住黑色棋子的位置才可以。
夹住方式:横向、竖向、斜向
注意落子后将夹住的黑棋吞噬变为白棋
(一)题目详解
1.棋盘以数组表示,“W”表示白子,“B”表示黑子,“-”表示空格
2.棋盘大小8行8列
(二)样例输入
2 //第一行是游戏局数 -------- //开始输入棋盘 -------- -------- ---WB--- ---BW--- -------- -------- -------- W //棋盘后,直接输入当前旗手 L //L是提示命令,如果当前有位置可以下子,则提示(3,5) (4,6) (5,3) (6,4) <前面是可以走的坐标>,如果没有位置可以走,提示No legal move. 则轮到对方黑棋下子。 M35 //M是下子命令,35表示落子在3行5列,落子后显示当前棋盘剩余棋子数 Black - 1 White - 4 L Q //Q是退出命令,退出时将当前棋盘数据打印 WWWWB--- WWWB---- WWB----- WB------ -------- -------- -------- -------- B L M25 L Q
(三)样例输出
(3,5) (4,6) (5,3) (6,4) //对于L提示命令 Black - 1 White - 4 //对于M35落子命令,提示棋盘当前棋子数 (3,4) (3,6) (5,6) //对于L提示命令 -------- //对于Q退出命令,打印棋盘 -------- ----W--- ---WW--- ---BW--- -------- -------- -------- No legal move. Black - 3 White - 12 (3,5) WWWWB--- WWWWW--- WWB----- WB------ -------- -------- -------- --------
二:代码实现
(一)第一版本:400+行,但是解析详细
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 8 char QP[N+1][N+1]; //棋盘信息 char player; //旗手信息 char OP; //对手信息 bool Oper[90]; //获取操作数据
信息获取和展示
//获取棋盘信息、旗手信息 void getQPInfo() { //获取棋盘信息 for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) scanf("%c", &QP[i][j]); getchar(); } //获取旗手信息、对手信息 scanf("%c", &player); while (player=='\n') scanf("%c", &player); player == 'W' ? OP = 'B' : OP = 'W'; getchar(); } //打印棋盘信息 void showQPInfo() { for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) printf("%c", QP[i][j]); printf("\n"); } } //打印可以走的步数 void printDataOper() { for (int i = 11; i <= 88; i++) if (Oper[i]) printf("(%d,%d) ", i / 10, i % 10); printf("\n"); } //打印棋子数目 void printNumber() { int w = 0, b = 0; for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) if (QP[i][j] == 'W') w++; else if (QP[i][j] == 'B') b++; printf("Black - %d White - %d\n", b, w); } //交换旗手位置 void ExchangePlayer() { if (player == 'W') { player = 'B'; OP = 'W'; } else { player = 'W'; OP = 'B'; } }
若是落子后,将夹住的对方棋子同化《版本二简化》
void dealAllOP(int n, int m) { //判断四周是否有对手棋子 int x, y; //先判断左上 x = n-1, y = m-1; if (x >= 1 && y >= 1 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x >= 1 && y >= 1) { x--; y--; } if (x >= 1 && y >= 1 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n - 1, y = m - 1; while (x >= 1 && y >= 1&&QP[x][y]!='-') { QP[x][y] = player; x--; y--; } } } //再判断上方 x = n-1, y = m; if (x >= 1 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x >= 1) { x--; } if (x >= 1 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n - 1, y = m; while (x >= 1 && QP[x][y] != '-') { QP[x][y] = player; x--; } } } //再判断右上 x = n - 1, y = m + 1; if (x >= 1 && y<= 8 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x >= 1 && y <= 8) { x--; y++; } if (x >= 1 && y <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n - 1, y = m + 1; while (x >= 1 && y <= 8 && QP[x][y] != '-') { QP[x][y] = player; x--; y++; } } } //再判断左 y = m - 1,x=n; if (y >= 1 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&y >= 1) { y--; } if (y>=1 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { y = m - 1, x = n; while (y >= 1 && QP[x][y] != '-') { QP[x][y] = player; y--; } } } //再判断右 x = n, y = m+1; if (y <=8 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&y <= 8) { y++; } if (y <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n, y = m + 1; while (y <= 8 && QP[x][y] != '-') { QP[x][y] = player; y++; } } } //再判断左下 x = n + 1, y = m - 1; if (x <= 8 && y >= 1 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x <= 8 && y >= 1) { x++; y--; } if (x <= 8 && y >= 1 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n + 1, y = m - 1; while (x <= 8 && y >= 1 && QP[x][y] != '-') { QP[x][y] = player; x++; y--; } } } //再判断下 x = n + 1, y = m; if (x <= 8 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x <= 8) { x++; } if (x <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n + 1, y = m; while (x <= 8 && QP[x][y] != '-') { QP[x][y] = player; x++; } } } //再判断右下 x = n + 1, y = m + 1; if (x <= 8 && y <= 8 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x <= 8 && y <= 8) { x++; y++; } if (x <= 8 && y <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n + 1, y = m + 1; while (x <= 8 && y <= 8 && QP[x][y] != '-') { QP[x][y] = player; x++; y++; } } } }
判断对方棋子四周8个方向是否可以落子《版本二简化》
bool judgePlayAtSite(int n,int m) { bool flag = false; int x, y; //先判断左上 x = n, y = m; if ((x - 1) >= 1 && (y - 1) >= 1 && QP[x - 1][y - 1] == '-') { //可以落子,判断是否合理 while (QP[x][y]==OP&&x<=8&&y<=8) { x++; y++; } if (x <= 8 && y <= 8&&QP[x][y] == player) //位置合理 落子合理 { Oper[(n-1) * 10 + m-1] = true; flag = true; } } //再判断上方 x = n, y = m; if ((x - 1) >= 1&& QP[x - 1][y] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x <= 8) x++; if (x <= 8 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n - 1) * 10 + m] = true; flag = true; } } //再判断右上 x = n, y = m; if ((x - 1) >= 1 && (y + 1) <= 8 && QP[x - 1][y + 1] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x <= 8 && y >= 1) { x++; y--; } if (x <= 8 && y >= 1 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n-1) * 10 + m+1] = true; flag = true; } } //再判断左 x = n, y = m; if ((y - 1) >= 1 && QP[x][y - 1] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP && y <= 8) { y++; } if (y <= 8 && QP[x][y] == player) //位置合理 落子合理 { Oper[n * 10 + m-1] = true; flag = true; } } //再判断右 x = n, y = m; if ((y + 1) <=8 && QP[x][y + 1] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP && y >= 1) { y--; } if (y >= 1 && QP[x][y] == player) //位置合理 落子合理 { Oper[n * 10 + m+1] = true; flag = true; } } //再判断左下 x = n, y = m; if ((x + 1) <= 8 && (y - 1) >= 1 && QP[x + 1][y - 1] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x >= 1 && y <= 8) { x--; y++; } if (x >= 1 && y <= 8 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n+1) * 10 + m-1] = true; flag = true; } } //再判断下 x = n, y = m; if ((x + 1) <= 8 && QP[x + 1][y] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x >= 1) { x--; } if (x >= 1 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n+1) * 10 + m] = true; flag = true; } } //再判断右下 x = n, y = m; if ((x + 1) <= 8 && (y + 1) <=8 && QP[x + 1][y + 1] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x >=1 && y >= 1) { x--; y--; } if (x >= 1 && y >= 1 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n+1) * 10 + m+1] = true; flag = true; } } return flag; }
判断是否当前旗手是否可以落子
bool judgeRunPlayer() { //初始化步操作 bool flag = false; memset(Oper, false, sizeof(Oper)); //循环棋盘,找到对方棋子,判断对方棋子四周是否可以落子 for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { if (QP[i][j] == OP) //判断四周是否可以落子 if (judgePlayAtSite(i, j)) flag = true; } } //如果步数无效,则调换对手 if (flag == false) ExchangePlayer(); return flag; }
处理命令
void dealCommand() { char comm; int x, y, temp; while (1) { scanf("%c", &comm); switch (comm) { case 'M': //落子 scanf("%d", &temp); x = temp / 10; y = temp % 10; //开始处理棋盘信息 QP[x][y] = player; dealAllOP(x, y); ExchangePlayer(); printNumber(); //输出棋盘棋子数 break; case 'L': //提示信息 //先判断当前旗手是否可以落子 if (judgeRunPlayer()) //打印数据 printDataOper(); else printf("No legal move.\n"); break; case 'Q': //退出游戏、打印棋盘 showQPInfo(); printf("\n"); getchar(); return; } getchar(); } }
主函数
int main() { FILE* fp = freopen("data3.in", "r", stdin); freopen("data3.out", "w", stdout); int num; scanf("%d", &num); getchar(); while (num--) { getQPInfo(); dealCommand(); } freopen("CON", "r", stdin); freopen("CON", "w", stdout); return 0; }
(二)第二版本:200+行,对两处函数进行了修改,含空行和注释
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 8 char QP[N+1][N+1]; //棋盘信息 char player; //旗手信息 char OP; //对手信息 bool Oper[90]; //获取操作数据 //8个方向 左上、上、右上、左、右、左下、下、右下 int x_dir[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; int y_dir[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; //获取棋盘信息、旗手信息 void getQPInfo() { //获取棋盘信息 for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) scanf("%c", &QP[i][j]); getchar(); } //获取旗手信息、对手信息 scanf("%c", &player); while (player=='\n') scanf("%c", &player); player == 'W' ? OP = 'B' : OP = 'W'; getchar(); } //打印棋盘信息 void showQPInfo() { for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) printf("%c", QP[i][j]); printf("\n"); } } //打印可以走的步数 void printDataOper() { for (int i = 11; i <= 88; i++) if (Oper[i]) printf("(%d,%d) ", i / 10, i % 10); printf("\n"); } //打印棋子数目 void printNumber() { int w = 0, b = 0; for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) if (QP[i][j] == 'W') w++; else if (QP[i][j] == 'B') b++; printf("Black - %d White - %d\n", b, w); } //交换旗手位置 void ExchangePlayer() { if (player == 'W') { player = 'B'; OP = 'W'; } else { player = 'W'; OP = 'B'; } } //判断对方四周是否可以落子 bool judgePlayAtSite(int n, int m) { bool flag = false; int x, y; for (int i = 0; i < 8; i++) //循环8个方向 { x = n, y = m; if ((x + x_dir[i]) >= 1 && (x + x_dir[i]) <= 8 && (y + y_dir[i]) >= 1 && (y + y_dir[i]) <= 8 && QP[x + x_dir[i]][y + y_dir[i]] == '-') { //可以落子,判断是否合理 while (QP[x][y] == OP&&x <= 8 && x >= 1 && y <= 8 && y >= 1) { x -= x_dir[i]; y -= y_dir[i]; } if (x <= 8 && x >= 1 && y <= 8 && y >= 1 && QP[x][y] == player) //位置合理 落子合理 { Oper[(n + x_dir[i]) * 10 + m + y_dir[i]] = true; flag = true; } } } return flag; } //将当前落子后的棋子夹住的棋子吞噬 void dealAllOP(int n, int m) { //判断四周是否有对手棋子 int x, y; for (int i = 0; i < 8; i++) { x = n + x_dir[i], y = m + y_dir[i]; if (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] == OP) { //夹住对手 while (QP[x][y] == OP&&x >= 1 && x <= 8 && y >= 1 && y <= 8) { x += x_dir[i]; y += y_dir[i]; } if (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n + x_dir[i], y = m + y_dir[i]; while (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] != '-') { QP[x][y] = player; x += x_dir[i]; y += y_dir[i]; } } } } } //判断是否当前旗手是否可以落子 bool judgeRunPlayer() { //初始化步操作 bool flag = false; memset(Oper, false, sizeof(Oper)); //循环棋盘,找到对方棋子,判断对方棋子四周是否可以落子 for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { if (QP[i][j] == OP) //判断四周是否可以落子 if (judgePlayAtSite(i, j)) flag = true; } } //如果步数无效,则调换对手 if (flag == false) ExchangePlayer(); return flag; } //处理命令 void dealCommand() { char comm; int x, y, temp; while (1) { scanf("%c", &comm); switch (comm) { case 'M': //落子 scanf("%d", &temp); x = temp / 10; y = temp % 10; //开始处理棋盘信息 QP[x][y] = player; dealAllOP(x, y); ExchangePlayer(); printNumber(); //输出棋盘棋子数 break; case 'L': //提示信息 //先判断当前旗手是否可以落子 if (judgeRunPlayer()) //打印数据 printDataOper(); else printf("No legal move.\n"); break; case 'Q': //退出游戏、打印棋盘 showQPInfo(); printf("\n"); getchar(); return; } getchar(); } } //主函数 void main() { FILE* fp = freopen("data3.in", "r", stdin); freopen("data3.out", "w", stdout); int num; scanf("%d", &num); getchar(); while (num--) { getQPInfo(); dealCommand(); } freopen("CON", "r", stdin); freopen("CON", "w", stdout); }
(三)第三版本:100+行,同网上其他形式,去掉注释,进行空行缩减,语句简写
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 8 char QP[N+1][N+1]; //棋盘信息 char player; //旗手信息 char OP; //对手信息 bool Oper[90]; //获取操作数据 int x_dir[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; int y_dir[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; void getQPInfo() { for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) scanf("%c", &QP[i][j]); getchar(); } scanf("%c", &player); while (player == '\n') scanf("%c", &player); player == 'W' ? OP = 'B' : OP = 'W'; getchar(); } void showQPInfo() { for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) printf("%c", QP[i][j]); printf("\n"); } } void printDataOper() { for (int i = 11; i <= 88; i++) if (Oper[i]) printf("(%d,%d) ", i / 10, i % 10); printf("\n"); } void printNumber() { int w = 0, b = 0; for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) if (QP[i][j] == 'W') w++; else if (QP[i][j] == 'B') b++; printf("Black - %d White - %d\n", b, w); } void ExchangePlayer() { if (player == 'W') player = 'B', OP = 'W'; else player = 'W', OP = 'B'; } bool judgePlayAtSite(int n, int m) { bool flag = false; int x, y; for (int i = 0; i < 8; i++) //循环8个方向 { x = n, y = m; if ((x + x_dir[i]) >= 1 && (x + x_dir[i]) <= 8 && (y + y_dir[i]) >= 1 && (y + y_dir[i]) <= 8 && QP[x + x_dir[i]][y + y_dir[i]] == '-') { while (QP[x][y] == OP&&x <= 8 && x >= 1 && y <= 8 && y >= 1) x -= x_dir[i],y -= y_dir[i]; if (x <= 8 && x >= 1 && y <= 8 && y >= 1 && QP[x][y] == player) //位置合理 落子合理 Oper[(n + x_dir[i]) * 10 + m + y_dir[i]] = true,flag = true; } } return flag; } void dealAllOP(int n, int m) { int x, y; for (int i = 0; i < 8; i++) { x = n + x_dir[i], y = m + y_dir[i]; if (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] == OP) { while (QP[x][y] == OP&&x >= 1 && x <= 8 && y >= 1 && y <= 8) x += x_dir[i],y += y_dir[i]; if (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] == player) //对面也是自己棋子,成功夹住,可以吞噬 { x = n + x_dir[i], y = m + y_dir[i]; while (x >= 1 && x <= 8 && y >= 1 && y <= 8 && QP[x][y] != '-') QP[x][y] = player,x += x_dir[i],y += y_dir[i]; } } } } bool judgeRunPlayer() { bool flag = false; memset(Oper, false, sizeof(Oper)); for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) if (QP[i][j] == OP) //判断四周是否可以落子 if (judgePlayAtSite(i, j)) flag = true; } if (flag == false) ExchangePlayer(); return flag; } void dealCommand() { char comm; int x, y, temp; while (1) { scanf("%c", &comm); switch (comm) { case 'M': //落子 scanf("%d", &temp); x = temp / 10, y = temp % 10; QP[x][y] = player; dealAllOP(x, y); ExchangePlayer(); printNumber(); //输出棋盘棋子数 break; case 'L': //提示信息 if (judgeRunPlayer()) printDataOper();//打印数据 else printf("No legal move.\n"); break; case 'Q': //退出游戏、打印棋盘 showQPInfo(); printf("\n"); getchar(); return; } getchar(); } } void main() { FILE* fp = freopen("data3.in", "r", stdin); freopen("data3.out", "w", stdout); int num; scanf("%d", &num); getchar(); while (num--) { getQPInfo(); dealCommand(); } freopen("CON", "r", stdin); freopen("CON", "w", stdout); }