[pukiwiki]
先日 遺伝的プログラミング(GA)の話をちょろっと書きましたけれども、その続き。
DSのドラクエ9面白そうダナー と思いつつも、なんとなく波に乗りそびれた私。Pythonで、モンスターのトーナメント戦をするゲームを作って遊んでみたりしました。文字表示だけですけどね。
[/pukiwiki]
[pukiwiki]
説明
“evolution begin press enter
という表示が出るので Enterキーを押してゲーム開始。
最初の世代のモンスターはランダムに生成
16回 世代交代させて進化させた後、代表一匹をトーナメントで選出。
なんか、大量の文字が表示された後、一時停止。
“old type # 最初の世代
name:tpj power=45 speed=41 defense=61 hp=53
name:xmz power=50 speed=45 defense=53 hp=52
~中略~
name:kgk power=41 speed=55 defense=51 hp=53
new type #進化した個体
name:vrj power=58 speed=37 defense=52 hp=53
今回代表に選ばれたモンスターの名前は 「jqf」
このコ を 1世代目全員と戦わせて勝率を見ます。
“old type vs new type hit enter
再び、Enterキー
” new wins against old 12 / 16
今回は 16戦中 12勝4敗。 そこそこ強いモンスターに進化したみたいです。
—-
プログラム自体の説明を、ほんのちょっとだけ
-GAを使って、合計200ポイントを、モンスターの4つのパラメータに割り振り。
-DNAとして、1と0の数列を使用
-2ビットずつ 0から3の数字をあらわす
-この数字は、攻撃力、スピード、防御力、HPのいずれにポイントを割り振るかを示している。
-2ビット読み込んで数字にデコードしては、どの属性にポイントを割り振るかを決めていく。
-DNAは2*200ビット - 4*2
RPG的バトルだけど、運はパラメータにありません。
ゲームではありますが、DNAで運が決まると、ちょっとアレかな、と思ったので。
関連?
-[[ググる:ティーラ・ブラウン リング・ワールド]]
—-
[/pukiwiki]
以下ソース。 というか、また遊びたくなった時の自分用メモ。
汚くてすんません。
import random pointmax=200 dnamax=pointmax*2-2*4 def random_letter(a=ord("a"),z=ord("z")): return chr(a+random.randint(0,z-a)) class Monster : def __init__(self,dna=None,name=None): if name : self.name=name else : self.name=random_letter()+random_letter()+random_letter() if not dna : self.dna=[ random.randint(0,192)%2 for i in xrange(dnamax)] else : self.dna=dna[:] #print self.dna self.decode_dna() def decode_dna(self): self.power=self.speed=self.defense=self.hp=0 param=[1 for x in range(4)] for i in xrange(0,dnamax,2): amino=self.dna[i]*2+self.dna[i+1] param[amino]+=1 self.power=param[0] self.speed=param[1] self.defense=param[2] self.hp=param[3] if False : print "name:%s power=%s speed=%s defense=%s hp=%s"\ %(self.name,self.power,self.speed,self.defense,self.hp) print "total %s points"%(self.power+self.speed+self.defense+self.hp) def pair(self,monster): dna1,dna2=self.cross(self.dna,monster.dna) dna1=self.mutate(dna1) dna2=self.mutate(dna2) #print return Monster(dna1),Monster(dna2) def __repr__(self): return "name:%s power=%s speed=%s defense=%s hp=%s"\ %(self.name,self.power,self.speed,self.defense,self.hp) def cross(self,dna1,dna2): cross_idx=random.randint(0,10000)%dnamax print "cross",cross_idx dna1b=dna2[:cross_idx] dna2b=dna1[:cross_idx] dna1b+=dna1[cross_idx:] dna2b+=dna2[cross_idx:] return dna1b,dna2b def mutate(self,dna): mutate_idx=random.randint(0,dnamax)-1 if mutate_idx>0: #print "mutate",mutate_idx #print dna dna[mutate_idx]=0 if dna[mutate_idx] else 1 #print dna return dna def copy(self): return Monster(self.dna) class Gameover(Exception): pass class Battle: flag_over="flag over" def __init__(self,mon1,mon2): self.mon_list=[mon1,mon2] self.mon1=mon1.copy() self.mon2=mon2.copy() self.mon1.idx,self.mon2.idx=0,1 self.mon1.hit_ratio=hit_miss_ratio(mon1,mon2) self.mon1.critical_ratio=critical_ratio(mon1,mon2) self.mon2.hit_ratio=hit_miss_ratio(mon2,mon1) self.mon2.critical_ratio=critical_ratio(mon2,mon1) self.mon1.name=mon1.name self.mon2.name=mon2.name def turn (self): mon1,mon2=self.mon1,self.mon2 m1,m2=self.speed() for i in xrange(2): print "atacker : %s"%m1.name hr=hit_miss_ratio(m1,m2) ap=self.damage(m1,m2) if ap<=0: ap=1 hitflag = hr>100.33*random.random()%1.0 if hitflag : cr=critical_ratio(m1,m2) if cr>100.33*random.random()%1.0: print "critical hit" ap=int(ap*2.5) if m2.hp>1 and m2.hp-ap<=0 :ap=m2.hp-1 m2.hp-=ap if m2.hp<0 : m2.hp=0 print " damage=%s %s : hp=%s"%(ap,m2.name,m2.hp) if m2.hp<=0 : raise Gameover else : print "miss" m1,m2=m2,m1 #print mon1 #print mon2 def battle(self): try: for i in xrange(100): self.turn() except Gameover: pass if self.mon1.hp>self.mon2.hp : return self.mon_list[0] else : return self.mon_list[1] def damage(self,atacker,defender): atack_rate=1.-float(defender.defense)/pointmax atack_rate=atack_rate*float(atacker.power)/defender.defense atack_rate=atack_rate*float(atacker.power)/pointmax ap=0.5*pointmax*atack_rate*(0.75 + 0.25*(random.random()-0.5)) if ap<=0 : ap=1 return int(ap) def speed(self): mon1,mon2=self.mon1,self.mon2 sp1=mon1.speed+random.randint(0,mon1.defense)//2 sp2=mon2.speed+random.randint(0,mon2.defense)//2 if sp1>sp2 : return mon1,mon2 else : return mon2,mon1 def critical_ratio(atacker,defender): weakpoint=pointmax-defender.defense weakratio=float(weakpoint)/pointmax #print "original weakpoint",weakpoint powerratio=float(atacker.power)/defender.defense speedratio=float(atacker.speed)/defender.speed #print "original weakratio",weakratio #print "powerration",powerratio #print "speedratio",speedratio weakratio=weakratio*powerratio*speedratio if weakratio >0.9 : weakratio=0.9 weakratio*=0.2 #print "final weakpoint ratio",weakratio return weakratio def hit_miss(atacker,defender): """ """ s=defender.speed/float(atacker.speed) if s< random.randint(0,1000)%pointmax+0.5*(random.random()-.5): hit1=True else: hit1=False d=defender.defense/float(atacker.power) if d< random.randint(0,1000)%pointmax+0.5*(random.random()-0.5): hit2=True else: hit2=False return hit1 and hit2 def hit_miss_ratio(atacker,defender): """ """ miss1=float(defender.speed)/pointmax/float(atacker.speed) miss2=float(defender.defense)/pointmax/float(atacker.power) return 1.0- (miss1+miss2) def stat(atacker,defender): fmax=float(pointmax) r1=defender.speed/fmax/atacker.speed r2=defender.defense/fmax/atacker.power print "calc ratio" , (1.0-(r1+r2))*100,"%" print "hit miss ratio",hit_miss_ratio(atacker,defender)*100,"%" print "calc critical ratio", print critical_ratio(atacker,defender)*100 ,"%" def vs(monlist): newlist=[] for i in monlist: print i print for i in xrange(0,len(monlist),2): print "vs",monlist[i].name,monlist[i+1].name battle=Battle(monlist[i],monlist[i+1]) winner=battle.battle() print "winner :",winner.name print newlist.append(winner) return newlist def pair(monlist): newlist=[] monlist=monlist[:] random.shuffle(monlist) for i in xrange(0,len(monlist),2): newlist+=monlist[i].pair(monlist[i+1]) newlist+=monlist[i].pair(monlist[i+1]) return newlist monlist0=monlist=[ Monster() for x in xrange(16)] raw_input ("evolution begin press enter") for i in xrange(16): monlist=vs(monlist) monlist=pair(monlist) monlist0=monlist0 monlist=vs(monlist) monlist=vs(monlist) monlist=vs(monlist) monlist=vs(monlist) print "old type" for i in monlist0: print i i.tp="old" print "new type" i=mon_new=monlist[0] print i i.tp="new" raw_input("old type vs new type hit enter ") counter=0 for i in monlist0: battle=Battle(mon_new,i) winner=battle.battle() if winner==mon_new : counter+=1 print " new wins against old %s / %s" % (counter,len(monlist0)) if False : mon1=Monster() mon2=Monster() print mon1 #print mon1.dna print mon2 #print mon2.dna #stat(mon1,mon2) #stat(mon2,mon1) battle=Battle(mon1,mon2) winner=battle.battle() print print "winner :" ,winner