博弈树(C++语言)

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

编写一程序,让计算机和人下棋。当计算机走下一步时,可以根据以下情况决定下一步:

(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)

(a,(b,(x)),(c,(d),(e,(g),(h)),(f)))
1
c
y
1
x
b
y
0
f
n

输出(1)

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

输入(1)

(a,(b,(c,(d),(e)),(f)),(g,(h),(i)),(j,(k,(m),(n),(o),(p,(r))),(x,(y,(z)))))
1
j
y
y
1
b
y
0
k
n

输出(1)

a
b
c
d
e
f
g
h
i
j
k
m
n
o
p
r
x
y
z
Who play first(0: computer; 1: player )?
player:
computer: x
player:
computer: z
Sorry, you lost.
Continue(y/n)?
Who play first(0: computer; 1: player )?
player:
computer: f
Sorry, you lost.
Continue(y/n)?
Who play first(0: computer; 1: player )?
computer: j
player:
computer: m
Sorry, you lost.
Continue(y/n)?

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    char data;
    int height;
    int win = -1;
    vector<int> sons;
};
struct Tree{
    node tnode[10005];
    int tot;
    int root = 0;
    map<int, int> _m;
    map<char, int> _mm;

    void _createTree(char s[], int left, int right, int fa) 
    {
        if(right==left+1)return;
        int now = ++tot;
        tnode[now].data = s[left+1];
        _mm[s[left+1]] = now;
        tnode[fa].sons.push_back(now);
        for(int i=left+2;i<=right-1;){ 
            if(s[i]==','){
                i++;
            }
            else if(s[i]=='('){
                int nxt = _m[i];
                _createTree(s, i, nxt, now);
                i=nxt+1;
            }
        }
    }
    Tree(char s[], int l) 
    {   
        tot = 0;
        if(l==2)return;  
        root = 1;
        stack<int> stk;
        for(int i=0;i<=l-1;i++){
            if(s[i]=='('){
                stk.push(i);
            }
            else if(s[i]==')'){
                _m[stk.top()] = i; 
                stk.pop();
            }
        }
        _createTree(s, 0, l-1, 0);
        InitHeight();
        InitWinNode();
    }
    void _InOrder(int rt)
    {
        printf("%c\n",tnode[rt].data);
        for(auto son:tnode[rt].sons){
            _InOrder(son);
        }
    }
    void InOrder()
    {
        _InOrder(this->root);
        return;
    }
    void InitHeight()
    {   
        _Dfs(root);
        return;
    }   
    int _Dfs(int now){
        if(tnode[now].height)return tnode[now].height;
        if(isLeaf(now))return 0;
        int res = 0;
        for(auto son: tnode[now].sons){
            res = max(res, _Dfs(son)+1);
        }
        return tnode[now].height = res;
    }
    void InitWinNode() 
    {
        _Dfs2(root);
        return;
    }
    int _Dfs2(int now){
        if(tnode[now].win!=-1) return tnode[now].win;
        if(isLeaf(now))return tnode[now].win = 1;
        int win=1;
        for(auto son: tnode[now].sons){
            win&= _Dfs2(son)^1;
        }
        return tnode[now].win = win;
    }
    bool isLeaf(int x){
        if(!tnode[x].sons.size())return 1;
        return 0;
    }
    bool isLegalMove(int now, char nxt){
        for(auto son: tnode[now].sons){
            if(nxt == tnode[son].data)return 1;
        }
        return 0;
    }
    int getIndexByData(char ch){
        if(!_mm.count(ch))return -1;
        return _mm[ch];
    }
    char getDataByIndex(int idx){
        if(idx<=0 || idx>tot)return '0';
        return tnode[idx].data;
    }
    int makeDecision(int now) 
    {
        int winwinwin = -1;
        for(int i=0;i<tnode[now].sons.size();++i){
            int son = tnode[now].sons[i];
            if(tnode[son].win==1){
                if(winwinwin==-1)winwinwin=son;
                else if(tnode[son].height<tnode[winwinwin].height)winwinwin=son;
            }
        }
        if(winwinwin!=-1)return winwinwin;
        int d_son = 0;
        for(int i=1;i<tnode[now].sons.size();++i){
            int son = tnode[now].sons[i];
            if(tnode[son].height>tnode[d_son].height)d_son = son;
        }
        return d_son;
    }
};
char s[10005];
int main(void)
{
    cin>>s;
    Tree T = Tree(s, strlen(s));
    T.InOrder();
    char isContinue;
    int whoIsFirst; 
    // mainloop
    do{
        printf("Who play first(0: computer; 1: player )?\n");
        cin >> whoIsFirst;
        int whoIsCur = whoIsFirst;
        int nowPlace = T.root;

        while(1){
            if(T.isLeaf(nowPlace)){
                if(whoIsCur){
                    printf("Sorry, you lost.\n");
                    break;
                }
                else {
                    printf("Congratulate, you win.\n");
                    break;
                }
            }
            
            if(whoIsCur){
                while(1){
                    printf("player:\n");
                    char nxt;
                    cin >> nxt;
                    if(T.isLegalMove(nowPlace, nxt)){
                        nowPlace = T.getIndexByData(nxt);
                        break;
                    }
                    printf("illegal move.\n");
                }
            }
            else{
                int nxtPlace = T.makeDecision(nowPlace);
                printf("computer: %c\n",T.getDataByIndex(nxtPlace));
                nowPlace = nxtPlace;
            }

            whoIsCur^=1;
        }   

        printf("Continue(y/n)?\n");
        cin >> isContinue;
    }while(isContinue=='y');
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值