파이썬 실전/로또 번호 생성기

파이썬 실전) 로또 번호 생성기 6. 이전회차 당첨번호와 중복되는 번호

마리사라 2021. 2. 21. 01:12
반응형

이번 강의는 로또 번호 생성기에 이전 회차의 번호와 현재 번호의 중복되는 개수를 제한하는 기능을 추가해 보겠습니다.


1. 중복 번호

동행복권 사이트 로또 구매
951회차 당첨 결과

만약 로또를 구매하실 때 이전 회차의 당첨번호와 거의 일치하신다면 어떻게 하시겠습니까? 저라면 심리적으로 같은 번호는 기피하게 될 것 같습니다. 대부분의 사람들은 이전 회차와 중복되는 번호는 피하게 됩니다. 이를 이용해 여러 로또 번호 사이트에서는 이전 회차와 중복되는 번호의 개수를 제한하는 필터링 기능을 만들어 놓은 경우가 많습니다. 이번 강의에서는 이전 회차의 번호와 중복되는 번호의 개수를 제한하는 기능을 만들어 보겠습니다.


2. 코드

저번 강의에서 requests와 BeautifulSoup를 이용해 이전 회차의 당첨번호를 조회하는 코드를 만들었습니다.

2021/02/11 - [파이썬 실전/로또 번호 생성기] - 파이썬 실전) 로또 번호 생성기 5. 이전 회차 당첨번호

 

파이썬 실전) 로또 번호 생성기 5. 이전 회차 당첨번호

이번 강의는 requests와 BeautifulSoup를 이용하여 이전 회차 당첨 번호를 조회하는 코드를 만들어 보겠습니다. 1. 이전 회차 당첨 번호 보통 로또 당첨번호를 조회하실 때에는 네이버에서 확인하실 겁

marisara.tistory.com

 

이전 강의의 이전 회차 당첨번호를 조회하는 함수의 return값을 저장하는 변수를 만들어 줍니다.

self.previous_number = self.extractor()

 

이제 프로그램의 좌상단에 이전회차 당첨번호를 띄워놓도록 하겠습니다. 우선 원래 있던 시행 횟수 입력 칸과 시행 버튼을 아래쪽으로 옮깁니다.

self.count = wx.TextCtrl(panel, id=1, pos=(5, 40))
self.generate_button = wx.Button(panel, id=2, label='생성', pos=(5, 70))

 

그 후 그 자리에 이전회차 당첨번호에 관한 문자를 넣어줍니다.

previous_number_text = wx.StaticText(panel, id=10, label='이전회차 당첨번호\n' + str(self.previous_number), pos=(5, 5))

이때 이전회차 당첨번호는 list 자료형이기 때문에 문자열 자료형으로 변환해서 입력해 주어야 합니다.

 

이번에는 중복되는 번호의 개수를 정해줄 수 있는 기능입니다. 이는 wxPython의 RadioBox기능으로 만들어 보겠습니다.

self.duplicates_list = ['0', '1', '2', '3', '4', '5', '6']
self.duplicates = wx.RadioBox(panel, id=11, label="중복 허용 갯수", pos=(5, 200), size=wx.DefaultSize, choices=self.duplicates_list, majorDimension=3, style=wx.RA_SPECIFY_COLS)

RadioBox는 위처럼 RadioBox에 들어갈 list자료형과 RadioBox본체로 이루어집니다. 이때 list자료형의 모든 원소는 문자열 자료형만 가능합니다.

 

이제 이를 이용해서 중복 번호를 제한하는 코드를 만들어 보겠습니다.

intersection = number & set(self.previous_number)
if len(intersection) > self.duplicates.GetSelection():
    number.remove(list(intersection)[0])

우선 중복 번호를 확인하는 방법으로는 이전 회차의 번호들의 list인 previous_number를 집합화 시킨 후, 랜덤으로 만든 6가지 숫자가 들어있는 number집합과 교집합을 하여 교집합의 개수를 통해 중복 번호의 개수를 파악합니다. if문을 통해 교집합의 원소의 개수를 중복 허용 개수로 선택한 개수보다 많을 경우에 교집합의 원소중 하나를 원래의 집합인 number에서 제외합니다.

 

마지막으로 원래의 코드를 변경된 코드에 맞게 다듬어주면 완성입니다.

def lotto(self, event):
    for i in range(int(self.count.GetValue())):
        number = set()
        if self.fixed_number_check.GetValue():
            number = self.fixed_number(number)
        while len(number) < 6:
            number.add(random.randint(1, 45))
            if len(number) == 6:
                intersection = number & set(self.previous_number)
                if len(intersection) > self.duplicates.GetSelection():
                    number.remove(list(intersection)[0])
                number = list(number)
                number.sort()
                if self.consecutive_number.GetValue():
                    for j in range(len(number) - 1):
                        try:
                            if number[j] + 1 == number[j + 1]:
                                del number[j + 1]
                        except:
                            pass
                if not len(number) == 6:
                    number = set(number)
                    if self.fixed_number_check.GetValue():
                        number = self.fixed_number(number)
        self.output.Append(str(number))

 

