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 <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);
}

原題

UVa220
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。