[Minecraft] 高難度!自動生成マイクラ迷路ダンジョンからの脱出

Minecraft

本記事はこちらの記事の高難度バージョンです。
ドーナツ状の迷路ダンジョンを生成します。
続きの記事としてまとめていますので、サンプルコードを動かす準備についてもこちらをご確認ください。

【高難度】迷路ダンジョン生成用のサンプルコード

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

maze_cdg.py
import copy
import minescript
import math
import random

LEVEL = 10
R1 = 30
R2 = 8
WIDTH, HEIGHT = R1 * 2 + 1, R1 * 2 + 1

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

def is_in_circle(x, y, r1, r2):
    if round(math.sqrt((x-r1)**2 + (y-r1)**2)) <= r1 and round(math.sqrt((x-r1)**2 + (y-r1)**2)) >= r2 :
        return True
    else:
        return False

def get_wall_color(x, z):
    if x >= 0 and z >=0:
        if abs(z) > abs(x):
            return "red_stained_glass"
        else:
            return "orange_stained_glass"
    elif x >=0 and z < 0:
        if abs(x) > abs(z):
            return "yellow_stained_glass"
        else:
            return "lime_stained_glass"
    elif x < 0 and z < 0:
        if abs(z) > abs(x):
            return "light_blue_stained_glass"
        else:
            return "blue_stained_glass"
    elif x < 0 and z >= 0:
        if abs(x) > abs(z):
            return "purple_stained_glass"
        else:
            return "magenta_stained_glass"


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

    for lv in range(LEVEL):

        maze = [[1] * WIDTH for _ in range(HEIGHT)]
        sets = {}
        edges = []
        floor = []

        for x in range(1, 2 * R1 + 1, 2):
            for y in range(1, 2 * R1 + 1, 2):
                if round(math.sqrt((x-R1)**2 + (y-R1)**2)) <= R1 and round(math.sqrt((x-R1)**2 + (y-R1)**2)) >= R2:
                    sets[(x, y)] = (x, y)
            
        for x in range(0, 2 * R1 + 1):
            for y in range(0, 2 * R1 + 1):
                if round(math.sqrt((x-R1)**2 + (y-R1)**2)) > R1 + 1 or round(math.sqrt((x-R1)**2 + (y-R1)**2)) < R2 - 1:
                    maze[x][y] = 0
        floor = copy.deepcopy(maze)

        if lv < (LEVEL - 1):
        
            for x in range(1, 2 * R1 + 1, 2):
                for y in range(1, 2 * R1 + 1, 2):
                    if is_in_circle(x, y, R1, R2) and is_in_circle(x + 2, y, R1, R2):
                        edges.append(((x, y), (x + 2, y)))
                    if is_in_circle(x, y, R1, R2) and is_in_circle(x, y + 2, R1, R2):
                        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

            x, z = 0, 0
            for row in floor:
                for cell in row:
                    if cell and lv != 0:
                        blockpacker.setblock((int(px + x - R1), int(py - 1), int(pz + z - R1)), "white_stained_glass")
                    elif cell and lv == 0:
                        blockpacker.setblock((int(px + x - R1), int(py - 1), int(pz + z - R1)), "white_concrete")
                    z = z + 1
                x = x + 1
                z = 0

            if lv != 0:
                gx, gz = 0, 0
                for row in floor:
                    for cell in row:
                        gx = random.randint(0, len(maze) - 1)
                        gz = random.randint(0, len(maze[0]) - 1)
                        if is_in_circle(gx, gz, R1, R2) and maze[gx][gz] == 0:
                            break
                blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1)), "air")
                blockpacker.setblock((int(px + gx - R1 - 1), int(py - 1), int(pz + gz - R1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + gx - R1 + 1), int(py - 1), int(pz + gz - R1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1 - 1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1 + 1)), "pearlescent_froglight")

            x, z = 0, 0
            for row in maze:
                for cell in row:
                    if cell:
                        blockpacker.setblock((int(px + x - R1), int(py),   int(pz + z - R1)), get_wall_color(int(x - R1), int(z - R1)))
                        blockpacker.setblock((int(px + x - R1), int(py+1), int(pz + z - R1)), get_wall_color(int(x - R1), int(z - R1)))
                    z = z + 1
                x = x + 1
                z = 0

            if lv == 0:
                blockpacker.setblock((int(px + R1 - 1), int(py), int(pz)), "air")
                blockpacker.setblock((int(px + R1 - 1), int(py + 1), int(pz)), "air")
                blockpacker.setblock((int(px + R1), int(py), int(pz)), "air")
                blockpacker.setblock((int(px + R1), int(py + 1), int(pz)), "air")
                blockpacker.setblock((int(px + R1), int(py), int(pz - 1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + R1), int(py), int(pz + 1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + R1), int(py + 1), int(pz - 1)), "pearlescent_froglight")
                blockpacker.setblock((int(px + R1), int(py + 1), int(pz + 1)), "pearlescent_froglight")
                
            blockpacker.pack().write_world()

        elif lv == (LEVEL - 1):
            x, z = 0, 0
            for row in floor:
                for cell in row:
                    if cell:
                        blockpacker.setblock((int(px + x - R1), int(py - 1), int(pz + z - R1)), "white_stained_glass")
                    z = z + 1
                x = x + 1
                z = 0

            gx, gz = 0, 0
            for row in floor:
                for cell in row:
                    gx = random.randint(0, len(maze) - 1)
                    gz = random.randint(0, len(maze[0]) - 1)
                    if is_in_circle(gx, gz, R1, R2) and maze[gx][gz] == 0:
                        break
            blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1)), "air")
            blockpacker.setblock((int(px + gx - R1 - 1), int(py - 1), int(pz + gz - R1)), "pearlescent_froglight")
            blockpacker.setblock((int(px + gx - R1 + 1), int(py - 1), int(pz + gz - R1)), "pearlescent_froglight")
            blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1 - 1)), "pearlescent_froglight")
            blockpacker.setblock((int(px + gx - R1), int(py - 1), int(pz + gz - R1 + 1)), "pearlescent_froglight")

            blockpacker.pack().write_world()

        py = py + 3

ドーナツ状の迷路ダンジョンを生成

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

ドーナツ状の迷路が階層になった高難度のダンジョンが完成します。
各フロアにはフロッグライトで囲まれた1×1の空きブロックが存在しますので、そのブロックを通って下のフロアに移動できます。
一番下のフロアには出口が1か所作られていますので、そこから出られたらゴールです。

LEVELとR1(外周の円の半径)を大きくすることで、より複雑な迷路を作ることができます。
こちらはR1を50にした例。

まとめ

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

コメント

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