博弈树-BIT

博弈树-BIT

下棋属于一种博弈游戏,博弈过程可以用树(博弈树)来表示。假设游戏由两个人( A 和 B )玩,开始由某个人从根结点开始走,两个人轮流走棋,每次只能走一步, 下一步棋只能选择当前结点的孩子结点,谁先走到叶子结点为胜。例如,对于下图所示的博弈树,若 A 先走,可以选 f , B 若选 h ,则 A 选 j 胜。

tree

编写一程序,让计算机和人下棋。当计算机走下一步时,可以根据以下情况决定下一步:
(1) 若存在可以确保取胜的一个孩子结点,则选择该结点作为下一步;
(2) 若存在多个可以确保取胜的孩子结点,则选择其中高度最小的结点作为下一步(若有多个选择,则选最左边的结点);
(3) 若不存在可以确保取胜的一个孩子结点,则选择高度最大的孩子结点作为下一步(若有多个选择,则选最左边的结点);

例: (下面的黑体为输入)

(a,(b,(x)),(c,(d),(e,(g),(h)),(f)))

a
b
x
c
d
e
g
h
f

Who play first(0: computer; 1: player )?
1
player:
c
computer: d
Sorry, you lost.
Continue(y/n)?
y
Who play first(0: computer; 1: player )?
1
player:
x
illegal move.
player:
b
computer: x
Sorry, you lost.
Continue(y/n)?
y
Who play first(0: computer; 1: player )?
0
computer: c
player:
f
Congratulate, you win.
Continue(y/n)?
n

大体思路:
先根据给出的广义表结构创立广义表,再根据建立的广义表创立树(这里采用了孩子兄弟表示法),关于建立广义表和根据广义表的步骤请参考《数据结构》教材,这里不加赘述。
下棋嘛,就是两个人的事,这里就是人和电脑的事。
人所下的位置是由输入决定的,对它的孩子节点进行遍历就能找到下一个位置,只要处理好非法输入的情况就好了。
而对于电脑,我们就需要做到题目要求的三点,
(1)对于电脑来说,非胜即败,通过预处理让电脑知道哪个点是必胜点,那个点是必败点,清楚了结果之后再 玩游戏,就可以开始“欺负”人类了。(叶子节点是必胜点,它的孩子节点全部为必败点的节点为必胜点,其他节点均视为必败点)
(2)(3)计算节点的高度,必胜点考虑最小高度,必败点考虑最大高度

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>

#define OK 1
#define YES 1
#define NO 0
#define ERROR 0
#define MAX_SIZE 10005

using namespace std;

const int INF = 0x3f3f3f3f;
typedef char ElemType;
typedef char AtomType;
typedef int Status;
typedef long long ll;

typedef enum {ATOM, LIST} ElemTag;
typedef struct GLNode {
    ElemTag tag;
    union {
        AtomType atom;
        struct {struct GLNode *hp, *tp;}ptr;
    };
} * Glist;

typedef struct Tnode{
    ElemType data;
    int status;
    struct Tnode * firstchild, * nextsibling;
} * Tree;

string emp("()");

Status CreateGlist(Glist &L, string s);
Status sever(string &str, string &hstr);
Glist GetHead(Glist L);
Glist GetTail(Glist L);
void CreateTree(Tree &T, Glist L);
Status pre_deal(Tree T);
Status play(Tree T);
int get_height(Tree T);
Status who_play_first();
Status illegal_move();
Tree computer_do(Tree T);
Tree human_do(Tree T);

int main() {

    string s;
    cin >> s;

    int i;
    for(i = 0; s[i] != '\0'; i++) {
        if(s[i] >= 'a' && s[i] <= 'z') printf("%c\n", s[i]);
    }

    Glist L;
    CreateGlist(L, s);

    Tree T;
    CreateTree(T, L);
    pre_deal(T);

    play(T);
    return 0;
}

Status CreateGlist(Glist &L, string s) {  //建立广义表
    if(s == emp) {
        L = NULL;
    }
    else {
        L = new GLNode;
        if(s.length() == 1) {    //原子节点
            L ->tag = ATOM;
            L ->atom = s[0];
        }
        else {    //表结点
            L ->tag = LIST;

            string sub, hsub;
            sub = s.substr(1, s.size() - 2);
            //cout << sub;
            Glist p, q;
            p = L;
            while(!sub.empty()) {
                sever(sub, hsub);    //分离头尾
                //cout << sub << endl;
                //cout << hsub << endl;
                CreateGlist(p ->ptr.hp, hsub);
                q = p;
                if(!sub.empty()) {    //若尾表非空,创建尾表指向以便递归使用
                    p = new GLNode;
                    p ->tag = LIST;
                    q ->ptr.tp = p;
                }
            }
            q ->ptr.tp = NULL;
        }    //else 创建表结点
    }    //else 表不空
    return OK;
}

Status sever(string &str, string &hstr) {  //头尾分离函数(用于建立广义表)

    int i, k = 0;
    int n = str.length();

    char ch = '\0';
    for(i = 0; i < n && (ch != ',' || k != 0); i++) {
        ch = str[i];
        if(ch == '(') {
            k++;
        }
        if(ch == ')') {
            k--;
        }
    }
    if(i < n) {
        hstr = str.substr(0, i - 1);
        str = str.substr(i, n - i);
        //cout << hstr << endl;
        //cout << str << endl;
    }
    else {
        hstr = str;
        str.clear();
    }
    return OK;
}

Glist GetHead(Glist L) {
    if(L) {
        return L ->ptr.hp;
    }
    else {
        return NULL;
    }
}

Glist GetTail(Glist L) {
    if(L) {
        return L ->ptr.tp;
    }
    else {
        return NULL;
    }
}

