프로젝트: 로또 시뮬레이션

타키탸키·2021년 1월 28일
0

Python 입문하기

목록 보기
13/14
post-thumbnail

이제 본격적으로 Python을 이용하여 프로젝트 하나를 진행해봅시다.

💎 프로젝트 개요

새 프로젝트의 주제는 로또 시뮬레이션 프로그램입니다. 그리고 지금부터 우리가 해야할 것은 로또 시뮬레이션을 위한 함수들을 작성하는 것입니다. 어떤 함수들을 사용할 지 생각해보기 전에 로또 시뮬레이션 프로그램의 규칙을 함께 봅시다.

[로또 시뮬레이션 규칙]

  • 로또는 주 1회씩
    1-1. 단, 한 사람이 한 회차에 여러 번 참여 가능
  • 번호는 1부터 45까지
    2-1. 매주 6개의 '일반 당첨 번호'와 1개의 '보너스 번호' 추출
    2-2. 참가자는 한 번 참여할 때마다 서로 다른 번호 6개를 선택
  • 당첨 액수 규칙
    3-1. 뽑은 번호 6개와 일반 당첨 번호 6개 모두 일치(10억원)
    3-2. 뽑은 번호 5개와 일반 당첨 번호 5개 일치 / 뽑은 번호 1개와 보너스 번호 일치(5천만원)
    3-3. 뽑은 번호 5개와 일반 당첨 번호 5개 일치(100만원)
    3-4. 뽑은 번호 4개와 일반 당첨 번호 4개 일치(5만원)
    3-5. 뽑은 번호 3개와 일반 당첨 번호 3개 일치(5천원)

다음으로, 필요한 함수들을 함께 봅시다.

❗ generate_numbers

이 함수는 파라미터로 정수를 받습니다. 1과 45 사이에서 임의의 서로 다른 번호 n개를 뽑고 그 번호들이 담긴 리스트를 리턴합니다.

예시를 한 번 봅시다.

print(generate_numbers(6))
[24, 7, 12, 9, 36, 42]

위 코드를 또 한 번 실행하면 다른 결과가 나옵니다.

이 함수는 참가자의 번호를 뽑을 때도 사용하지만 당첨 번호 7개를 뽑을 때도 사용 가능합니다.

❗ draw_winning_numbers

일반 당첨 번호 6개와 보너스 번호 1개가 포함된 리스트를 리턴하기 위해 draw_winning_numbers라는 함수가 필요합니다. 일반 당첨 번호 6개는 정렬된 상태로 있어야 하고, 보너스 번호는 그 마지막에 추가합니다.

예시를 봅시다.

print(draw_winning_numbers())
[6, 8, 10, 15, 22, 39, 16]

앞에서 정의한 generate_numbers 함수를 잘 활용하면 간결하게 이 함수를 작성할 수 있습니다.

❗ count_matching_numbers

이 함수는 파라미터리스트 list_1st와 리스트 list_2nd를 받고, 두 리스트 사이에 중복되는 번호의 개수를 리턴합니다.

예시를 보겠습니다.

print(count_matching_numbers([3, 7, 11, 24, 37, 41], [4, 7, 9, 24, 26, 41]))
3

7과 24, 41 세 수가 중복되기 때문에 3이 나옵니다.

❗ check

참가자의 당첨 금액을 리턴하는 함수입니다. 파라미터참가자가 뽑은 번호가 담긴 리스트nums_list와 주최측에서 뽑은 번호가 담긴 리스트 winning_nums_list를 받습니다. nums에는 6개의 번호가 담겨 있고, winning_nums에는 보너스 번호까지 포함해서 7개의 번호가 담겨 있습니다.

예시를 봅시다.

test_nums = [3, 7, 11, 24, 37, 41]
test_winning_nums = [4, 7, 9, 24, 26, 41]

print(check(nums_list, test_winning_nums))
5000

3개가 중복되기 때문에 상금 5000원을 받습니다.

💎 번호 뽑기

함수를 하나씩 만들어 가며 단계를 진행해봅시다.

먼저, 임의의 번호를 뽑는 함수 generate_numbers를 만들어보겠습니다.

앞서 임의의 번호를 추출하기 위해 스탠다드 라이브러리에 존재하는 모듈 random에 대해 배웠습니다. 그리고 모듈을 불러오기 위해서는 import라는 것을 사용해야 했죠?

import random

def generate_numbers(n):

새로운 함수를 정의하기 위해 def문까지 작성해봤습니다. 함수 generate_numbers는 파라미터로 정수 n을 받는다는 것을 잊지 마세요.

다음으로 해야할 일은 리스트를 반환하기 위해 새로운 리스트를 만들어주는 것입니다. 이 리스트 안에는 임의의 숫자들이 저장될 예정입니다.

nums = []

