1. 程式人生 > >少年啊,來一發昆特嗎(四)——AI的編寫

少年啊,來一發昆特嗎(四)——AI的編寫

這類紙牌遊戲的常用演算法通常是博弈樹演算法,具體的博弈樹演算法與A*演算法的思想比較相似,就是對AI的行動有一個評估值,評估值越高,這手牌的打法就最好,評估值要怎麼定,就要看遊戲了,紙牌遊戲的目的很明確就是贏過對手,也就是玩家,那麼對於昆特牌來說估值最高的就是使自己的力量在結束時比玩家的力量高,所以首先需要對整個遊戲中所有紙牌型別做個分類,並給予它們相應的估值,當然越高代表行動越正確

在昆特牌中總共有領導技能,普通單位牌,間諜技能牌,提升力量牌,醫生牌,天氣牌,特殊牌等幾種型別的牌型,接下來就是對這幾種牌型進行評估,

1.首先,對於我自己玩昆特牌的經驗來說,手牌數就是生命,能增加手牌數的一般有間諜,醫生,領導技能,其中間諜和幾個特殊領導技能相當於白抽一張卡,自然權值定到最高。

2.醫生設為稍高,因為醫生要增加手牌數的話必須是墓地中有間諜的情況,不過因為醫生相當於一次出兩張牌,權值也可以稍微定高點。

3.領導技能不會減手牌數量並且相當於放空一回合,但是領導技能可能會對牌的力量值產生影響,所以此時的權值需要對場上力量值進行比對,再定,相當於一個內部比分,如果出牌後力量比玩家大就定位高權值,如果比力量小,就定位低權值。

4.提升力量牌權值比上述3個定位低,也需要對場上的力量進行比對後,定義權值

5.天氣牌,會使某一個攻擊佇列,力量全部變為1,所以也需要判斷後,在賦給權值。

6.特殊牌有誘餌和灼燒,這兩種如果場上有間諜,則誘餌牌可以權值設為最高,沒有則設為低,灼燒,如果場上最高是敵方的牌,則最高,反之,則低。

有了上面這個簡單的分類,接下來的ai編寫就會非常簡便了,也就是對手中的每張牌進行上述的分析,然後選擇拿出權值最高的那組,如果權值相同,就在進行內部判斷,拿出權值最高的,如果手上的權值有一半等於1,則選擇棄權,保留卡牌到下一句,如果是決勝局就死磕,下面是一個簡單的ai分析出牌的原始碼,要增強ai的話,可以考慮在基礎上新增對玩家手卡的分析,通過類似於迷宮尋徑的方式找出權值最高的那條路,因為時間關係,原始碼裡面並沒有做到這個地步

