【Kivy】Pythonで迷路開発Part2

【Kivy】Pythonで迷路開発Part2を表すサムネイル

こんにちは、にわこまです。

今回は、Part1で作った盤面生成プログラムの問題点を提起し、その問題を解決するプログラムを作成します。盤面生成を正しくできないとお話にならないため慎重に、プログラムしていきます。

 

誤字脱字や分からない点が、ございましたらご連絡お願いいたします。

 

 

スポンサードサーチ


【Kivy】Pythonで迷路開発Part2

Part2を表す画像

今回のシリーズは、2Dの迷路を開発することを目的としています。(プレイヤーを操作してスタートからゴールまでの時間を競います。)

 

今回のシリーズの主な内容

1.迷路の盤面を生成するプログラムの開発

2.Kivyで迷路アプリケーション開発

 

迷路の盤面を生成するプログラムでは、手書きで迷路を作るような処理を、プログラムに直していきます。

Kivyでの開発は、プレイヤーと壁との当たり判定に気を付けて開発を行います。

 

 

今回は

今回は、1つ目の迷路の盤面を作成するプログラムを作成します。Part1で作成した盤面生成プログラムの問題点とその解決方法を紹介します。

 

 

問題提起

問題提起を表す画像

Part1で作成した、labyrinth02.pyの問題点を提起します。

labyrinth02.pyでは、5×5(実質3×3)の盤面に迷路を生成しました。しかし、6×6(実質4×4)の盤面で迷路を生成すると以下のような盤面でつまずくことがあります。

Part1で作成したlabyrinth02.pyの問題点を表した画像

図の左下の盤面では、「(rowCurrent, colCurrent) = (4, 1)」となり、これ以上道を作ることができません。しかし、迷路は完成しておらずwhile文を無限にループしてしまいます。

 

 

解決策

先のような盤面に陥った場合、道上に分岐できる座標を探します。

分岐できる座標は、道(1)であり、さらにその座標の上下左右の座標に道が作れる座標です。

 

 

スポンサードサーチ


盤面生成3

盤面生成3を表す画像

laybrinth02.pyでの問題を解決するプログラムを作成します。

 

labyrinth03.pyを作成し、以下のコードを書きこみます。

import numpy as np
import random


def nextCrossBlocks(field, pos, rowNext, colNext):
    offset = [(0, -1), (-1, 0), (0, 1), (1, 0)]
    pos = (pos[0] * (-1), pos[1] * (-1))
    offset.remove(pos)
    rowMax, colMax = np.shape(field)
    blocks = []
    for pos in offset:
        row = rowNext + pos[0]
        col = colNext + pos[1]
        if(row != 0 and row != rowMax-1 and col != 0 and col != colMax):
            blocks.append(field[(row, col)])
    return blocks

def findFork(field):
    posList = list(zip(*np.where(field == 1)))
    offset = [(0, -1), (-1, 0), (0, 1), (1, 0)]
    rowMax, colMax = np.shape(field)
    possible = []
    for point in posList:
        for pos in offset:
            row = point[0] + pos[0]
            col = point[1] + pos[1]
            block = field[(row, col)]
            if(row != 0 and row != rowMax-1 and col != 0 and col != colMax-1 and block == 0):
                blocks = nextCrossBlocks(field, pos, row, col)
                if(1 not in blocks):
                    possible.append(point)
                    break
    return possible

def makeLabyrinth(field):
    rowMax, colMax = np.shape(field)
    posGoal = list(zip(*np.where(field == 2)))[0]
    rowCurrent, colCurrent = (1, 1)
    offset = [(0, -1), (-1, 0), (0, 1), (1, 0)]
    while(True):
        possible = []
        for pos in offset:
            row = rowCurrent + pos[0]
            col = colCurrent + pos[1]
            block = field[(row, col)]
            if(0 < row and row < rowMax-1 and 0 < col and col < colMax-1 and block != 1):
                blocks = nextCrossBlocks(field, pos, row, col)
                if(1 not in blocks):
                    possible.append((row, col))
        if(posGoal in possible):
            break
        if(len(possible) == 0):
            possible = findFork(field)
        r = random.randrange(len(possible))
        rowCurrent, colCurrent = possible[r]
        field[(rowCurrent, colCurrent)] = 1
    print(field)
    pass

field = np.array([[0, 0, 0, 0, 0, 0],
                  [0, 1, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 2, 0],
                  [0, 0, 0, 0, 0, 0]])

test = np.array([[0, 0, 0, 0, 0, 0],
                 [0, 1, 0, 0, 0, 0],
                 [0, 1, 1, 0, 0, 0],
                 [0, 0, 1, 0, 0, 0],
                 [0, 1, 1, 0, 2, 0],
                 [0, 0, 0, 0, 0, 0]])

if __name__ == '__main__':
    makeLabyrinth(field)

 

 

コードの解説

1、2行目の「import numpy as np」と「import random」は、盤面生成を実装する上で必要なライブラリをインポートしています。

 

5行目~16行目の「nextCrossBlocks」は、道を作ろうとする座標の周りの座標の状態を調べるための関数です。内容はPart1の盤面生成2で解説しているため省略します。

 

18行目~33行目の「findFork」は、道上に分岐点を探すための関数です。

19行目の「posList = list(zip(*np.where(field == 1)))」は、盤面における道の座標をposListに代入しています。

28行目の「if文」は、「0より大きく、最大値未満」+「その座標が壁」にしてあります。

29行目の「blocks = nextCrossBlocks(field, pos, row, col)」は、道を作る座標の周りの座標の状態を取得します。

30行目の「if文」は、道を作ろうとしている座標の周りの座標に道が存在しないことを確認しています。

33行目の「return possible」は、分岐点の座標をリストで返しています。

 

35行目~58行目の「makeLabyrinth」は、盤面生成の主な機能を果たす関数です。

52、53行目の「if文」と「findFork」は、現在の座標から道を作ることが出来なくなった時に、findForkを実行し分岐点を探します。

 

 

動作確認

問題を解決できているか動作確認を行います。コマンドプロンプトを開き、ファイルを保存したフォルダまで移動します。移動したら以下のコマンドを入力し、実行します。

python labyrinth03.py

 

以下のように盤面が生成されていれば、問題ありません。

[[0 0 0 0 0 0]
 [0 1 1 0 1 0]
 [0 0 1 1 1 0]
 [0 1 1 0 1 0]
 [0 1 0 0 2 0]
 [0 0 0 0 0 0]]

 

以上で動作確認は完了です。

 

 

まとめ

まとめの画像

今回は、labyrinth02.pyの問題点を解決するプログラムを作成しました。

しかし、盤面生成のプログラムはまだ完成ではありません。まだ問題点があります。

 

今回作成したコードを以下に示します。

 

次回は、その問題点と解決方法を紹介します。

 

 

最後までお読みいただきありがとうございます。


スポンサードサーチ