우리가 해야할 일은 n개의 번호를 리스트에 담는 것입니다. 이를 위해 반복 작업이 필요할 것 같습니다. 따라서, while문을 작성해야 합니다. while문의 조건 부분에는 리스트 길이가 n을 넘을 때 종료된다는 조건을 추가해줘야 합니다.

while len(nums) < n:

규칙에 따르면, 번호는 1부터 45까지 존재합니다. 따라서, 무작위로 뽑는 수의 범위를 1부터 45로 지정해줘야겠죠? 특정 범위에서 임의의 정수를 추출하려면 어떤 함수가 필요했었죠? 맞습니다! randint가 필요합니다.

while len(nums) < n:
    random_num = random.randint(1, 45)

그런데 randint를 while문 이전에 미리 정의하지 않은 이유가 뭘까요? 우리는 서로 다른 임의의 수가 필요합니다. 만약 randint가 while문 밖에서 정의된다면 하나의 값만 나오게 됩니다. 따라서, randint를 반복해서 호출해야 서로 다른 임의의 수를 얻을 수 있는 것이죠.

또 하나 주의해야 할 것이 있습니다. 새로 얻은 이 수들을 리스트에 무작정 추가하면, 중복값이 생길 수 있습니다. 로또는 서로 다른 수들이 나와야 합니다. 중복값을 없애기 위해 새로 얻은 수가 리스트에 없을 때만 추가를 하도록 제한을 걸어야 합니다.

if random_num not in nums:
    nums.append(random_num)

if의 수행 부분에는 append를 사용해서 새로 얻은 수들을 하나씩 리스트에 집어 넣도록 합시다.

마지막으로 반복문에서 나오면 n개의 번호들이 리스트에 추가됩니다. 그럼 이 리스트를 반환하기만 하면 되겠죠?

return nums

이제 완성된 코드를 한 번에 봅시다.

import random

def generate_numbers(n):
    nums = []
    
    while len(nums) < n:
        random_num = random.randint(1, 45)
        
        if random_num not in nums:
            nums.append(random_num)
    
    return nums

💎 당첨 번호 뽑기

이번에는 당첨 번호를 뽑아 봅시다. 앞서 임의의 수를 뽑는 함수를 만들었으니 당첨 번호를 뽑는 함수를 정의하기가 훨씬 수월해졌습니다.

규칙을 보면 당첨 번호에는 6개의 일반 번호와 1개의 보너스 번호가 추출된다고 합니다. 이때, 6개의 일반 번호는 정렬된 상태로 있어야 하고 보너스 번호는 추가적으로 뽑기 때문에 정렬의 영향을 받지 않아야 합니다.

위 규칙을 실현할 수 있는 두 가지 사례를 보여드리겠습니다.

import random

def draw_winning_numbers():

    winning_nums = sorted(generate_numbers(6))
    bonus_num = random.randint(1, 45)
    
    if bonus_num not in winning_nums:
        winning_nums.append(bonus_num)
    else:
        bonus_num = random.randint(1, 45)
        if bonus_num not in winning_nums:
            winning_nums.append(bonus_num)
        
    return winning_nums

첫 번째 방법은 이렇습니다.

  1. 정렬 된 6개의 숫자 리스트를 winning_nums 리스트에 저장
  2. 임의의 수 한 개를 뽑아 bonus_num에 저장
  3. 중복을 피하기 위해 bonus_num이 리스트에 없을 때만 리스트에 추가
  4. 중복된 수라면 다시 수를 뽑고 없는지 확인한 뒤 리스트에 추가
  5. 리스트 반환

3번 조건이 필요한 이유는 보너스 번호라 하더라도 일반 번호 6개와 중복이 되지 않아야 하기 때문입니다. 그러나 위 방법의 경우, 조건문이 반복해서 등장하여 다소 코드가 지저분해 보입니다.

두번째 방법은 아주 간결한 코드로 표현할 수 있습니다.

우선, 번호를 7개 뽑아 봅시다. generate_numbers 함수를 사용하면 되겠죠? 그리고 그 결과를 활용하기 위해 변수에 저장해줍시다.

winning_nums = generate_numbers(7)

6개의 정렬된 수와 보너스 번호를 따로 뽑기 위해 리스트 슬라이싱을 활용해봅시다. 두 개의 리스트를 뽑되, 하나는 정렬을 해야하고 정렬한 후에는 나머지 리스트와 연결되어야 합니다. 이를 코드로 표현하면 다음과 같습니다.

sorted(winning_nums[:6]) + winning_nums[6:]

이제 위 코드를 리턴해주기만 하면 됩니다. 따라서, 완성된 모습은 이렇습니다.

import random

# generate_numbers 생략

def draw_winning_numbers():
    winning_nums = generate_numbers(7)
    return sorted(winning_nums[:6]) + winning_nums[6:]

💎 중복된 번호 개수

이제 참가자가 뽑은 번호와 당첨 번호가 일치하는지 매칭하는 함수가 필요합니다. count_matching_numbers는 파라미터로 리스트 두 개를 받아 두 리스트 사이에 중복되는 번호 개수를 리턴합니다.

