迷路の自動生成(6月12日)

今日やったこと

ワーキングメモリーレーニン

勉強

ゲーム開発

迷路の自動生成のアルゴリズムの作成

algoful.com

このサイトを参考にして何とか書きました。

こんなアルゴリズムを自力で書ける人は凄い...

自分の力不足を痛感しました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MakeMaze : MonoBehaviour
{
    public int mapSize;

    [HideInInspector] public int[,] maze;

    [SerializeField] private GameObject wallObject;

    // 穴掘り開始候補座標
    private List<Cell> StartCells;

    // 通路・壁情報
    private static readonly int OutSide = -1;
    private static readonly int OutLineWall = 0;
    private static readonly int InnerWall = 1;
    private static readonly int Path = 2;

    // Start is called before the first frame update
    void Start()
    {
        Initialize();
    }

    public void Initialize()
    {
        //外枠も含めてmapの配列を作成
        //-1:外,0:外枠の壁,1:内側にある壁,2:通路
        maze = new int[mapSize, mapSize];

        StartCells = new List<Cell>();

        MakeOutside();
        MakeOutWall();
        MakeInnerWall();

        Dig(2, 2);
    }


    //外枠用の値(-1)を代入
    private void MakeOutside()
    {
        for(int i = 0; i < mapSize; i++)
        {
            maze[0, i] = OutSide;
            maze[i, 0] = OutSide;
            maze[mapSize - 1, i] = OutSide;
            maze[i, mapSize - 1] = OutSide;
        }
    }

    //一番外側の壁を作成
    private void MakeOutWall()
    {
        for(int i = 1; i < mapSize - 1; i++)
        {
            maze[1, i] = OutLineWall;
            maze[i, 1] = OutLineWall;
            maze[mapSize - 2, i] = OutLineWall;
            maze[i, mapSize - 2] = OutLineWall;
        }
    }

    //内側を全て壁で埋める
    private void MakeInnerWall()
    {
        for(int i = 2; i < mapSize - 2; i++)
        {
            for(int j = 2; j< mapSize - 2; j++)
            {
                maze[i, j] = InnerWall;
            }
        }
    }

    // 座標(x, y)に穴を掘る
    private void Dig(int x, int y)
    {
        // 指定座標から掘れなくなるまで堀り続ける
        var rnd = new System.Random();

        //掘り始めた場所を掘る
        maze[x, y] = Path;

        while (true)
        {
            // 掘り進めることができる方向のリストを作成
            var directions = new List<Direction>();

            if (maze[x, y - 1] == InnerWall && maze[x, y - 2] == InnerWall)
                directions.Add(Direction.Up);

            if (maze[x + 1, y] == InnerWall && maze[x + 2, y] == InnerWall)
                directions.Add(Direction.Right);

            if (maze[x, y + 1] == InnerWall && maze[x, y + 2] == InnerWall)
                directions.Add(Direction.Down);

            if (maze[x - 1, y] == InnerWall && maze[x - 2, y] == InnerWall)
                directions.Add(Direction.Left);

            // 掘り進められない場合、ループを抜ける
            if (directions.Count == 0)
                break;
                

            // 掘り進められる場合はランダムに方向を決めて掘り進める
            var dirIndex = rnd.Next(directions.Count);

            // 決まった方向に先2マス分を通路とする
            switch (directions[dirIndex])
            {
                case Direction.Up:
                    y--;
                    DigPath(x, y);
                    y--;
                    DigPath(x, y);
                    break;

                case Direction.Right:
                    x++;
                    DigPath(x, y);
                    x++;
                    DigPath(x, y);
                    break;

                case Direction.Down:
                    y++;
                    DigPath(x, y);
                    y++;
                    DigPath(x, y);
                    break;

                case Direction.Left:
                    x--;
                    DigPath(x, y);
                    x--;
                    DigPath(x, y);
                    break;
            }
        }

        // どこにも掘り進められない場合、穴掘り開始候補座標から掘りなおし
        // 候補座標が存在しないとき、穴掘り完了
        var cell = GetStartCell();

        if (cell != null)
        {
            Dig(cell.X, cell.Y);
        }
    }

    // 座標を通路とする(穴掘り開始座標候補の場合は保持)
    private void DigPath(int x, int y)
    {
        maze[x, y] = Path;

        if (x % 2 == 0 && y % 2 == 0)
        {
            // 穴掘り直し候補の座標を追加
            StartCells.Add(new Cell() { X = x, Y = y });
        }
    }

    // 穴掘り再開位置をランダムに取得する
    private Cell GetStartCell()
    {
        if (StartCells.Count == 0) 
            return null;

        // ランダムに開始座標を取得する
        var rnd = new System.Random();
        var index = rnd.Next(StartCells.Count);
        var cell = StartCells[index];
        StartCells.RemoveAt(index);

        return cell;
    }

}

// セル情報
public class Cell
{
    public int X { get; set; }
    public int Y { get; set; }
}

// 方向
public enum Direction
{
    Up = 0,
    Right = 1,
    Down = 2,
    Left = 3
}

8×8

f:id:alberto_hojo:20190612154523p:plain

100 × 100

f:id:alberto_hojo:20190612154633p:plain

今日のパフォーマンス

JINS MEME ESという最新の学術研究の成果を元に人間の心理状態を測定できるウェアラブルバイスを使って本日の僕の集中状態を測定した結果は以下のようになりました。

f:id:alberto_hojo:20190613000652p:plain:w250

作業時間 9時間41分

集中時間 2時間59分

集中率 31%