로또 번호 생성 알고리즘 파이썬 - lotto beonho saengseong algolijeum paisseon

[파이썬] 로또 번호 생성기 ② -random.choice 함수

로또 번호 생성 알고리즘 파이썬 - lotto beonho saengseong algolijeum paisseon

2018. 5. 28. 19:05

중1 아이가 파이썬으로 로또 번호를 생성하는 프로그램을 짜고 있길래, random.choice 함수를 사용해서 알고리즘을 만들어 보라고 하였다. random.choice 함수는 리스트(list)를 인자로 받아서 리스트 중의 하나의 객체를 임의로 추출하게 된다.

번호 추출 알고리즘

1) range 함수로 1 ~ 45까지의 정수를 만든 다음에 list 함수를 사용하여 리스트로 변환시킨다.
2) 6개 번호를 추출하여 담을 빈 리스트를 만들어서 lotto라는 변수에 할당한다.
3) while 반복문을 사용하여 lotto 리스트에 6개의 숫자가 선택될 때까지 반복 추출한다.
4) random 모듈의 choice 함수로 45개 숫자 중에서 한 개를 골라 num 변수에 할당한다.
5) 추출한 수(num)가 lotto 리스트에 없으면, append 함수를 써서 리스트에 추가한다.
6) lotto 리스트를 print 한다.

코딩 예제

로또 번호 생성 알고리즘 파이썬 - lotto beonho saengseong algolijeum paisseon

실행 결과

로또 번호 생성 알고리즘 파이썬 - lotto beonho saengseong algolijeum paisseon

  • #파이썬
  • #파이썬로또
  • #로또번호
  • #로또생성
  • #파이썬코딩
  • #random
  • #randomchoice
  • #randomshuffle
  • #번호생성기

파이썬을 이용해 로또번호생성기를 만들어보자.

기획의도
- 단순 난수생성기(.random)이 아닌 내가 원하는 알고리즘에 대한 가중치를 두어 번호를 생성하도록 한다.
- 화면을 만들어 콘솔 화면이 아닌 창에서 확인할 수 있도록 한다.
- 실행프로그램(.exe)으로 만들어 파일을 가진 누구나 실행을 할 수 있도록 한다.

동작방식
- 화면상의 버튼을 클릭하면 메세지박스로 로또번호 6개를 생성한다.
- 로또번호는 생성될 때 랜덤으로 생성되도록 한다.
- 랜덤으로 생성되는 숫자는 이전에 당첨번호들에 영향을 줄 수 있는 가중치를 부여한다

주의사항
- 난수 생성시 중복되는 숫자가 발생하지 않도록 처리한다.

가중치
- 이전에 당첨된 번호는 다음 당첨번호와 관계가 있다.

cf.
기본적으로 로또번호 중 '1' 이라는 숫자가 나올 가능성은 1/45이며 다음으로 '2'에 대한 확률은 1/44가 된다.
여기에서 '1'과 '2'를 다른 숫자로 바꾸더라도 확률은 변하지 않는다. 뭐 독립시행이라 하는데,
근데 로또 당첨 숫자들을 보면 유독 당첨 번호에 잘나오는 숫자들이 보이기도 하고, 마치 패턴이 있는 것 처럼 연속되는 정보들이 가끔씩은 보이는 것도 같다. (본인 피셜)
그래서 이번 로또번호 생성기에서의 가중치 설정은
1회차 당첨번호가 [10,23,29,33,37,40] 이고 2회차가 [9,13,21,25,32,42,2] 라면 1회차의 당첨번호가 나왔을 때 2회차의 당첨번호들이 다음에 나올 가능성이 높다. 라는 가정하에 가중치 비율을 추가하는 방식으로 로또생성기를 만들고자 한다.

======
해당 당첨번호를 정리하여 1회차에서부터 978회차(08.28)까지 당첨번호를
board = ([10,23,29,33,37,40,16],[9,13,21,25,32,42,2],[11,16,19,21,27,31,30],...,[2,9,10,14,22,44,16], [1,7,15,32,34,42,8])
로 선언하여 관리한다.
이부분은 개인적 취향에 따라 메모장이나 엑셀로 저장한 뒤 fopen 또는 selenium을 이용하여 읽어와도 무방하다.

그러고 난 뒤 가중취를 저장할
45*45 사이즈의 배열을 할당하고
gravity = [[0] * 45 for _ in range(45)]

마지막 당첨번호의 각 당첨번호를 변수에 할당한다.
destiny_num1 = board[len(board)-1][0]
destiny_num2 = board[len(board)-1][1]
destiny_num3 = board[len(board)-1][2]
destiny_num4 = board[len(board)-1][3]
destiny_num5 = board[len(board)-1][4]
destiny_num6 = board[len(board)-1][5]

여기까지가 완료가 되면
각 당첨번호들에 대한 가중치 적용을 위해

numpy를 이용하여 각 당첨번호들을 재할당한 뒤,
마지막 당첨번호의 당첨 위치를 확인하고 select_num에 저장한다.
board = numpy.array(board)
select_num = numpy.where(board == destiny_num1)[0]

그다음은 2중 for문을 이용하여 당첨번호(1)가 동일하게 존재하는 회차를 찾고 그 다음에 당첨번호(2)를 확인하여
가중치 배열에 해당 당첨번호(2)에 대해 가중치(2) 를 부여한다.
이 때 가중치는 조율 가능하다(가중치 값에 따라 영향도를 크게 혹은 작게 줄일 수 있다).

for i in range(7):
for j in range(len(select_num)):
if len(board) - (select_num[j]+1) > 0 :
gravity[destiny_num1-1][(board[select_num[j]+1][i])-1] += 2
else :
continue

