[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