パズドラの落ちコンの分布を探る

最近パズドラにはまってます。そこで、花火を打った時の落ちコンの分布をグラフ化しようと思いました。

```python
import random
from matplotlib import pyplot as plt

tate = 5
yoko = 6
iro = 6

class UnionFind():
    #ｎは頂点数
    def __init__(self, n):
        self.parent = [-1]*n

    #aの属する集合の根を取得
    def root(self,a):
        if self.parent[a] < 0:return a
        self.parent[a] = self.root(self.parent[a])
        return self.parent[a]
    
    #aの属する集合の要素数を取得
    def size(self,a):
        return -self.parent[self.root(a)]

    #aとbをくっつける
    def connect(self,a,b):
        if self.root(a) == self.root(b):return False
        a = self.root(a);b = self.root(b)
        if self.size(a) < self.size(b):a,b = b,a
        self.parent[a] += self.parent[b]
        self.parent[b] = a
        return True

#コンボ数を数える関数
def count(ls : list) -> (int,list):
    check = [[0 for i in ls[j]] for j in range(len(ls))]
    #同じ色で消えるところを色塗り
    for i in range(len(ls)):
        for j in range(len(ls[0])):
            try:
                #横
                if ls[i][j] == ls[i][j+1] == ls[i][j+2]:
                    if check[i][j] != 0 or check[i][j+1] != 0 or check[i][j+2] != 0:
                        check[i][j],check[i][j+1],check[i][j+2] = ls[i][j],ls[i][j],ls[i][j]
                    else:
                        check[i][j],check[i][j+1],check[i][j+2] = ls[i][j],ls[i][j],ls[i][j]
            except:
                pass
            try:
                #縦
                if ls[i][j] == ls[i+1][j] == ls[i+2][j]:
                    if check[i][j] != 0 or check[i+1][j] != 0 or check[i+2][j] != 0:
                        check[i][j],check[i+1][j],check[i+2][j] = ls[i][j],ls[i][j],ls[i][j]
                    else:
                        check[i][j],check[i+1][j],check[i+2][j] = ls[i][j],ls[i][j],ls[i][j]
            except:
                pass
    #UnionFind
    uni = UnionFind(len(ls)*len(ls[0]))
    #graph = [[] for i in range(len(ls)*len(ls[0]))]
    for i in range(len(ls)):
        for j in range(len(ls[0])):
            if check[i][j] == 0:continue
            for x,y in [[1,0],[-1,0],[0,1],[0,-1]]:
                try:
                    if check[i][j] == check[i+x][j+y]:
                        uni.connect(len(ls[0])*i+j,len(ls[0])*(i+x)+j+y)
                        #graph[len(ls[0])*i+j].append(len(ls[0])*(i+x)+j+y)
                except:
                    pass
    #コンボ数を集計
    conbo = 0
    for i in uni.parent:
        if i < -2:conbo+=1
    return conbo,check

#乱数を使ってパズルを更新する関数
def update(ls : list,n : int) -> (int,list):
    conbo,check = count(ls)
    for i in range(len(ls)):
        for j in range(len(ls[0])):
            if check[i][j] > 0:
                check[i][j] = random.randint(1,n)
            else:
                check[i][j] = ls[i][j]
    return conbo,check

#n回数花火を打ってコンボ数の分布をみる
def analytics(n : int) -> list:
    buf = [0]*n
    for i in range(n):
        ls = [[1]*yoko for i in range(tate)]
        conbo = -1
        while True:
            c,ls = update(ls,iro)
            if c == 0:
                break
            else:
                conbo += c
        buf[i] = conbo
    dis = [0]*(max(buf)+1)
    for i in buf:
        dis[i] += 1
    return dis
ls = analytics(10000)
lef = [i for i in range(len(ls))]
plt.bar(lef,ls)
plt.show()
```

コードは上のやつで全部です。tateは縦の個数、yokoは横の個数、iroは色の種類です。乱数に補正がかかってないとしてパズルを更新しています。色のつながりはUnionFindで管理してます。縦軸が回数で横軸がコンボ数です。

6×7盤面 6色
![6_7_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278116/a2e900fa-b8c6-f037-6ba0-b1b33f522d91.png)


5×6盤面 6色
![5_6_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278116/6c99f0b6-54f7-4be3-5742-d3cb077c4fba.png)

4×5盤面 6色
![4_5_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278116/ea8ecdad-71c6-d229-bc04-3997dc70a148.png)


これだけです。
　　終
制作・著作
━━━━━
　ⓃⒽⓀ