UVa220黑白棋问题

黑白棋问题
原英文题意.

题意翻译

你的任务是模拟黑白棋游戏的进程。黑白棋的规则为:黑白双方轮流放棋子,每次必 须让新放的棋子“夹住”至少一枚对方棋子,然后把所有被新放棋子“夹住”的对方棋子 替换成己方棋子。一段连续(横、竖或者斜向)的同色棋子被“夹住”的条件是两端都是 对方棋子(不能是空位)。如图所示,白棋有6个合法操作,分别为(2,3),(3,3),(3,5),(6,2),(7,3),(7,4)。选择在(7,3)放白棋后变成如图所示效果(注意有竖向和斜向的共两枚黑棋变白)。注意(4,6)的黑色棋子虽然被夹住,但不是被新放的棋子夹住,因此不变白。

输入一个8*8的棋盘以及当前下一次操作的游戏者,处理3种指令:

L指令打印所有合法操作,从左到右的顺序排列(无合法操作时输出No legal move)。

Mrc指令放一枚棋子在(r,c)。如果当前游戏者没有合法操作,则是先切换游戏者再操作。保证输入合法。输出操作后的黑白棋子总数。

Q指令退出游戏,并打印当前棋盘(同输入格式)。

需要注意的问题点:

1、注意题意中不存在合法下棋位置时的操作
2、对与合法位置的判断,尽量保持原意,判断坐标是否在范围内
3、对合法下棋位置的判断:对棋盘上每个可下点,对其8个方向进行扩展判断,判断时带上方向作为参数,这样方便之后进行吃棋时对该方向上的棋进行吃操作
4、获取输入时,如果有多类型输入(单纯字母和字母加数字,可以用数组存储)

具体思路见下面的代码:

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
using namespace std;

typedef pair<int, int> P;

char s[10][10];//棋盘
char c;
int d[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1},
    {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; //可以延伸的八个方向

bool legal(int x, int y)//判断棋子位置是否合法
{
    return 1 <= x && x <= 8 && 1 <= y && y <= 8;
}

char next()//每次行动后更换玩家
{
    return c == 'W' ? 'B' : 'W';
}

bool check_dir(int x, int y, int i) //判断在(x,y)位置处向i方向是否合法
{
    if (s[x][y] != '-') return false;
    int nx = x + d[i][0];
    int ny = y + d[i][1];//延伸
    if (s[nx][ny] != next())
        return false;
    while (true)//不断沿此方向判断是否为敌棋颜色
    {
        nx += d[i][0];
        ny += d[i][1];
        if (s[nx][ny] == c) return true;
        if (s[nx][ny] != next())
            return false;
    }
}
bool can_set(int x, int y)//判断(x,y)能否置子
{
    for (int i = 0; i < 8; i ++) {
        if (check_dir(x, y, i)) {
            return true;
        }
    }
    return false;
}

void set(int x, int y)//下子并从八个方向吃敌棋
{
    for (int i = 0; i < 8; i ++) {
        if (check_dir(x, y, i)) {
            int nx = x+d[i][0], ny = y+d[i][1];
            while (s[nx][ny] == next()) {//不断吃棋,直到遇到非敌棋
                s[nx][ny] = c;
                nx += d[i][0];
                ny += d[i][1];
            }
        }
    }
    s[x][y] = c;
}

P cnt()//数场上的黑白棋数量
{
    P res(0, 0);
    for (int i = 1; i <= 8; i ++) {
        for (int j = 1; j <= 8; j ++) {
            if (s[i][j] == 'B') res.first ++;
            if (s[i][j] == 'W') res.second ++;
        }
    }
    return res;
}

void print_chess()
{
    for (int i = 1; i <= 8; i ++) {
        for (int j = 1; j <= 8; j ++) {
            printf("%c", s[i][j]);
        }
        printf("\n");
    }
}

int main(void)
{
    int kase;
    char op[4];
    cin >> kase;
    for (int t = 1; t <= kase; t++)
    {
        memset(s,'n',sizeof(s));
        for (int i = 1; i <= 8; i ++)
            scanf("%s", s[i]+1);
        scanf("%s", op);
        c = op[0];

        if (t > 1) printf("\n");
        while (scanf("%s", op))
        {
            if (op[0] == 'L')//三种输入,按要求模拟
            {
                bool flag = false;
                bool first = true;
                for (int i = 1; i <= 8; i ++) {
                    for (int j = 1; j <= 8; j ++) {
                        if (can_set(i, j)) {
                            flag = true;
                            if (!first) printf(" ");
                            printf("(%d,%d)", i, j);
                            first = false;
                        }
                    }
                }
                if (flag == false) printf("No legal move.");
                printf("\n");
            }
            else if(op[0] == 'M')
            {
                int x = op[1]-'0', y = op[2]-'0';
                if (can_set(x, y)) { set(x, y);}
                else { c = next(); set(x, y); }
                c = next();
                P num = cnt();
                printf("Black - %2d White - %2d\n", num.first, num.second);
            } 
            else {
                print_chess();
                break;
            }
        }
    }

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值