[Minecraft] 自動生成されたマイクラ迷路ダンジョンからの脱出!

Minecraft

巨大な迷路ダンジョンをPythonを使って自動生成します。
内容としては、例によってMinescript modでマイクラ上でPythonを実行できるようにして、迷路フロアを複数階層作ることでダンジョン化しています。
サンプルコードも載せていますので、マイクラ上で実際に作ってみてください。

りお
りお

難易度高めですので、イライラして壁ブロックを壊さないようにしましょう!

迷路ダンジョンを作るための準備

まずはマイクラでMinescript modを使えるようにします。
このmodは、マイクラ内でPythonスクリプトを実行するためのmodです。
使えるようにする方法は、こちらの記事にまとめていますので、参考にしてみてください。

迷路ダンジョン生成用のサンプルコード

かなり汚いコードになってしまってますが、サンプルコードの全体がこちらです。
こちらの内容をmaze_dg.pyというファイル名で保存します。
maze_dg.pyは、Minescriptフォルダ(%appdata%\.minecraft\minescript フォルダ)に保存します。

maze_dg.py
import minescript
import random

FLOOR_COLOR = "white_stained_glass"
WALL_COLOR = ["red_stained_glass",
              "orange_stained_glass",
              "yellow_stained_glass",
              "lime_stained_glass",
              "green_stained_glass",
              "light_blue_stained_glass",
              "blue_stained_glass",
              "purple_stained_glass",
              "magenta_stained_glass",
              "pink_stained_glass"]

LEVEL = 10
WIDTH, HEIGHT = 31, 31

def find(cell):
    if sets[cell] != cell:
        sets[cell] = find(sets[cell])
    return sets[cell]

def union(cell1, cell2):
    root1, root2 = find(cell1), find(cell2)
    if root1 != root2:
        sets[root2] = root1
        return True
    return False

if __name__ == '__main__':
    (px, py, pz) = minescript.player_position()
    blockpacker = minescript.BlockPacker()

    for lv in range(LEVEL):

        for i in range(WIDTH):
            vx = int(px - WIDTH / 2 + i)
            for j in range(HEIGHT):
                vz = int(pz - HEIGHT / 2 + j)
                blockpacker.setblock((vx, int(py - 1), vz), FLOOR_COLOR)
                if (lv == 0 or lv == LEVEL - 1) and (i == 0 or i == WIDTH - 1 or j == 0 or j == HEIGHT - 1):
                    blockpacker.setblock((vx, int(py), vz), FLOOR_COLOR)
                    blockpacker.setblock((vx, int(py+1), vz), FLOOR_COLOR)
        blockpacker.pack().write_world()

        if lv == 0:
            gx = int(px)
            gz = int(pz + HEIGHT / 2)
            blockpacker.setblock((gx, int(py), gz-1), "air")
            blockpacker.setblock((gx, int(py+1), gz-1), "air")
            blockpacker.setblock((gx-1, int(py), gz-1), "pearlescent_froglight")
            blockpacker.setblock((gx-1, int(py+1), gz-1), "pearlescent_froglight")
            blockpacker.setblock((gx+1, int(py), gz-1), "pearlescent_froglight")
            blockpacker.setblock((gx+1, int(py+1), gz-1), "pearlescent_froglight")
            blockpacker.pack().write_world()

        elif lv > 0 and lv < LEVEL - 1:
            gx = random.randrange(int(px - WIDTH / 2) + 1, int(px + WIDTH / 2), 2)
            gz = random.randrange(int(pz - HEIGHT / 2) + 1, int(pz + HEIGHT / 2), 2)
            blockpacker.setblock((gx, int(py - 1), gz), "air")
            blockpacker.setblock((gx-1, int(py - 1), gz), "pearlescent_froglight")
            blockpacker.setblock((gx+1, int(py - 1), gz), "pearlescent_froglight")
            blockpacker.setblock((gx, int(py - 1), gz-1), "pearlescent_froglight")
            blockpacker.setblock((gx, int(py - 1), gz+1), "pearlescent_froglight")
            blockpacker.pack().write_world()

            maze = [[1] * WIDTH for _ in range(HEIGHT)]
            sets = {(x, y): (x, y) for x in range(1, WIDTH, 2) for y in range(1, HEIGHT, 2)}
            edges = []
            for x in range(1, WIDTH, 2):
                for y in range(1, HEIGHT, 2):
                    if x + 2 < WIDTH:
                        edges.append(((x, y), (x + 2, y)))
                    if y + 2 < HEIGHT:
                        edges.append(((x, y), (x, y + 2)))
            random.shuffle(edges)
            for (x1, y1), (x2, y2) in edges:
                if union((x1, y1), (x2, y2)):
                    maze[y1][x1] = 0
                    maze[y2][x2] = 0
                    maze[(y1 + y2) // 2][(x1 + x2) // 2] = 0

            for i in range(WIDTH):
                vx = int(px - WIDTH / 2 + i)
                for j in range(HEIGHT):
                    vz = int(pz - HEIGHT / 2 + j)
                    if maze[i][j]:
                        blockpacker.setblock((vx, int(py), vz), WALL_COLOR[(lv + 1) % 10])
                        blockpacker.setblock((vx, int(py+1), vz), WALL_COLOR[(lv + 1) % 10])
            blockpacker.pack().write_world()

        elif lv == LEVEL - 1:
            gx = random.randrange(int(px - WIDTH / 2) + 1, int(px + WIDTH / 2), 2)
            gz = random.randrange(int(pz - HEIGHT / 2) + 1, int(pz + HEIGHT / 2), 2)
            blockpacker.setblock((gx, int(py - 1), gz), "air")
            blockpacker.setblock((gx-1, int(py - 1), gz), "pearlescent_froglight")
            blockpacker.setblock((gx+1, int(py - 1), gz), "pearlescent_froglight")
            blockpacker.setblock((gx, int(py - 1), gz-1), "pearlescent_froglight")
            blockpacker.setblock((gx, int(py - 1), gz+1), "pearlescent_froglight")
            blockpacker.pack().write_world()            

        py = py + 3

迷路ダンジョンを生成

準備が完了したらマイクラのワールドで実際に動かしてみます。
「\maze_dg」を実行することで迷路ダンジョンが生成されます。

実行するとプレイヤーを中心としてダンジョンが作成されていきます。

各フロアの迷路が生成されながら、巨大なダンジョンになっていきます。
本記事のサンプルコードでは、各フロアが30×30ブロックで、合計10フロアとして生成していますが、これらの値を変更してあげることで、もっと巨大なダンジョンを生成することもできます。
クリアする前に諦めることになるとは思いますが。。

想定としては、最下層をゴールのフロアとして出口を生成しています。

しばらくするとダンジョン生成が完了しますので、屋上部分から各フロアを下に降りていきます。
各フロアにはフロッグライトで囲まれた1×1の空きブロックが存在しますので、そのブロックを通って下のフロアに移動できます。

複雑な迷路になっていますので、屋上からゴールフロアに辿り着くまでに思ったよりも時間が掛かると思います。

まとめ

本記事ではマイクラで迷路ダンジョンを作成してみました。
これだけでも難易度は高めですが、時間によって1×1の空きブロックの位置を変更するとか、トラップを仕掛けてみるとかで、さらに難易度を高めることもできます。
逆に空きブロックを増やすことで難易度も下げることができますので、色々なブロックを配置してダンジョンを生成してみるのも楽しいと思います。

コメント

タイトルとURLをコピーしました