오늘은 Random Seed 생성 도구를 만들어 보았다.

 

"Random seed" 또는 "seed value"란?

난수 생성 알고리즘에서 초기 시작점을 설정하는 데 사용되는 초기 값이다.

 

"Random Seed Generator"는 Unity 에디터용으로 설계된 다용도 도구로,

최소값과 최대값 사이의 범위에서 난수를 생성할 수 있도록 사용자에게 인터페이스를 제공하고,

원하는 반복 횟수만큼 난수를 생성할 수 있다.

 

생성된 난수들은 리스트에 저장되고,  에디터 창에서 직접적으로 조회할 수 있다.

 

선형 합동 생성기(LCG) 알고리즘을 사용하여 가상의 난수를 생성하는데,

LCG(선형 합동 생성기) 알고리즘은 간단하면서도 널리 사용되는 난수 생성 방법 중 하나다.

 

LCG 알고리즘은 다음과 같은 수학적 공식을 사용하여 난수 시퀀스를 생성한다.

 

 

Xn+1=(aXn+c)mod m

 

 

Xn+1 = 다음 난수

Xn = 현재 난수

a = 곱셈 상수

c = 증가 상수

m = 모듈(나눗셈의 나머지를 구할때 사용되는 값)

mod = 나머지

 

 

 

using UnityEditor;
using System.Collections.Generic;
using UnityEditor.PackageManager.UI;
using UnityEngine;

public class RandomSeedGenerator : EditorWindow
{
    private int minNumber = 0;
    private int maxNumber = 0;
    private int iterations = 0;
    private List<int> results = new List<int>();

    // LCG Parameters
    private const long a = 1103515245;
    private const long c = 12345;
    private const long m = 2147483647;
    private long seed = 123456789; // Initial seed

    private bool showResults = true;

    private Vector2 scrollPosition;



    [MenuItem("Tools/Random Seed Generator")]
    public static void ShowWindow()
    {
        var window = GetWindow<RandomSeedGenerator>("Random Seed Generator");
        window.maxSize = new Vector2(window.maxSize.x, window.maxSize.y);
        window.minSize = new Vector2(300, 400);
        window.LoadNumberValues();
    }

    void OnGUI()
    {
        GUIStyle centeredStyle = new GUIStyle(GUI.skin.label);
        centeredStyle.alignment = TextAnchor.MiddleCenter;

        GUILayout.Label("Ver. 1.0.0", EditorStyles.boldLabel);

        DrawLine();

        minNumber = EditorGUILayout.IntField("Min Number", minNumber);
        maxNumber = EditorGUILayout.IntField("Max Number", maxNumber);
        iterations = EditorGUILayout.IntSlider("Iterations", iterations, 0, 99);

        if (GUILayout.Button("Generate"))
        {
            GenerateRandomNumbers();
            showResults = true;
            SaveNumberValues();
        }

        GUILayout.BeginHorizontal();
        if (GUILayout.Button("Clear"))
        {
            showResults = false;
        }

        if (GUILayout.Button("Init"))
        {
            // 초기화 재 확인 다이알로그
            bool confirm = EditorUtility.DisplayDialog(
                "Initialize Random Numbers",
                "Are you sure you want to initialize and generate new random numbers? This will clear all existing numbers.",
                "Yes",
                "No"
            );

            if (confirm)
            {
                showResults = false; // 화면 초기화
                results.Clear(); // 난수 초기화
                GenerateRandomNumbers(); // 새로운 난수 생성
            }
        }

        GUILayout.EndHorizontal();

        DrawLine();

        GUILayout.BeginHorizontal();
        GUILayout.Label("Iteration", centeredStyle, GUILayout.ExpandWidth(false));

        Rect lastRect = GUILayoutUtility.GetLastRect();
        GUILayout.Space(10); // 레이블과 세로선 사이의 공간

        GUILayout.Label("Seed", centeredStyle, GUILayout.ExpandWidth(true));
        GUILayout.EndHorizontal();

        DrawVerticalLine(lastRect.xMax + 5, lastRect.y); // 세로 선 

        DrawLine();

        if (showResults)
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            for (int i = 0; i < results.Count; i++)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label($"{i + 1}", centeredStyle, GUILayout.Width(50));
                GUILayout.Space(20);
                GUILayout.Label($"{results[i]}", centeredStyle, GUILayout.ExpandWidth(true));
                GUILayout.EndHorizontal();
            }

            EditorGUILayout.EndScrollView();
        }
    }

    void GenerateRandomNumbers()
    {
        int currentCount = results.Count;
        if (iterations > currentCount)
        {
            // iterations 값이 현재 결과보다 크다면, 추가로 생성
            int additionalIterations = iterations - currentCount;
            for (int i = 0; i < additionalIterations; i++)
            {
                seed = (a * seed + c) % m;
                int randomNumber = minNumber + (int)(seed % (maxNumber - minNumber + 1));
                results.Add(randomNumber);
            }
        }
        else
        {
            // iterations 값이 현재 결과보다 작거나 같다면, 리스트를 잘라서 사용
            results = results.GetRange(0, iterations);
        }
    }

    // Number값 EditorPrefs에 저장
    void SaveNumberValues()
    {
        EditorPrefs.SetInt("MinNumber", minNumber);
        EditorPrefs.SetInt("MaxNumber", maxNumber);
        EditorPrefs.SetInt("iterations", iterations);
    }

    // Number값 EditorPrefs에서 불러오기
    void LoadNumberValues()
    {
        minNumber = EditorPrefs.GetInt("MinNumber", 0);
        maxNumber = EditorPrefs.GetInt("MaxNumber", 0);
        iterations = EditorPrefs.GetInt("iterations", 0);
    }

    private void DrawLine()
    {
        var rect = GUILayoutUtility.GetRect(1, 1, GUILayout.ExpandWidth(true));
        EditorGUI.DrawRect(rect, Color.gray);
    }

    private void DrawVerticalLine(float xPosition, float yPosition)
    {
        EditorGUI.DrawRect(new Rect(xPosition, yPosition, 1, this.position.height), Color.gray);
    }
}

+ Recent posts