UVa220 - Othello(黑白棋)

题目

这条题输入格式要求非常多...很多坑,笔者就在输出格式这搞了很久最终通过网站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 
#include 
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);
}

原题

UVa220

你可能感兴趣的:(UVa220 - Othello(黑白棋))