ランダムより少しましな塗るアルゴリズムをつくってみました。
水色が塗るほう、黄色はランダムに撒き散らすタイプです。
かなり互角です。しかしこれは黄色の方が移動速度10倍以上速かったりします。
速くてもランダムなのでこんな感じです。
少し水色の足を速くするとそんなアルゴリズムを入れてたつもりはないのに、
私が道を丁寧に塗るときのようなジグザクの動きを自然にマスターしました。
さらに相手の土地を塗ることを評価させてみると戦いのようなことまではじめました。
ブルーオーシャンを狙うアルゴリズムにしてみると端の塗りが甘くなってしまいました。
追加した関数としては、
円を塗る関数を改造して円の中にある色を数える関数
一定方向に移動して色を数えてまだ塗っていない箇所、相手の色から優先順位をつけて実行する関数ぐらいです。
設計をしていないのでソースは破綻寸前です。
#スプラしい
import pygame,random
import copy
from itertools import product
from pygame.locals import *
screen = pygame.display.set_mode((900, 600))
bd = [["#" for x in range(300)] for y in range(200)] #ゲームボード(boardの略)
col=[(0,100,0),(0,250,200),(255,200,0)] #色 空間:緑 チーム1:水色 チーム2:黄色
unit=[]#(owner,x,y,d,beforeAction) dとbeforeActionは現在未使用
ri=random.randint
def stageMake():
global unit,bd
for i in range(10):#対称になるように空間を空けます。つながらない時もあります
x,y,r=ri(0, 299),ri(0, 199),ri(30, 50)
circle(x,y,r,"0","a");circle(299-x,199-y,r,"0","a")
circle(50,50,50,"0","a");circle(299-50,199-50,50,"0","a")
for x,y in product(range(300),range(200)):#枠
if x==0 or y==0 or x==299 or y==199:bd[y][x]="#"
for i in range(5):#イカは2チーム 5体ずつ
unit+=[(1,20,20,0,"")]
unit+=[(2,299-20,199-20,0,"")]
def action():
workBd=copy.deepcopy(bd)
for n,u in enumerate(unit):#壁でなければ動き足跡を残す、最後に墨をはく
o,x,y,d,bf=u
ac=""
if o==1:
#ac=openMove(o,x,y)
ac=oceanMove(o,x,y)
#ac=battleMove2(o,x,y)
else:
#ac=randMove(o)
#ac=oceanMove(o,x,y)
ac=battleMove(o,x,y)
mv=50#移動量 移動コスト 壁:4 相手の色:3 何もなし:2 自分の色:1
for a in ac:
dx=[0,0,1,-1]["UDRL".find(a)]
dy=[-1,1,0,0]["UDRL".find(a)]
if bd[y+dy][x+dx]!="#":
if bd[y+dy][x+dx]=="0":mv-=2
elif bd[y+dy][x+dx]==str(o):mv-=1
else: mv-=3
if mv<=0:break
x+=dx
y+=dy
bd[y][x]=str(o)
else:mv-=4
unit[n]=(o,x,y,d,ac)
circle(x,y,5,str(o),"#")
def randMove(o):
r=""
if o==1:
for i in range(100):r+="UDRL"[ri(0,3)]#ランダム 100歩
else:
for i in range(10):r+="UDRL"[ri(0,3)]*10#ランダム10回 直進10歩
return r
def reset():
global unit,bd
bd = [["#" for x in range(300)] for y in range(200)]
unit=[]
stageMake()
def openMove(o,x,y):
moveTimes=8
score=[]
for dx,dy,direction in zip([0,0,1,-1],[-1,1,0,0],"UDRL"):
sw=0
for i in range(1,moveTimes+1):
if bd[y+dy*i][x+dx*i]=="#":
sw=1
break
if sw==0:
c=circleCount(x+dx*moveTimes,y+dy*moveTimes,5,str(o))
score+=[(c,x+dx*moveTimes,y+dy*moveTimes,direction*5)]
if len(score)==0:return randMove(0)
score.sort()
c,x,y,code=score[-1]
if c==0:return randMove(0)
circle(x,y,5,str(o))
return code
def oceanMove(o,x,y):
moveTimes=8
score=[]
for dx,dy,direction in zip([0,0,1,-1],[-1,1,0,0],"UDRL"):
sw=0
for i in range(1,moveTimes+1):
if bd[y+dy*i][x+dx*i]=="#":
sw=1
break
if sw==0:
c=circleCount(x+dx*moveTimes*2,y+dy*moveTimes*2,15,str(o))
score+=[(c,x+dx*moveTimes,y+dy*moveTimes,direction*5)]
if len(score)==0:return randMove(0)
score.sort()
c,x,y,code=score[-1]
if c==0:return randMove(0)
circle(x,y,5,str(o))
return code
def battleMove(o,x,y):
eo="1"
if str(o)=="1":eo="2"
moveTimes=8
score=[]
for dx,dy,direction in zip([0,0,1,-1],[-1,1,0,0],"UDRL"):
sw=0
for i in range(1,moveTimes+1):
if bd[y+dy*i][x+dx*i]=="#":
sw=1
break
if sw==0:
c=circleCount2(x+dx*moveTimes,y+dy*moveTimes,5,"0")
c+=circleCount2(x+dx*moveTimes,y+dy*moveTimes,5,eo)
score+=[(c,x+dx*moveTimes,y+dy*moveTimes,direction*5)]
if len(score)==0:return randMove(0)
score.sort()
c,x,y,code=score[-1]
if c==0:return randMove(0)
circle(x,y,5,str(o))
return code
def battleMove2(o,x,y):
eo="1"
if str(o)=="1":eo="2"
moveTimes=8
score=[]
for dx,dy,direction in zip([0,0,1,-1],[-1,1,0,0],"UDRL"):
for i in range(1,moveTimes+1):
if bd[y+dy*i][x+dx*i]!="#":
c=circleCount2(x+dx*i,y+dy*i,5,"0")
c+=circleCount2(x+dx*i,y+dy*i,5,eo)
score+=[(c,x+dx*i,y+dy*i,direction*i)]
else:
break
if len(score)==0:return randMove(0)
score.sort()
c,x,y,code=score[-1]
if c==0:return randMove(0)
circle(x,y,5,str(o))
return code
def circle(sx,sy,r,s,o="#"): #円を塗ります oは塗らない条件です
r2=r*r
for x,y in product(range(sx-r,sx+r+1),range(sy-r,sy+r+1)):
if 0<=x<300 and 0<=y<200 and (sx-x)**2+(sy-y)**2<=r2 and bd[y][x]!=o:bd[y][x]=s
def circleCount(sx,sy,r,o,out="#"): #塗り替える箇所を数える outは塗らない条件です
r2=r*r
c=0
for x,y in product(range(sx-r,sx+r+1),range(sy-r,sy+r+1)):
if 0<=x<300 and 0<=y<200 and (sx-x)**2+(sy-y)**2<=r2:
if bd[y][x]==out or str(bd[y][x])==o:continue
c+=1
return c
def circleCount2(sx,sy,r,o): #塗り替える箇所を数える outは塗らない条件です
r2=r*r
c=0
for x,y in product(range(sx-r,sx+r+1),range(sy-r,sy+r+1)):
if 0<=x<300 and 0<=y<200 and (sx-x)**2+(sy-y)**2<=r2:
if bd[y][x]==o:c+=1
return c
def main():
stageMake()
gameOver=0 #どちらかが50%超えるとゲーム終了とします
while (1):
if gameOver==0:
action()
screen.fill((0,0,0))
s1,s2=mapWrite()
text(40,40,"SPRASII",50,(255,255,255))
text(540,540,"cyan:"+str(s1)+" vs "+"yellow:"+str(s2),40,(255,100,100))
if s1>50 or s2>50:gameOver=1
pygame.display.update()
for event in pygame.event.get(): #pygameお決まりの処理です
if event.type == pygame.QUIT:pygame.quit();quit()
if event.type == KEYDOWN:
if event.key == K_SPACE:
reset()
gameOver=0
def mapWrite(): #bdの値によって色をつけます 同時に色によってスコアを計算します
score=[0,0,0]
for x,y in product(range(300),range(200)):
if bd[y][x]!="#":
score[int(bd[y][x])]+=1
pygame.draw.rect(screen, col[int(bd[y][x])], Rect(x*3,y*3,3,3))
return round(score[1]*100/sum(score),1),round(score[2]*100/sum(score),1)
def text(x,y,txt,size,c):
screen.blit(pygame.font.Font(None, size).render(txt, True,(0,0,0)), [x+2, y+2])
screen.blit(pygame.font.Font(None, size).render(txt, True,c), [x, y])
pygame.init();main();pygame.quit();quit()