본문 바로가기

게임 프로그래밍 (Game Programming)/유니티 (Unity)

Let's make a lottery machine!! 로또 번호 생성기 만들기

 

 

이번 시간에는 간단하게 로또 번호 추첨기를 만들어 보겠습니다.

한국의 로또는 어떠한 방식일까요?

1부터 45까지 적혀있는 45개의 공을 기계에 넣고 섞습니다.

공을 하나씩 꺼내게 되고 여섯개의 번호가 내가 구매한 번호와 일치한다면 1등에 당첨이 되는 것이죠.

 

로또의 당첨 확률은 무려 1/8,145,060(814만 5천60분의일)이라고 합니다.

퍼센테이지로 환산 시 약 0.000012%입니다.

이는 흔히 농담으로 번개에 맞을 확률이라고 하죠.

인터넷에 로또 번호 추첨이라고 검색을 하면 수많은 번호 추첨 사이트가 나옵니다.

빅데이터를 사용했다, 슈퍼 컴퓨터로 분석했다 등등 여러 말로 유혹을 합니다.

로또 번호는 완벽한 난수이기 때문에 절대로 예측이 불가합니다.

단지 재미로 한두번 재미삼아 번호 추첨사이트를 이용해보는 것을 권장드립니다.

보통의 경우에는 유료 결제를 해야만 더 정밀한 번호를 준다며 유혹합니다.

이 글을 보시는 분들은 현명한 선택을 하시길 바랍니다!!

 

 

 

 

 

복잡하게 파고들면 복권류의 번호를 생성하는 것은 쉬운 일이 아닙니다.

유니티에서 사용하게 될 Random이라는 클래스는 난수가 아닌 의사 난수를 생성하기 때문이죠.

 

난수란 생성 방법이 결정되어 있지 않기 때문에 다음에 생성될 값을 전혀 예측할 수 없습니다.

전혀 예측할 수 없는 것이 무엇이 있을까요? 우리는 자연을 완벽하게 예측할 수 없습니다.

기상청의 일기 예보 또한 수많은 빅데이터에 의한 통계일 뿐 정확한 날씨를 예측할 수 없는 것처럼요.

 

의사 난수란

복잡한 알고리즘에 의해 생성된 값입니다.생성된 수열은 컴퓨터가 만들었기 때문에 일정한 주기를 가지며 난수처럼 예측 불가능성을 가질 수 없지만주기가 엄청 크기 때문에 일반적으로 예측하기가 어렵습니다. 즉 게임이나 랜덤 재생 등과 같은 것을 구현할 때 사용하여도 지장이 없을 정도의 수를 의사 난수라고 합니다.가끔 음악 플레이어에서 랜덤하게 음악 목록을 재생시켰지만 한 바퀴가 돌고나면 똑같은 순서로 재생되는 현상이바로 이 의사 난수를 사용했기 때문입니다.

 

서론이 너무 길었죠? 자, 본격적으로 복권 번호 추첨기를 만들어 봅시다!

 

 

New project를 눌러 새로운 프로젝트를 생성합시다.

 

 

 

프로젝트 이름은 Lotto로 하겠습니다.

 

 

 

처음 URP 프로젝트를 만들면 콘솔 창에 이와 같은 메시지가 뜰 수 있습니다.

유니티의 고질적인 문제로 가볍게 무시해주면 됩니다.

두 번째 실행부터는 뜨지않으니 걱정하지 마세요!

 

Hierarchy밑에 있는 +버튼을 눌러 Create Empty를 눌러주세요.

Empty오브젝트가 생성될 겁니다.

 

 

 

GameObject라는 이름으로 다음과 같은 오브젝트가 생성되었습니다.

우측의 inspector를 보면 Transform이외의 어떤 컴포넌트(속성)도 추가되지 않은 것을 보실 수 있습니다.