우선, 개수를 담을 수 있는 변수 count를 선언합시다. 그 다음에는 첫번째 리스트에 있는 수들이 두번째 리스트와 중복될 때마다 count의 수가 하나씩 증가하도록 해야 합니다. for문을 사용해 봅시다.

count = 0

for i in range(len(list_1st)):
    if list_1st[i] in list_2nd:
        count += 1        

이렇게 하면 첫번째 리스트의 길이만큼 수행 부분이 실행되어 두번째 리스트와 계속해서 비교를 하게 됩니다. 중복 여부는 if문을 통해 첫번째 리스트의 요소가 두번째 리스트에 있는지 확인하면 됩니다. 이제 count를 리턴하는 일만 남았습니다.

이렇게 해서 완성된 코드의 모습은 이렇습니다.

def count_matching_numbers(list_1st, list_2nd):
    
    count = 0
    
    for i in range(len(list_1st)):
        if list_1st[i] in list_2nd:
            count += 1
    
    return count

💎 당첨금 확인

마지막 단계입니다. 앞서 작성한 count_matching_numbers 함수를 사용해서 뽑은 번호와 당첨 번호 사이에 중복된 숫자의 개수를 구하고 그 숫자에 따라 당첨금을 출력해주는 check함수를 정의해야 합니다.

당첨금 규칙은 상단의 프로젝트 개요를 확인하면 됩니다.

check 함수는 참가자의 당첨 금액을 리턴하고 파라미터참가자가 뽑은 번호가 담긴 리스트 nums와 당첨 번호가 담긴 리스트 winning_nums를 받습니다. nums에는 6개의 번호가 있고 winning_nums에는 보너스 번호 1개를 포함해서 7개의 번호가 있습니다.

check 함수에서 가장 중요한 것은 6개의 당첨 번호와의 중복 개수와 1개의 보너스 번호와의 중복 개수를 따로 구해야 한다는 점입니다. 이를 위해서는 각각의 경우를 다른 변수에 저장해두어야 합니다. 아래 코드를 함께 보시죠.

def check(nums, winning_nums)

    count = count_matching_numbers(nums, winning_nums[:6])
    bonus_count = count_matching_numbers(nums, winning_nums[6:])

앞서 일반 번호와 보너스 번호를 별도로 추출할 때 리스트 슬라이싱을 활용했습니다. 이번에도 리스트 슬라이싱을 통해 두 리스트를 구분하고 각각 다른 변수에 저장한 뒤 count_matching_numbers를 호출했습니다.

다음으로 필요한 과정은 규칙에 따라 당첨금을 배분하는 작업입니다. 이런 경우에 특화된 구문이 있죠? 바로 if문입니다.

if count == 6:
        return 1000000000
    elif count == 5 and bonus_count == 1:
        return 50000000
    elif count == 5:
        return 1000000
    elif count == 4:    
        return 50000
    elif count == 3:
        return 5000
    else:
        return 0

첫번째 elif문을 보면 당첨 번호와 보너스 번호의 별도로 구분하여 당첨금을 지급하는 규칙이 잘 실현되어 있습니다. 마지막에 else를 통해 나머지 경우에 당첨금을 받을 수 없다는 규정도 표현했습니다.

💎 함수 합치기

이제 드디어 작성했던 모든 함수를 한 곳에 모아 하나의 프로젝트를 완성해보겠습니다. 만약 모든 함수가 오류없이 동작한다면 프로젝트는 성공한 것입니다.

Pycharm을 열고 lottery.py라는 새 파일을 만듭시다. 그리고 작성한 함수들을 모두 이 파일 안에 넣어주세요. 이제 이 파일은 하나의 모듈이 되었습니다.

모듈이라는 것은 다른 파일에서 활용이 가능한 파일이라고 배웠었죠? 이제 여러분들은 이 lottery.py 파일을 가지고 여러가지 활용을 시도해볼 수 있습니다.

한 가지 예로, html 코드를 활용하여 lotter.py 파일의 결과를 시각화해서 웹상에 띄울 수도 있습니다. 이에 필요한 과정은 분량상 생략하고 그 결과물만 보여 드리겠습니다.


이렇게 Python을 응용한 첫 번째 프로젝트가 마무리되었습니다!

사실 Python의 문법만 공부해서는 이 코드들이 어떻게 프로그램화되는지 알 수 없는 경우가 많은데요. 따라서, 여러 프로젝트를 통해 Python의 코드가 결과물로 실현되는 과정을 체험해보는 것이 정말 중요합니다.

다음 시간에는 또 다른 프로젝트로 찾아뵙겠습니다. 안녕!🥳🥳🥳

* 이 자료는 CODEIT의 '프로그래밍 기초 in Python'을 기반으로 작성되었습니다.
profile
There's Only One Thing To Do: Learn All We Can

0개의 댓글