題目
這條題輸入格式要求非常多...很多坑,筆者就在輸出格式這搞了很久最終通過網站https://cn.vjudge.net debug才發現哪里不對,先提一下。
L輸出的每個坐標間要有空格,但是整行首末都不能有空格;題目與題目之間有空行,且最后一題在輸出棋盤后也有一個空行;M命令輸出的棋數統計的數字占兩格(%2d)。
輸入
輸入包括三部分
第一部分只有一個數字 n,表示下面一共有 n 個題目。
第二部分有 9 行,代表當前棋盤狀態。前八行是 8*8 的棋盤,'-'代表空,'B'代表黑棋,'W'代表白棋。第九行是 'B' 或者 'W' 代表當前玩家。
第三部分是操作命令,有三種:
'L': 輸出當前玩家可放棋的所有位置。column優先升序再到row升序。
'Mij': 當前玩家在 (i,j)下棋子,如果當前玩家沒有可放棋的位置則直接變為對手下這一步棋。下棋之后轉換當前玩家。
'Q': 退出這題。
處理
當放下一個棋子后,若該棋子的水平、垂直 或 對角線方向(共八個方向)滿足有相同顏色的棋子且兩棋子間都是相反顏色的棋子,則把中間的棋子全部變為己方的棋子。要求每次下棋至少有一個棋子被轉換。
解讀
題目主要需要處理的功能有兩個:列出可走的位置 和 下棋。下面進行解析。
列出可走的位置只需傳遞一個參數 player(當前玩家),然后遍歷棋盤所有空格,并判斷該位置能否下棋,能則輸出。所以這里右需要一個函數(check1)。
check1函數需要三個參數:player,x,y。但是判斷一個位置又分八個方向,所以再加一個函數(check2)。遍歷八個方向,有一個方向為真就返回1。
check2函數需要五個參數:player,x,y,dx,dy。其中 dx 和 dy 表示方向,取值 -1,0,1。遍歷該方向,若符合則返回長度。
下棋則需要三個參數,player,x,y。遍歷八個方向,用 check2 返回的長度對該方向遍歷,進行轉換。
代碼
#define maxn 10
#include <stdio.h>
#include <string.h>
char broad[maxn][maxn];
void print() {
for (int i = 1; i <= 8; i++)
printf("%s\n", &broad[i][1]);
}
char readdisk() {
char ch;
while (ch = getchar())
if (ch == '-' || ch == 'W' || ch == 'B') return ch;
}
int list(char &player);
int check(char &player, int x, int y);
int check(char &player, int x, int y, int dx, int dy);
void place(char &player, int x, int y);
void sum();
int main() {
#ifdef TEST
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif // TEST
int n, kase = 0;
scanf("%d", &n);
while (n--) {
if (kase++) putchar('\n');
memset(broad, '\0', sizeof(broad));
for (int i = 1; i <= 8; i++) {
broad[i][1] = readdisk();
for (int j = 2; j <= 8; j++) {
broad[i][j] = getchar();
}
}
char player[2];
scanf("%s", player);
char cmd[5];
while(scanf("%s", cmd) != EOF && cmd[0] != 'Q') {
if (cmd[0] == 'L') list(player[0]);
else if (cmd[0] == 'M') place(player[0], cmd[1] - '0', cmd[2] - '0');
}
print();
}
return 0;
}
int list(char &player) {
int sum = 0, kase = 0;
for (int x = 1; x <= 8; x++) for (int y = 1; y <= 8; y++) {
if (broad[x][y] != '-') continue;
if (check(player, x, y)) {
if (kase++) putchar(' ');
printf("(%d,%d)", x, y), sum++;
}
}
if (sum == 0) printf("No legal move.");
printf("\n");
return sum;
}
int check(char &player, int x, int y) {
for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {
//不遍歷(0,0)方向
if (dx == 0 && dy == 0) continue;
if (check(player, x, y, dx, dy)) return 1;
}
return 0;
}
int check(char &player, int x, int y, int dx, int dy){
int len, flag = 0;
x += dx; y += dy;
//len統計該方向兩棋間長度
for (len = 1; x <= 8 && x >= 1 && y <= 8 && y >= 1; len++) {
if (broad[x][y] == '-') break;
if (broad[x][y] == player) { flag = 1; break; }
x += dx; y += dy;
}
if (len == 1 || flag == 0) return 0;
return len;
}
void place(char &player, int x, int y) {
if (check(player, x, y) == 0) player = (player == 'W' ? 'B' : 'W');
broad[x][y] = player;
for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {
//不遍歷(0,0)方向
if (dx == 0 && dy == 0) continue;
int len = check(player, x, y, dx, dy);
//遍歷兩棋間
for (int i = 1; i < len; i++) broad[x + i * dx][y + i * dy] = player;
}
player = (player == 'W' ? 'B' : 'W');
sum();
}
void sum() {
int sumb = 0, sumw = 0;
for (int x = 1; x <= 8; x++) for (int y = 1; y <= 8; y++) {
if (broad[x][y] == 'W') sumw++;
else if (broad[x][y] == 'B') sumb++;
}
printf("Black - %2d White - %2d\n", sumb, sumw);
}