즉 이 오브젝트는 우리의 씬에 존재는 하지만 눈으로 볼 수도 없고 아직 아무런 기능을 할 수 없습니다.

저는 이 오브젝트의 이름을 Lotto Number Creator로 바꿔주겠습니다.

 

 

 

Project 탭의 Assets를 우클릭하여 Create - C# Script를 눌러줍니다.

 

 

 

이와 같이 NewBehaviourScript라는 스크립트가 생성되었습니다.

이는 Behaviour를 상속 받은 스크립트라는 의미인데 지금 자세하게 다루지는 않겠습니다!

지금은 간단하게 유니티에서 오브젝트에 기능을 부여하는 스크립트라고 생각하시면 됩니다.

저는 이 스크립트의 이름을 Lotto 라고 지어주었습니다.

스크립트를 더블클릭하여 열어줍니다.

저와 함께 지난시간에 유니티를 설치하였다면 비주얼 스튜디오가 기본 툴로 설정되어 실행될 겁니다.

 

 

이 단계에서 중요한 것은 우리가 프로젝트 탭에서 만들었던 스크립트의 이름과 스크립트를 실행하였을 때 보이는 class 의 이름이 동일해야만 한다는 것입니다.

만약 public class Lotto : ~ 가 아닌, public class NewBehaviourScript : ~ 라면 스크립트를 삭제한 후 다시 만들어주세요.

스크립트를 생성하는 단계에서 바로 이름을 바꿔주어야 합니다.

이름을 잘못 지었더라도 수정할 수 있지만 유니티가 처음이신 분들은 삭제 후 재생성하는 방법이 헷갈리지 않고 좋습니다!

 

 

유니티의 MonoBehavior를 상속 받는 class는 유니티의 이벤트 함수가 기본으로 작성되어 있습니다.

Start함수는 주석에 쓰여있듯 첫 번째 프레임이 업데이트 되기 전에 호출됩니다.

간단하게 말해서 시작 시 실행이 된다고 생각하시면 됩니다.

보통 초기 설정을 이 곳에서 해줍니다.

 

 

우리가 만들 게임(응용프로그램)은 다른 말로는 Loop라고 표현할 수 있습니다.

끊임없이 작동하며 기능을 수행하여 하나의 프로그램이 되는 것이죠.

Update함수는 매프레임마다 호출됩니다.

보통 기능을 이곳에서 호출해줍니다.

 

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

public class Lotto : MonoBehaviour
{
    [SerializeField]
    List<int> numList = new List<int>();
    [SerializeField]
    int[] arr = new int[6];

    void Update()
    {
        
    }
}

 

지금 시간에는 Update함수 이외의 다른 함수를 사용하지 않을 것이기 때문에 Start함수를 지워주었습니다.

저는 1부터 45까지의 숫자가 적힌 공을 담아 둘 List와 당첨 번호 여섯 개를 담기 위해 배열을 생성하였습니다.

[SerializeField]를 앞에 붙여준 것은 다른 스크립트에서는 접근이 불가능하되 유니티 에디터에서는 접근할 수 있다는

의미입니다. 자세한 설명은 지금 포스팅에서는 하지 않겠습니다.

 

저는 키보드의 Space 바를 누를 때마다 여섯 개의 로또 번호를 추첨해주는 것을 만들고 싶습니다.

 

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

public class Lotto : MonoBehaviour
{
    [SerializeField]
    List<int> numList = new List<int>();
    [SerializeField]
    int[] arr = new int[6];

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            // Function to run whenever space bar is pressed
        }
    }
}

 

유니티에서 제공하는 Input 클래스를 사용하여 간단하게 구현할 수 있습니다.

if(Input.GetKeyDown(KeyCode.Space))
        {
           이 코드 블럭 안에 기능을 만들어 스페이스 바를 누를 때마다 실행되도록 만들 겁니다.
        }

 

 

void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < 45; i++)
            {
                numList.Add(i + 1);
            }
        }
    }

 

