基于深度优先搜索的围棋问题

下围棋
【问题描述】
小明是一个围棋高手,他在与任何人下棋时都能保持极高的胜率(大概百分之百吧)。当然高手也有烦恼,小明觉得每次落子以后查看自己是否赢(或者自己自杀了呵呵呵),都非常的麻烦,于是乎他找到了机智的你。
他现在处在一个棋局中,并且决定了他下一步的位置!现在他请你帮忙判断他的此次落子后棋局出现了什么变化。
【输入格式】
第1到9行是一个棋局,每一行有9个字符,分别用’.’、’O’、’X’来表示空白的位置、白色棋子、黑色棋子。
紧接一行为下一次落子位置x,y,chess,分别为x,y坐标与棋子颜色(颜色与棋盘表示方式相同)0<=x,y<=8。
【输出格式】
输出仅包含一行,如果小明落子后吃掉了对方,则输出”K.O.”;如果小明”自杀”了,则输出”Suicide”;如果没有吃子,则输出”Safe”。注意每次输出后需要换行。
【数据保证】
输入棋局均为合法字符,且为合法棋局。落子位置一定合法。
【输入样例】
这里写图片描述
这里写图片描述
注:此题用的深搜,搜的并非传统意义上的输赢,而是一步后的相关处理。
解析:
想要判断结果是K.O. 还是Suicide抑或Safe,就要知道他们的判断先后顺序—–这至关重要。我们不妨拿一种情况举例:
。。。。。。。。。
。。。。。。。。。
。。。 O。。。。。
。。O 。 O 。 。 。
。。X O X 。。。。
。。。X 。。。。。
。。。。。。。。。
。。。。。。。。。
。。。。。。。。。
3 3 X
此时应该为X棋子取胜,但是如果先判断是否自杀(Suicide),就应该是O棋KO了X棋—–这显然不是我们想要的。因此,我们判断的顺序应该是:先判断是否吃子(KO),再判断是否自杀(Suicide),最后,如果两种情况都不满足,那显然就是Safe了!

知道了这一点之后,我们再来分别分析三种情况:
1.是否KO对方:
我们可以把KO对方这一情况理解为:对于所有落点位置周围四个方向的棋子,只要有任何一个位置为对方棋子,那么则对该棋子进行有无气的检测**(DFS(x,y,op)来实现),加设全局变量flag并对其初始化为0,如果在DFS函数里得到 有气 这一状态,就让flag变为1,因为这样代表对方的一片棋子没有了气,这便可知己方KO了对手。
代码如下:**