void CreateTree(Tree &T, Glist L) {  //根据广义表建立树

    if(L) {
        T = new Tnode;
        T ->data = GetHead(L) ->atom;
        T ->firstchild = NULL;
        T ->nextsibling = NULL;

        if(GetTail(L)) {

            Glist h = GetHead(GetTail(L));
            Glist t = GetTail(GetTail(L));
            CreateTree(T ->firstchild, h);
        
            Tnode * p = T ->firstchild;
            while(t) {
                h = GetHead(t);
                t = GetTail(t);
                CreateTree(p ->nextsibling, h);
                p = p ->nextsibling;
            }
        
            p ->nextsibling = NULL;
        }
    }
    else {
        T = NULL;
    }

    return;
}

Status play(Tree T) {
    while(1) {

        who_play_first();

        int player, flag = 0;
        scanf("%d", &player);
        Tree p = T;
        switch(player) {
            case 0:
                p = computer_do(T);
                flag = 0;
                break;
            case 1:
                p = human_do(T);
                flag = 1;
                break;
            default: exit(-1);
        }
        if(p ->firstchild == NULL) {// 本局结束
            if(flag == 0) {
                printf("Sorry,you lost.\n");
            }
            else {
                printf("Congratulate,you win.\n");
            }
            
            printf("Continue(y/n)?\n");
                
            char c;
            getchar();
            scanf("%c", &c);

            if(c == 'y') {
                continue;
            }
            else {
                return OK;
            }
        }
        if(flag == 1 && p != T) {  //下一步电脑
            while(1) {  //循环电脑-人-电脑-人-...
                
                p = computer_do(p);
                if(p ->firstchild == NULL) {
                    printf("Sorry,you lost.\n");
                    printf("Continue(y/n)?\n");
                
                    char c;
                    getchar();
                    scanf("%c", &c);

                    if(c == 'y') {
                        break;
                    }
                    else {
                        return OK;
                    }
                } 
                
                while(1) {  //处理因输入错误而重来的情况
                    Tree q;
                    q = human_do(p);
                    if(q != p) {
                        p = q;
                        break;
                    }
                }
                if(p ->firstchild == NULL) {
                    printf("Congratulate,you win.\n");
                    printf("Continue(y/n)?\n");
                
                    char c;
                    getchar();
                    scanf("%c", &c);

                    if(c == 'y') {
                        break;
                    }
                    else {
                        return OK;
                    }
                } 
            }
        }
        else {  //下一步人
            while(1) {  //思路同上

                while(1) {
                    Tree q;
                    q = human_do(p);
                    if(q != p) {
                        p = q;
                        break;
                    }
                }
                if(p ->firstchild == NULL) {
                    printf("Congratulate,you win.\n");
                    printf("Continue(y/n)?\n");
                
                    char c;
                    getchar();
                    scanf("%c", &c);

                    if(c == 'y') {
                        break;
                    }
                    else {
                        return OK;
                    }
                }

                p = computer_do(p);
                if(p ->firstchild == NULL) {
                    printf("Sorry,you lost.\n");
                    printf("Continue(y/n)?\n");
                
                    char c;
                    getchar();
                    scanf("%c", &c);

                    if(c == 'y') {
                        break;
                    }
                    else {
                        return OK;
                    }
                }
            }
        }
    }
    return OK;
}

Status pre_deal(Tree T) { //预处理

    if(T) {
        if(T ->firstchild == NULL) {
            T ->status = 1;
        }

        pre_deal(T ->firstchild);
        pre_deal(T ->nextsibling);

        Tnode * p = T;
        if(T ->firstchild) {
            p = T ->firstchild;
            int flag = 1;
            while(p) {
                if(p ->status == 1) {
                    flag = 0;
                    break;
                }
                p = p ->nextsibling;
            }
            if(flag) {
                T ->status = 1;
            }
            else {
                T ->status = 0;
            }
        }
    }

    return OK;
}

Status who_play_first() {
    printf("Who play first(0:computer;1:player)?\n");
    return OK;
}

Status illegal_move() {
    printf("illegal move.\n");
    return OK;
}

Tree computer_do(Tree T) {  //电脑进行一轮操作
    int victory_h = INF, false_h = 0;
    Tree p = T, q1, q2;
    if(p ->firstchild) {
        p = p ->firstchild;
        while(p) {
            int h = get_height(p);
            if(p ->status == 1) {
                if(h < victory_h) {
                    victory_h = h;
                    q1 = p;
                }
            }
            else {
                if(h > false_h) {
                    false_h = h;
                    q2 = p;
                }
            }
            p = p ->nextsibling;
        }
        if(victory_h != INF) {
            printf("computer:%c\n", q1 ->data);
            return q1;
        }
        else {
            printf("computer:%c\n", q2 ->data);
            return q2;
        }
    }
    return T;
}

Tree human_do(Tree T) {  //人进行一轮操作

    printf("player:\n");

    char c;
    getchar();
    scanf("%c", &c);

    Tnode * p = T;
    if(p ->firstchild) {
        p = p ->firstchild;
        while(p) {
            if(p ->data == c) {
                break;
            }
            p = p ->nextsibling;
        }
    }
    if(p) {
        return p;
    }
    else {
        illegal_move();
        return T;
    }
}

int get_height(Tree T) {  //计算树的高度
    
    if(T == NULL) return 0;
    else {
        int h, h2;
        h = get_height(T ->firstchild);
        if(h != 0) {
            T = T ->firstchild;
            while(T) {
                h2 = get_height(T ->nextsibling);
                if(h < h2) {
                    h = h2;
                }
                T = T ->nextsibling;
            }
        }
        return h + 1;
    }
}


  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值