업데이트 함수만 출력하겠습니다.

코드 블럭 안에 포문을 이용하여 아까 만든 45개의 공을 담아둘 리스트에 1부터 45의 번호를 부여하겠습니다.

index를 의미하는 i는 보통의 경우 0부터 시작하기 때문에 (i + 1)을 해주어 0이 아닌 1부터 시작하도록 해줍니다.

 

 

void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < 45; i++)
            {
                numList.Add(i + 1);
            }
            
            for (int i = 0; i < arr.Length; i++)
            {
                int num = UnityEngine.Random.Range(0, numList.Count);
                arr[i] = numList[num];
                numList.RemoveAt(num);  
            }
        }
    }

 

그 다음은 여섯 개의 당첨 번호를 생성할 겁니다.

int 형 num변수에 유니티 엔진의 Random 클래스를 이용하여 1부터 45의 수 중 랜덤으로 한 번호를 뽑을 겁니다.

그 이후 랜덤으로 뽑힌 번호를 당첨 번호 배열에 넣어 줍니다.

로또 시스템은 한 번 뽑힌 번호는 다시 나오지 않기 때문에 45개의 공을 담는 리스트에서 위에서 뽑힌 번호를 제거합니다.

이 과정을 총 여섯 번 포문을 통해 반복해줍니다.

 

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

public class Lotto : MonoBehaviour
{
    [SerializeField]
    List<int> numList = new List<int>();
    [SerializeField]
    int[] arr = new int[6];

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < 45; i++)
            {
                numList.Add(i + 1);
            }
            
            for (int i = 0; i < arr.Length; i++)
       		{
            	int num = UnityEngine.Random.Range(0, numList.Count);
            	arr[i] = numList[num];
            	numList.RemoveAt(num);  
        	}
        	Array.Sort(arr);
        }
    }
}

 

가장 첫 줄에 using System; 을 추가한 것을 보실 수 있는데 이는 System의 Array클래스를 사용하기 위함입니다.

낮은 수부터 높은 수 순서로 출력시키기 위해 Array.Sort(arr);을 하여 정렬을 하였습니다.

 

 

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

public class Lotto : MonoBehaviour
{
    [SerializeField]
    List<int> numList = new List<int>();
    [SerializeField]
    int[] arr = new int[6];

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < 45; i++)
            {
                numList.Add(i + 1);
            }

            for (int i = 0; i < arr.Length; i++)
            {
                int num = UnityEngine.Random.Range(0, numList.Count);
                arr[i] = numList[num];
                numList.RemoveAt(num);
            }

            Array.Sort(arr);

            for (int i = 0; i < arr.Length; i++)
            {
                Debug.Log(arr[i]);
            }
        }
    }
}

 

포문을 배열의 크기만큼 반복하여 배열에 담긴 당첨 번호를 Debug.Log를 통해 콘솔 창에 출력시켜 보겠습니다.

 

 

여기까지 코드를 작성한 후 Ctrl + S 키를 눌러 스크립트를 저장하겠습니다.

스크린샷처럼 Lotto.cs* 스크립트 뒤에 *이 붙어 있다면 아직 저장이 안 되었음을 의미합니다.

저장을 하게되면 뒤에 *은 사라집니다. 

이 상태에서 다시 유니티 에디터로 돌아옵니다.

 

 

 

우리가 작성한 Lotto 스크립트를 드래그 앤 드롭으로 Lotto Number Creator오브젝트에 추가시켜줍니다.

 

 

inspector를 보면 Lotto 스크립트가 추가된 것을 보실 수 있습니다.

이전에 [SerializeField]를 해주었기 때문에 인스펙터에서 리스트와 배열을 확인할 수 있습니다.

 

 

스크립트와 마찬가지로 Hierarchy가 변경되면 씬 옆에 *이 생깁니다.

Ctrl + S를 눌러 저장해줍니다.

 

 

 

