下棋属于一种博弈游戏,博弈过程可以用树(博弈树)来表示。假设游戏由两个人( 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;
}