void isEat(char ch, char op)
{
    //想要判断是否KO对手,只需要判断周围是否有对方子没有气
    //分别判断四个方向
    int cnt=0;
    flag = 0;
    if (boundary[m - 1][n] == op) {
        DFS(m - 1, n, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m + 1][n] == op) {
        DFS(m + 1, n, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m][n - 1] == op) {
        DFS(m, n - 1, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m][n + 1] == op) {
        DFS(m, n + 1, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (cnt!=0) {
        printf("K.O.");system("pause");
        exit(0);
    }
}

2.是否自杀(Suicide):
想要判断是否KO对方,需要给出的对方棋子的的符号(O或者X)来判断对方是否有气,而想要判断是否自杀,则只需要判断自己是否有气。
代码实现:

void isSuicide(char ch)
{
    memset(visit, 0, sizeof(visit));
    //判断是否自杀,只需要判断自身是否没有气
    flag = 0;
    DFS(m, n, ch);
    if (!flag) {
        printf("Suicide");
        system("pause");
        exit(0);
    }
}

3.是否安全(Safe):
判断了前面的两种情况之后,第三种情况只需要一个else便可以实现,因为我在前面两个函数中,使他们如果满足条件就直接exit (0),因此便有了下面的代码:

    //下面判断是否吃子
    isEat(ch,op);
    isSuicide(ch);
    //过滤掉两种情况后自然是Safe
    printf("Safe");
    system("pause");
    return 0;

———————————————————–以下是BFS函数的实现—————————————————————–

这里采用深度优先搜索的方法来搜索出指定点周围空格(也就是气)的是否存在,默认气不存在(flag=0),如果存在,则flag=1;
这里将已走过的点从0变为1用来记录,防止反复走重复的地方;

    visit[x][y] = 1;//走过变为1

递归不会无休止的进行,因此我们假定围棋棋盘有一圈额外的边界,一旦到达边界即停止搜索。满足以下条件即可return ,
1.到达边界

if (x == 0 || x == N - 1 || y == 0 || y == N - 1) return;

2.搜索到对方的子(此时便没有必要再进行搜索了)return;
3.搜索到空格(气),此时将flag标记为1,证明有气,return。

此时核心部分都已完成,完整代码如下(编译环境VS 2017)

#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#define N 11
char boundary[N][N];
int m, n,flag;
int visit[N][N];    //boundary用来存储棋局,visit用来存储移动操作(若已移动过的位置置1,否则为0代表可移动)
void DFS(int x, int y, char c);
void init_boundary(char str[N][N]);
void isEat(char ch, char op);
void isSuicide(char ch);
int main()
{
    char ch, str[N][N];
    char op; //相反子,若ch为O则op为X
    int i,j;
    init_boundary(str);
    fflush(stdin);
    scanf("%d %d %c", &m, &n, &ch);
    m++;
    n++;
    boundary[m][n] = ch;
    memset(visit, 0, sizeof(visit));//先将visit全部初始化为0,走过的地方变为1以记录
    ch == 'O' ? op = 'X' : op = 'O';
    for (i = 1;i <= N - 2;i++) {
        printf("\n");
        for (j = 1;j <= N - 2;j++)
            printf("%c ", boundary[i][j]);
    }
    //下面判断是否吃子
    isEat(ch,op);
    isSuicide(ch);
    //过滤掉两种情况后自然是Safe
    printf("Safe");
    system("pause");
    return 0;
}
void init_boundary(char str[N][N])
{
    int i, j;
    for (i = 1;i <= N - 2;i++)
    {
        for (j = 1;j <= N - 2;j++)
            boundary[i][j]=getchar();
        getchar();
    }
}
void isEat(char ch, char op)
{
    //想要判断是否KO对手,只需要判断周围是否有对方子没有气
    //分别判断四个方向
    int cnt=0;
    flag = 0;
    if (boundary[m - 1][n] == op) {
        DFS(m - 1, n, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m + 1][n] == op) {
        DFS(m + 1, n, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m][n - 1] == op) {
        DFS(m, n - 1, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (boundary[m][n + 1] == op) {
        DFS(m, n + 1, op);if (flag==0) cnt ++;
    }
    flag = 0;
    if (cnt!=0) {
        printf("K.O.");system("pause");
        exit(0);
    }
}
void isSuicide(char ch)
{
    memset(visit, 0, sizeof(visit));
    //判断是否自杀,只需要判断自身是否没有气
    flag = 0;
    DFS(m, n, ch);
    if (!flag) {
        printf("Suicide");
        system("pause");
        exit(0);
    }
}
void DFS(int x, int y, char c)
{
    visit[x][y] = 1;//走过变为1
    if (x == 0 || x == N - 1 || y == 0 || y == N - 1) return;
    if (boundary[x][y] == c) //如果本次和上次字符相同,则证明还可以深入
    {
        if (visit[x-1][y] == 0 ) DFS(x - 1, y, c);
        if (visit[x+1][y] == 0 ) DFS(x + 1, y, c);
        if (visit[x][y-1] == 0 ) DFS(x, y - 1, c);
        if (visit[x][y+1] == 0 ) DFS(x, y + 1, c);
        return;
    }
    else if (boundary[x][y] == '.') {
        flag = 1;
        return;
    }
    else
        return;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值