에디터의 실행 버튼을 눌러주세요.

 

 

이후 게임 탭을 마우스로 한 번 클릭하여 활성화 해준다음 미리 지정해놓았던 스페이스바를 눌러

로또 번호를 추첨받아 보겠습니다. 

콘솔 창에 36이라는 숫자가 보이네요.

우리는 여섯 개의 숫자를 뽑았는데 하나의 숫자만 나오네요.

당황하지 마시고 콘솔 창을 눌러 확인해보겠습니다.

 

콘솔 탭을 마우스로 클릭하세요!

 

 

위와 같이 콘솔 창이 확장되며 우리가 뽑은 여섯 개의 숫자가 보입니다.

낮은 수부터 높은 수 순으로 잘 정렬된 모습입니다.

지금 당장 해당 번호로 로또를 구매하여도 되겠네요^^!

 

 

 

인스펙터를 확인해보면 총 45개의 리스트 중 6개의 숫자가 당첨 번호가 되어 배열에 저장되었으므로

리스트는 39개의 수만 남아있네요.

 

우리는 스페이스바를 누를 때마다 반복하여 당첨 번호를 생성하기로 했습니다.

그대로 스페이스바를 눌러 다음 여섯개의 당첨 번호를 출력해보도록 하죠~!

 

 

 

두 번째 당첨 번호가 출력되었습니다.

그런데 문제가 생겼군요? 우리의 의도와는 다르게 두 번호가 중복되었습니다.

이렇게 되면 로또 번호 추첨기라고 할 수가 없죠.

그리고 이 현상은 스페이스바를 누르면 누를 수록 더 자주 보이게 됩니다.

해결하러 가보죠!!

 

다시 Lotto 스크립트를 더블 클릭하여 열어줍니다.

지금처럼 중복 번호가 생성되는 현상은 우리가 사용한 리스트와 배열을 초기화하지 않았기 때문에

스페이스 바를 누를 때마다 리스트에 계속 45개의 공이 추가로 들어가 언젠가는 중복 번호가 뽑힐 수 있게 되는 것입니다.

 

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

public class Lotto : MonoBehaviour
{
    [SerializeField]
    List<int> numList = new List<int>();
    [SerializeField]
    int[] arr = new int[6];

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            for (int i = 0; i < 45; i++)
            {
                numList.Add(i + 1);
            }

            for (int i = 0; i < arr.Length; i++)
            {
                int num = UnityEngine.Random.Range(0, numList.Count);
                arr[i] = numList[num];
                numList.RemoveAt(num);
            }

            Array.Sort(arr);

            for (int i = 0; i < arr.Length; i++)
            {
                Debug.Log(arr[i]);
            }

            numList.Clear();
            Array.Clear(arr, 0, 6);
        }
    }
}

 

위와 같이 마지막에 리스트와 배열을 초기화 하는 코드를 추가하였습니다.

이제 다시 저장 후 에디터로 돌아와 실행 후 스페이스바를 반복하여 눌러보면

중복된 번호 없이 매번 정상적으로 새로운 번호를 생성하는 것을 확인하실 수 있을 겁니다!

 

여러분은 이제 로또 번호 추첨기 사이트의 도움 없이 스스로 로또 번호를 생성하실 수 있게 되셨습니다!

축하합니다.!! 스스로 생성한 번호로 로또를 구매하여 당첨되면 더 의미가 있을 겁니다!

행운을 빌게요 :D

 

 

하단에 스크립트를 첨부하였습니다. 

다운을 받아 사용하셔도 됩니다.

Lotto.cs
0.00MB

 

다음 시간에는 위의 프로젝트를 조금 더 재미있게 확인할 수 있도록 UI를 이용하여 꾸며보겠습니다.

다음 시간에 봐요~~!

 

 

글 : 작성자 본인 작성

사진 : 구글링, 본인 캡쳐