int   *pNum=new   int[enemeyhandarray->count()]; 
int i=0;
//分析完畢後進入出牌判斷
//如果npc近戰力量小於玩家近戰力量,則出冰凍牌
//優先判斷應該出單位卡,還是特殊卡,還是天氣卡
//總和力量值玩家大時
//enemypow>=pow的權值為1,場上牌數量多出一張則權值為2,手牌數量不減少權值為3,手牌數量增加權值為4,pow>enemypow則權值為
Object *item=NULL;
CCARRAY_FOREACH(enemeyhandarray,item){
Dictionary *dic=(Dictionary *)item;
if(((String *)dic->objectForKey("type"))->getCString()!="weather"&&((String *)dic->objectForKey("type"))->getCString()!="special"){
 if(((String *)dic->objectForKey("Ability"))->getCString()=="----"){
               //當無能力時且卡牌為單位卡時,僅加算卡牌力量
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(((String *)dic->objectForKey("type"))->getCString()=="hero"){
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }
 }else {
 if(((String *)dic->objectForKey("attackrange"))->getCString()=="shortrange"){
 if(frostflag==true){
 if(epowerups>=2){
 power=1*2+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=1+(epowerups)*10;
 }else{
 power=1;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }else{
 if(epowerups>=2){
 power=power*2+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=power+(epowerups)*10;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }
 }else if(((String *)dic->objectForKey("attackrange"))->getCString()=="longrange"){
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(fogflag==true){
 if(epowerupl>=2){
 power=1*2+(epowerupl-2)*10;
 }else if(epowerupl>0&&epowerupl<1){
 power=1+(epowerupl)*10;
 }else{
 power=1;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }else{
 if(epowerupl>=2){
 power=power*2+(epowerupl-2)*10;
 }else if(epowerupl>0&&epowerupl<1){
 power=power+(epowerupl)*10;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }
 }else  if(((String *)dic->objectForKey("attackrange"))->getCString()=="shortrange"){
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(frostflag==true){
 if(epowerups>=2){
 power=1*2+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=1+(epowerups)*10;
 }else{
 power=1;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }else{
 if(epowerups>=2){
 power=power*2+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=power+(epowerups)*10;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }
 }else if(((String *)dic->objectForKey("attackrange"))->getCString()=="siegerange"){
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(rainflag==true){
 if(epowerupsiege>=2){
 power=1*2+(epowerupsiege-2)*10;
 }else if(epowerupsiege>0&&epowerupsiege<1){
 power=1+(epowerupsiege)*10;
 }else{
 power=1;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }else{
 if(epowerupsiege>=2){
 power=power*2+(epowerupsiege-2)*10;
 }else if(epowerupsiege>0&&epowerupsiege<1){
 power=power+(epowerupsiege)*10;
 }
 if(enemypow+power>pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }
 }
 }
 }else{
                  //卡牌附加能力時
 //間諜能力時權值+4
 if(((String *)dic->objectForKey("Ability"))->getCString()=="spy"){
 pNum[i]=4;


 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="doctor"){
 pNum[i]=2;


 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="powerup"){
 //只有一張近戰的卡片是力量雙倍
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(frostflag==true){
 if(epowerups>=2){
 power=1*2+(epowerups-2)*10;


 }else if(epowerups>0&&epowerups<1){
 power=1+(epowerups-2)*10+enemyshortpow;
 }else{
 power=1+enemyshortpow;
 }
 if(enemypow+power>=pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }
 }else{
  if(epowerups>=2){
 power=power*2+(epowerups-2)*10;


 }else if(epowerups>0&&epowerups<1){
 power=power+(epowerups-2)*10+enemyshortpow;
 }else{
 power=power+enemyshortpow;
 }
 if(enemypow+power>=pow){
 pNum[i]=1;
 }else{
 pNum[i]=0;
 }


 }
 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="sibling"){
 //如果為團結力量則考慮是否有同名卡,且發動後的力量是否大於pow
  //只有一張近戰的卡片是力量雙倍
 auto power=atoi(((String *)dic->objectForKey("power"))->getCString());
 if(((String *)dic->objectForKey("attackrange"))->getCString()=="shortrange"){
 auto layer=(Layer *)this->getChildByName("enemyshortlayer");
 auto sp=layer->getChildren();
 int Siblingtimes=0;//強化幾次
 for(auto a:sp){
 GWentCard *child=(GWentCard *)a;
 if(((String *)dic->objectForKey("cardname"))->getCString()==child->getCardName()){
 Siblingtimes++;
 }
 }
 //如果強化兩次
 if(Siblingtimes!=0){
 if(frostflag==true){
 if(epowerups>=2){
 power=1*2+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=1+(epowerups)*10;
 }else{
 power=1;
 }
 }else{
 if(epowerups>=2){
 power=(power*2*Siblingtimes*(Siblingtimes+1))*2-(power*2*Siblingtimes)+(epowerups-2)*10;
 }else if(epowerups>0&&epowerups<1){
 power=power*2*Siblingtimes*2+(epowerups)*10;
 }


 }
 


 }
 if(enemypow+power>=pow){
  pNum[i]=1;


 }else{
 pNum[i]=0;


 }
 }else if(((String *)dic->objectForKey("attackrange"))->getCString()=="longrange"){
 auto layer=(Layer *)this->getChildByName("enemylonglayer");
 auto sp=layer->getChildren();
 int Siblingtimes=0;//強化幾次
 for(auto a:sp){
 GWentCard *child=(GWentCard *)a;
 if(((String *)dic->objectForKey("cardname"))->getCString()==child->getCardName()){
 Siblingtimes++;
 }
 }
 //如果強化兩次
 if(Siblingtimes!=0){
 if(fogflag==true){
 if(epowerupl>=2){
 power=1*2+(epowerupl-2)*10;
 }else if(epowerupl>0&&epowerupl<1){
 power=1+(epowerupl)*10;
 }else{
 power=1;
 }
 }else{
 if(epowerupl>=2){
 power=(power*2*Siblingtimes*(Siblingtimes+1))*2-(power*2*Siblingtimes)+(epowerupl-2)*10;
 }else if(epowerupl>0&&epowerupl<1){
 power=power*2*Siblingtimes*2+(epowerups)*10;
 }


 }
 


 }
 if(enemypow+power>=pow){
  pNum[i]=1;


 }else{
 pNum[i]=0;


 }
 }else if(((String *)dic->objectForKey("attackrange"))->getCString()=="siegerange"){
  auto layer=(Layer *)this->getChildByName("enemysiegelayer");
 auto sp=layer->getChildren();
 int Siblingtimes=0;//強化幾次
 for(auto a:sp){
 GWentCard *child=(GWentCard *)a;
 if(((String *)dic->objectForKey("cardname"))->getCString()==child->getCardName()){
 Siblingtimes++;
 }
 }
 //如果強化兩次
 if(Siblingtimes!=0){
 if(rainflag==true){
 if(epowerupsiege>=2){
 power=1*2+(epowerupsiege-2)*10;
 }else if(epowerupsiege>0&&epowerupsiege<1){
 power=1+(epowerupsiege)*10;
 }else{
 power=1;
 }
 }else{
 if(epowerupsiege>=2){
 power=(power*2*Siblingtimes*(Siblingtimes+1))*2-(power*2*Siblingtimes)+(epowerupsiege-2)*10;
 }else if(epowerupsiege>0&&epowerupsiege<1){
 power=power*2*Siblingtimes*2+(epowerupsiege)*10;
 }


 } 
 }
 if(enemypow+power>=pow){
  pNum[i]=1;


 }else{
 pNum[i]=0;


 }


 }
 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="spowerup"){
 //如果為提升士氣,且發動後的力量是否大於pow
 pNum[i]=1;
 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="unit"){
 //如果為提升士氣,且發動後的力量是否大於pow
 pNum[i]=1;
 }else if(((String *)dic->objectForKey("Ability"))->getCString()=="Scorch"){
 //如果為提升士氣,且發動後的力量是否大於pow
 pNum[i]=1;
 }




 }
              


}else{
//如果是天氣牌或者特殊牌
if(((String *)dic->objectForKey("type"))->getCString()=="special"){
//如果是powerup卡牌的話
if(((String *)dic->objectForKey("Ability"))->getCString()=="powerup"){
auto maxPow=enemypow+enemyshortpow;
if(enemypow+enemyshortpow>=pow){
pNum[i]=1;
EnemypowerupRange="shortrange";
}else{
pNum[i]=0;
EnemypowerupRange="shortrange";
}
if(enemypow+enemylongpow>=pow){
if(enemypow+enemylongpow>maxPow){
pNum[i]=1;
   EnemypowerupRange="longrange";
maxPow=enemypow+enemylongpow;
}
}
if(enemypow+enemysiegepow>=pow){
if(enemypow+enemysiegepow>maxPow){
                           pNum[i]=1;
  EnemypowerupRange="siegerange";
}

}
       



}else if(((String *)dic->objectForKey("Ability"))->getCString()=="destroy"){
pNum[i]=1;


}else if(((String *)dic->objectForKey("Ability"))->getCString()=="replace"){
pNum[i]=3;
auto shortlayer=(Layer *)this->getChildByName("enemyshortlayer");
auto longlayer=(Layer *)this->getChildByName("enemylonglayer");
auto siegelayer=(Layer *)this->getChildByName("enemysiegelayer");
Array *all=Array::create();
auto sp=shortlayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
all->addObject(child);
}
sp=longlayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
all->addObject(child);
}
sp=siegelayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
all->addObject(child);
}
               Object *it=NULL;
CCARRAY_FOREACH(all,it){
GWentCard *card=(GWentCard *)it;
if(card->getAbility()=="spy"){
setEnemyReplaced(card);
break;
}else if(card->getAbility()=="doctor"){
setEnemyReplaced(card);
break;
}else if(card->getAbility()=="Scorch"){
setEnemyReplaced(card);
break;
}


}
}
}else if(((String *)dic->objectForKey("type"))->getCString()=="weather"){
if(((String *)dic->objectForKey("cardname"))->getCString()=="Biting-Frost"){
if(frostflag=true){
pNum[i]=0;
}else{
auto layer =(Layer *)this->getChildByName("enemyshortlayer");
auto otherlayer =(Layer *)this->getChildByName("shortlayer");
int epow=0;
int eotherpow=0;
auto sp=layer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
epow=epow+1;


}else{
epow=epow+child->getNewPower();


}


}
sp=otherlayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
eotherpow=eotherpow+1;


}else{
eotherpow=eotherpow+child->getNewPower();


}


}
if(pow-shortpow+eotherpow<=enemypow-enemyshortpow+epow){


pNum[i]=1;
}else{


pNum[i]=0;
}




}


}else if(((String *)dic->objectForKey("cardname"))->getCString()=="impenetrable-fog"){
if(fogflag=true){
pNum[i]=0;
}else{
auto layer =(Layer *)this->getChildByName("enemylonglayer");
auto otherlayer =(Layer *)this->getChildByName("longlayer");
int epow=0;
int eotherpow=0;
auto sp=layer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
epow=epow+1;


}else{
epow=epow+child->getNewPower();


}


}
sp=otherlayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
eotherpow=eotherpow+1;


}else{
eotherpow=eotherpow+child->getNewPower();


}


}
if(pow-longpow+eotherpow<=enemypow-enemylongpow+epow){


pNum[i]=1;
}else{


pNum[i]=0;
}




}




}else if(((String *)dic->objectForKey("cardname"))->getCString()=="Torrential-Rain"){


if(rainflag=true){
pNum[i]=0;
}else{
auto layer =(Layer *)this->getChildByName("enemysiegelayer");
auto otherlayer =(Layer *)this->getChildByName("siegelayer");
int epow=0;
int eotherpow=0;
auto sp=layer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
epow=epow+1;


}else{
epow=epow+child->getNewPower();


}


}
sp=otherlayer->getChildren();
for(auto a:sp){
GWentCard *child=(GWentCard *)a;
if(child->getType()!="hero"&&child->getType()!="special"){
eotherpow=eotherpow+1;


}else{
eotherpow=eotherpow+child->getNewPower();


}


}
if(pow-siegepow+eotherpow<=enemypow-enemysiegepow+epow){


pNum[i]=1;
}else{


pNum[i]=0;
}




}


}else if(((String *)dic->objectForKey("cardname"))->getCString()=="Clear-Weather"){
if(frostflag!=true&&fogflag!=true&&rainflag!=true){
pNum[i]=0;


}else{
pNum[i]=1;


}


}


}
}
i++;


}
int zeronumber=0;//記錄權值為0的操作,如果全為0則棄權
int max=pNum[0];
int outPosition=0;
for(int i=0;i<enemeyhandarray->count();i++){
if(pNum[i]==0){
zeronumber++;


}
if(max<=pNum[i]){
max=pNum[i];
outPosition=i;


}
}
if(qiquanflag==true&&enemypow>pow){
return NULL;
}
if(zeronumber>enemeyhandarray->count()/2){
return NULL;
}
Dictionary *cardDic=(Dictionary *)enemeyhandarray->objectAtIndex(outPosition);
cardDic->retain();
enemeyhandarray->removeObject(cardDic);
GWentCard *card=GWentCard::create(cardDic);
card->setGameMain(this);
card->setBType(3);
card->setScale(0.26);
return card;