이제 결과입니다.

좌 : 중복 가능 0개 / 중 : 중복 가능 3개 / 우 : 중복 가능 6개

중복 허용 갯수가 0개인 경우에는 이전 회차와 중복되는 번호가 하나도 없지만, 중복 허용 개수가 3개와 6개인 경우에는 이전 회차와 중복되는 개수가 존재합니다. 3과 6의 차이가 거의 없어 보이는 것은 이 프로그램으로 이전 회차와 동일한 번호를 만들 확률과 다음 회차와 동일한 번호를 만들 확률(로또에 당첨될 확률)이 같기 때문에 보기는 힘든 경우입니다.


3. 마치며

이번 시간에는 로또 번호에서 이전 회차의 번호와 중복을 허용하는 개수를 조절하는 기능을 만들었습니다. 다음에는 이렇게 만든 숫자를 파일로 저장하는 기능을 만들면서 강의를 마치도록 하겠습니다.

import random
import wx
import requests
from bs4 import BeautifulSoup


class Mainframe(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(300, 450))
        panel = wx.Panel(self)
        self.count = wx.TextCtrl(panel, id=1, pos=(5, 40))
        self.count.SetHint("시행 횟수 입력")
        self.generate_button = wx.Button(panel, id=2, label='생성', pos=(5, 70))
        self.output = wx.ListBox(panel, id=3, choices=[], pos=(130, 5), size=(150, 400))

        fixed_number_box = wx.StaticBox(panel, id=5, label="고정수", pos=(5, 100), size=(80, 50))
        self.fixed_number_1 = wx.TextCtrl(fixed_number_box, id=6, size=(30, 20), pos=(5, 20))
        self.fixed_number_2 = wx.TextCtrl(fixed_number_box, id=7, size=(30, 20), pos=(40, 20))
        self.fixed_number_check = wx.CheckBox(panel, id=8, pos=(100, 120))

        self.consecutive_number = wx.CheckBox(panel, id=9, pos=(10, 160), label="연속수 제거")

        self.previous_number = self.extractor()
        previous_number_text = wx.StaticText(panel, id=10, label='이전회차 당첨번호\n' + str(self.previous_number), pos=(5, 5))

        self.duplicates_list = ['0', '1', '2', '3', '4', '5', '6']
        self.duplicates = wx.RadioBox(panel, id=11, label="중복 허용 갯수", pos=(5, 200), size=wx.DefaultSize, choices=self.duplicates_list, majorDimension=3, style=wx.RA_SPECIFY_COLS)

        self.Bind(wx.EVT_BUTTON, self.lotto, id=2)

    def lotto(self, event):
        for i in range(int(self.count.GetValue())):
            number = set()
            if self.fixed_number_check.GetValue():
                number = self.fixed_number(number)
            while len(number) < 6:
                number.add(random.randint(1, 45))
                if len(number) == 6:
                    intersection = number & set(self.previous_number)
                    if len(intersection) > self.duplicates.GetSelection():
                        number.remove(list(intersection)[0])
                    number = list(number)
                    number.sort()
                    if self.consecutive_number.GetValue():
                        for j in range(len(number) - 1):
                            try:
                                if number[j] + 1 == number[j + 1]:
                                    del number[j + 1]
                            except:
                                pass
                    if not len(number) == 6:
                        number = set(number)
                        if self.fixed_number_check.GetValue():
                            number = self.fixed_number(number)
            self.output.Append(str(number))

    def fixed_number(self, number):
        try:
            fixed_number_1 = int(self.fixed_number_1.GetValue())
            number.add(fixed_number_1)
        except:
            pass
        try:
            fixed_number_2 = int(self.fixed_number_2.GetValue())
            number.add(fixed_number_2)
        except:
            pass
        return number

    def extractor(self):
        url = "https://dhlottery.co.kr/common.do?method=main"
        query = requests.get(url=url)
        soup = BeautifulSoup(query.content, "html.parser")
        no_1 = soup.find("span", {"id": "drwtNo1"})
        no_2 = soup.find("span", {"id": "drwtNo2"})
        no_3 = soup.find("span", {"id": "drwtNo3"})
        no_4 = soup.find("span", {"id": "drwtNo4"})
        no_5 = soup.find("span", {"id": "drwtNo5"})
        no_6 = soup.find("span", {"id": "drwtNo6"})
        extract_number = [int(no_1.get_text()), int(no_2.get_text()), int(no_3.get_text()), int(no_4.get_text()),
                          int(no_5.get_text()), int(no_6.get_text())]
        return extract_number


def run():
    app = wx.App()
    frame = Mainframe(None, -1, 'Lotto Number Generator')
    frame.Show()
    app.MainLoop()


run()
반응형