ぷよぷよの連鎖プログラム(pygame zero)

ぷよぷよの連鎖を再現するプログラムです。pygame zeroで動きます。
2020年にセガが公式でぷよぷよのプログラミング学習用のキットを公開していますが、このプログラムはそれを使っていません。

f:id:nicotakuya:20210514135848j:plain

ぷよぷよの連鎖

 

実行画面です。消えていくプロセスを一気に表示します。
ぷよの接続数は再帰処理で検出しています。プログラムの特徴はそれだけです。

# 落ち物の連鎖
import pgzrun # Pygame Zeroをインポート
WIDTH = 800   # 画面の幅(ピクセル)
HEIGHT = 600  # 画面の高さ(ピクセル)
CELLW = 6     # 舞台の幅(セル数)
CELLH = 8     # 舞台の高さ(セル数)
CELLSIZE = 20 # 1セルのピクセル数
DISPW = int(WIDTH/CELLSIZE)
DISPH = int(HEIGHT/CELLSIZE)

cell = [[0 for j in range(DISPW)] for i in range(DISPH)]

initialdata = [
    [0,0,0,0,0,0],
    [0,2,0,0,0,0],
    [0,2,3,0,0,0],
    [0,2,3,4,0,0],
    [0,1,3,4,0,0],
    [0,1,2,3,3,0],
    [0,1,2,4,3,4],
    [2,1,3,3,4,4]
]

# カラーテーブル
colortable = ['black','blue','red','purple','green']

# セルの書き込み(X座標,Y座標,カラー番号)
def setcell(x,y,data):
    cell[y][x] = data

# セルの読み込み(X座標,Y座標)。戻り値=カラー番号
def getcell(x,y):
    ret = 0
    if x>=0 and x<CELLW and y>=0 and y<CELLH: ret = cell[y][x]
    return ret

# セルを塗りつぶす(X座標,Y座標,変更前の色,変更後の色,連結セル数)
def fill(x,y,before,after,cnt):
    if (before<=0) or (after<0):return 0
    if getcell(x,y)==before:
        setcell(x,y,after)  # 色を変更する
        cnt = cnt+1         # 連結セル数を加算する

    if getcell(x,y-1)==before: cnt = fill(x,y-1,before,after,cnt)
    if getcell(x,y+1)==before: cnt = fill(x,y+1,before,after,cnt)
    if getcell(x-1,y)==before: cnt = fill(x-1,y,before,after,cnt)
    if getcell(x+1,y)==before: cnt = fill(x+1,y,before,after,cnt)
    return cnt  # 戻り値=連結セル数

# セルの落下
def movecell():
    for i in range(CELLH-1):
        for y in range(CELLH-1,0,-1):
            for x in range(CELLW):
                num = getcell(x,y-1)
                if (getcell(x,y)==0) and (num!=0):
                    setcell(x,y-1,0)
                    setcell(x,y  ,num)

# セルの消去。戻り値=消去した回数
def checkcell():
    clearcnt = 0
    for y in range(CELLH):
        for x in range(CELLW):
            num = getcell(x,y)
            if num>=10:continue  # 調査済みのセルはスキップする
            cnt = fill(x,y,num,num+10,0)  # 連結セル数を算出
            if cnt>=4:             # 4個以上連結した場合
                cnt = fill(x,y,num+10,0,0)  # セル消去
                clearcnt = clearcnt+1

    for y in range(CELLH):
        for x in range(CELLW):
            num = getcell(x,y)
            if num<10:continue  # 復元済みのセルはスキップする
            cnt = fill(x,y,num,num-10,0)    # セルの復元

    return clearcnt  # 消去した回数を返す

#セルの状態をバックアップ(X座標,Y座標)
def backup(ofsx,ofsy):
    for y in range(CELLH):
        for x in range(CELLW):
            setcell(ofsx+x,ofsy+y,getcell(x,y))

# 画面の描画
def draw():
    screen.fill('BLACK')
    for y in range(DISPH):
        for x in range(DISPW):
            color = colortable[cell[y][x]]
            r = int(CELLSIZE / 2)
            pos =(x*CELLSIZE+r,y*CELLSIZE+r)
            screen.draw.filled_circle(pos, r, color)

    for i in range(4):
         screen.draw.text(str(i+1)+' COMBO',
              left=CELLSIZE*8*i,top=CELLSIZE*27,fontsize=30)

# セルの初期化と連鎖処理
for y in range(CELLH):
    for x in range(CELLW):
        setcell(x,y,initialdata[y][x])

for combo in range(100):  # 連鎖のループ
    movecell()               # セルの落下
    backup(combo*8,8)        # 消去前のセルをバックアップ
    if checkcell()==0:break  # セルの消去。不可能な場合は終了
    backup(combo*8,18)       # 消去後のセルをバックアップ

pgzrun.go()