이와 같은 작업을 당첨번호 7개(보너스 포함)에 대해 모두 동일하게 진행을 한다.

그리고 난수생성기(.random)을 이용하여 당첨번호를 생성한다.
이때 앞서 생성한 가중치를 부여한다.

함수를 생성하는데,
random.choices("범위", "가중치")를 이용하면 가중치를 부여할 수 있는데
범위와 가중치를 1대1로 대응시키면 된다.
또한 생성된 숫자가 앞서 생성된 숫자 들 중 중복값은 없는지 확인 후
중복생성된 경우 중복이 아닐 때까지 while문을 이용하여 재생성 시킨다.
이후 생성된 숫자를 .sort() 이용하여 정렬시키고 반환한다.

def 함수명():
bunholist=[]
for i in range(1):
a = random.choices("로또번호 1- 45",gravity[destiny_num1-1])
bunholist.append(a)

...중략(반복)


a = random.choices("로또번호 1- 45",gravity[destiny_num6-1])
while a in bunholist:
a = random.choices("로또번호 1- 45",gravity[destiny_num6-1])
bunholist.append(a)

bunholist.sort()
return bunholist

여기까지 진행하면 번호를 생성하는데는 아무 문제가 없다.
앞서 생성한 함수만 실행하면 번호가 생성될 것이다.
사용성을 좀더 쉽게 하기 위해

창을 생성한다. 창은 tk를 이용하여 생성한다.
창 크기를 설정하고 탭을 생성한다(해당 탭을 이용해 추가 기능들을 부여가 가능해질 수 있기 때문에 확장성을 고려하여 탭 안에 생성)
탭의 이름을 정하고 메뉴도 만들어 간단하게 종료버튼과 버전정보 확인 메뉴를 생성한다.

root = tk.Tk()
root.title("Decoder")
notebook=tkinter.ttk.Notebook(root, width=200, height=200)
notebook.pack()
tab1=tkinter.Frame(root)
notebook.add(tab1, text=" Lotto ")
menubar = tk.Menu(root)

def close():
root.quit()
root.destroy()

def func_open() :
messagebox.showinfo("버전", "20210901_0.1v")

filemenu = tk.Menu(menubar)
filemenu.add_command(label="exit", command=close)
menubar.add_cascade(label="File", menu=filemenu)

filemenu2 = tk.Menu(menubar)
filemenu2.add_command(label="info", command=func_open)
menubar.add_cascade(label="help", menu=filemenu2)

root.config(menu=menubar)

이후,
탭 내에 버튼을 생성하여 버튼 클릭시 로또생성 함수를 동작하도록 설정한다.
이 때 로또번호의 값을 메세지 박스로 띄우도록 한다.

def getTextInput():
messagebox.showinfo("당첨번호", 함수명())

btnRead=tk.Button(tab1, height=2, width=20, text="생성", command=getTextInput)
btnRead.place(x=30, y=60)

여기 까지 완료가 되었다면 메세지박스를 통해서 로또번호가 생성되는 것을 확인 할 수 있을 것이다.
이 후에는 #pyinstaller를 이용하여 실행파일로 생성만 하면 끝.

======전체 소스 코드======

import numpy
import random
import tkinter as tk
from tkinter import Menu
import tkinter.ttk
from tkinter import messagebox

root = tk.Tk()
root.title("Decoder")
notebook=tkinter.ttk.Notebook(root, width=200, height=200)
notebook.pack()
basic = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45

tab1=tkinter.Frame(root)
notebook.add(tab1, text=" Lotto ")

menubar = tk.Menu(root)

def close():
    root.quit()
    root.destroy()

def func_open() :    
    messagebox.showinfo("버전", "20210831_0.1v")


filemenu = tk.Menu(menubar)
filemenu.add_command(label="exit", command=close)
menubar.add_cascade(label="File", menu=filemenu)
filemenu2 = tk.Menu(menubar)
filemenu2.add_command(label="info", command=func_open)
menubar.add_cascade(label="help", menu=filemenu2)
root.config(menu=menubar)
gravity = [[0] * 45 for _ in range(45)]
board = [[0] * 7 for _ in range(10000)]

board = ([10,23,29,33,37,40,16],...(이부분은 너무 길어 중략....) [1,7,15,32,34,42,8])

destiny_num = [board[len(board)-1][0],board[len(board)-1][1],board[len(board)-1][2],board[len(board)-1][3],board[len(board)-1][4],board[len(board)-1][5]]
board = numpy.array(board)

for t in range(6):
    select_num = numpy.where(board == destiny_num[t])[0]    
    for i in range(7):
        for j in range(len(select_num)):
            if len(board) - (select_num[j]+1) > 0 :            
                gravity[destiny_num[t]-1][(board[select_num[j]+1][i])-1] += 100            
            else :
                continue

def qordjr():
    alist=[]     
    for i in range(6):                    
        a = random.choices(basic,gravity[destiny_num[i]-1])
        while a in alist :
            a = random.choices(basic,gravity[destiny_num[i]-1])        
        alist.append(a)       
    alist.sort()  
    return alist

def getTextInput():    
    messagebox.showinfo("당첨번호", qordjr())

btnRead=tk.Button(tab1, height=2, width=20, text="생성", command=getTextInput)
btnRead.place(x=30, y=60)

=====================

.마치며
현재 로또번호 생성기는 매회차 당첨번호를 소스코드에 수동으로 추가해야 하는 불편함이 존재하기 때문에 사용성이 떨어진다. 이 후에 로또생성기2에서는 크롤러를 이용하여 매회차 당첨번호를 자동으로 저장하고 가중치 외에 추가적인 요소를 추가해보도록 하겠다.