题目简单分析
题目的详细内容可以在这个网站上看到,下面简单说明一下题目要求。
[题意]
本题主要任务是模拟黑白棋的过程,黑白棋的规则是一方用自己的棋子夹住对方的棋子,然后就可以把夹住的棋子“吃掉”,从而变为自己的棋子,最终棋子数多的获胜。分析下棋的规则可知,程序的主要任务为下面两点:
①计算棋局中可落子的位置。
②计算落子后棋盘中的棋子的变化。
上图可以看出,白色方在(7,3)位置落子之后,将黑色方(6,3)和(6,4)位置两枚棋子“吃掉”了。
[输入输出]
样例输入输出如下:
输入的格式如图,其中,第一行的2表示测试用例的数量为2;接下来的8行为棋盘,B代笔黑色棋子,W代表白色棋子,-代表该处无子;其他命令的意义如下:
W:表示指定当前执子方为白色方,
L:列出可落子的位置,
M35:指定落子在(3,5)处并在落子之后打印出双方棋子数,
Q:表示打印棋盘并结束。
输出的格式如图所示,注意各例之间用空行隔开。
[分析]
分析黑白棋的规则可知,玩家可以从8个方向“吃掉”对方的棋子,故搜寻可落子时需要考虑八个方向的情况,分别是上、下、左、右、左上、右上、左下、右下。
代码
完整代码如下,用C语言实现,VS2017的工程在github。代码如有bug,敬请指出。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
typedef struct {
int x, y;
int dir[8];
}Move;
Move move[64];
int Nmove = 0;
//上、下、左、右、左上、右上、左下、右下
int dx[8] = { -1,1,0,0,-1,-1,1,1 }, dy[8] = { 0,0,-1,1,-1,1,-1,1 };
int nWhite, nBlack;//黑白棋子数
char board[9 + 1][9 + 1];//多1行/列,防止溢出
char cmd[4], player;//指令最长为3个字符
void exec_cmd();//执行命令
void make_a_move();//下棋
int main() {
int n;
//freopen("data.txt", "r", stdin);
memset(board, 0, sizeof(board));
scanf("%d", &n);
while (n--) {
memset(move, 0, sizeof(move));
if (cmd[0]) printf("\n");//除了第一局之前都加上\n
for (int i = 1; i <= 8; ++i) scanf("%s", &board[i][1]);
do {
scanf("%s", cmd);//读取命令
exec_cmd();//执行命令
} while (cmd[0] != 'Q');
}
//fclose(stdin);
return 0;
}
void find_legal_move();//查找合法位置
void list_legal_move();//列出合法位置
void print_board();//打印棋局
void exec_cmd() {
if (cmd[0] == 'W') player = 1;
else if (cmd[0] == 'B') player = 0;
else if (cmd[0] == 'M') make_a_move();
else if (cmd[0] == 'L') list_legal_move();
else if (cmd[0] == 'Q') print_board();
}
void find_legal_move() {
char mine,rival, flag = 0;
Nmove = 0;//合法点计数
memset(move, 0, sizeof(move));
if (player) mine = 'W',rival='B';
else mine = 'B',rival='W';
for(int i=1;i<=8;++i)//遍历所有位置
for (int j = 1; j <= 8; ++j) {
if (board[i][j] != '-') continue;
flag = 0;
for (int k = 0; k < 8; ++k)//八个方向
if (board[i + dx[k]][j + dy[k]] == rival)
for (int m = i + dx[k], n = j + dy[k]; m > 0 && n > 0 && m < 9 && n < 9; m += dx[k], n += dy[k]) {
if (board[m][n] == '-') break;
if (board[m][n] == mine) {
move[Nmove].dir[k] = 1; flag = 1;
}
}
if (flag) {move[Nmove].x = i; move[Nmove].y = j; Nmove++;}
}
}
void list_legal_move() {
find_legal_move();
if (Nmove == 0) {
printf("No legal move.\n");
return;
}
int i = 0;
for (; i < Nmove-1; ++i) {
printf("(%d,%d) ", move[i].x, move[i].y);
}
printf("(%d,%d)\n", move[i].x, move[i].y);
}
void count();
void make_a_move() {
char mine,rival;//自己-对手
int tempx, tempy;
find_legal_move();
if (Nmove == 0) {
player = 1 - player;
find_legal_move();
}
if (player) mine = 'W', rival = 'B';
else mine = 'B', rival = 'W';
for (int i = 0; i < Nmove; ++i)
if (move[i].x == cmd[1]-'0' && move[i].y == cmd[2]-'0') {
tempx = move[i].x; tempy = move[i].y;
board[tempx][tempy] = mine;
for (int k = 0; k < 8; ++k)
if(move[i].dir[k])
for(int m=tempx+dx[k],n=tempy+dy[k]; m > 0 && n > 0 && m < 9 && n < 9; m += dx[k], n += dy[k])
if (board[m][n] == mine) break;
else board[m][n] = mine;
}
count();
printf("Black -%3d White -%3d\n", nBlack, nWhite);//坑爹的3d
player = 1 - player;
}
void print_board(){
for (int i = 1; i <= 8; ++i) printf("%s\n", &board[i][1]);
}
void count() {
nWhite=0, nBlack=0;
for (int i = 1; i <= 8; ++i)
for (int j = 1; j <= 8; ++j)
if (board[i][j] == 'W') nWhite++;
else if(board[i][j] == 'B') nBlack++;
}