포스트

지난주 당첨번호를 만들어 낸 사주와 차번호를 찾아봤습니다

사주로또와 차번호 로또에 새 기능을 넣었습니다. 지난 회차 당첨번호 여섯 개를 그대로 만들어 내는 생년월일이나 차번호가 있었는지 매주 전수로 찾아 보여 줍니다. 같은 기능인데 두 앱의 성질이 정반대라 문구도 다르게 썼습니다. 사주는 절반 넘는 주에 아예 없고, 차번호는 매주 200대 넘게 나옵니다

지난주 당첨번호를 만들어 낸 사주와 차번호를 찾아봤습니다

Info

Two of our lottery number apps now look backwards. Every week a job searches for the birth charts and the license plates whose app generated numbers exactly match the real winning six. The two apps behave in opposite ways: the birth chart space is smaller than the number of lotto combinations, so most weeks produce nothing, while the plate space is forty two times larger, so roughly two hundred plates match every single week. The wording had to change with the arithmetic.

사주로또와 차번호 로또는 입력을 넣으면 번호를 뽑아 주는 앱입니다. 같은 사주면 같은 주에 늘 같은 번호가 나옵니다. 그렇다면 거꾸로 물어볼 수 있습니다. 지난주 당첨번호를 그대로 만들어 내는 입력이 있었을까요?

먼저 짚을 것

이건 예측이 아닙니다. 추첨 결과를 알고 나서 거꾸로 찾는 사후 대조입니다. 누가 실제로 그 번호를 샀다는 뜻도 아닙니다. 그래서 앱 어디에도 “1등”이라고 쓰지 않았습니다. 그 한 단어가 들어가는 순간 “우리 앱이 맞혔다”로 읽히기 때문입니다.

두 앱이 정반대였습니다

로또 6/45의 조합은 8,145,060가지입니다. 이 숫자와 각 앱의 입력 공간을 비교하면 성질이 갈립니다.

앱입력 공간로또 조합 대비
사주로또816,6860.1배
차번호 로또346,500,00042배

사주는 생년월일에 태어난 시와 성별을 곱한 것이고, 차번호는 앞자리와 한글 한 글자와 뒷자리 네 자리를 곱한 것입니다.

사주는 후보가 모자랍니다. 1231회부터 1243회까지 열세 회차를 전부 돌려 보니 일곱 번만 나왔습니다. 없는 주가 절반 가까이 됩니다. 그래서 못 찾은 주에는 가장 최근에 찾은 회차를 그대로 보여 줍니다.

차번호는 넘칩니다. 조합 수가 로또보다 마흔 배 넘게 많으니 안 나오는 주가 없습니다. 1243회를 전수로 훑어 보니 206대였습니다. 여기서 “드물게 나온 일”처럼 쓰면 거짓말이 됩니다. 그래서 문구를 “찾아봤어요”로 두고, 왜 여러 대가 나오는지를 카드에 같이 적었습니다. 설명이 없으면 사용자는 우리가 숫자를 지어낸다고 의심하게 됩니다.

번호판은 한 자리를 가립니다

차번호는 실존하는 차 한 대를 특정합니다. 생년월일은 수천 명이 공유하지만 번호판은 그렇지 않습니다. 그래서 숫자 한 자리를 가려서 보여 줍니다. 가리는 자리는 매주 바뀌고 줄마다 다릅니다.

가린 자리 후보는 열 개뿐이라 넣어 보면 찾아집니다. 숨기기에는 허술하지만 그게 요점입니다. 직접 확인할 수 있어야 지어낸 게 아니라는 걸 보여 줄 수 있습니다. 앱에 그 번호판을 넣으면 카드에 적힌 그 게임에서 당첨번호가 그대로 나옵니다.

한글은 가리지 않았습니다. 후보가 서른다섯 개로 늘어 확인하려는 사람에게 너무 가혹합니다.

왜 기기에서 안 돌리나

차번호 전수 탐색은 3억 4,650만 대를 훑습니다. 앱이 쓰는 생성 코드를 그대로 쓰면 다섯 시간이 걸립니다. 휴대폰에서 할 일이 아닙니다.

그래서 깃허브 액션이 매주 일요일 아침에 한 번 계산하고, 앱은 결과만 받아 갑니다. 당첨번호 자체도 이미 매주 자동으로 갱신하고 있어서 그 뒤에 붙였습니다.

훑을 때는 가지치기를 씁니다. 앱과 같은 순서로 번호를 뽑되 당첨번호에 없는 수가 나오는 순간 그 후보를 버립니다. 여섯 개를 다 뽑을 필요가 없으니 후보당 해시가 서른다섯 번에서 여섯 번으로 줄어듭니다.

여기에 코어를 나눠 씁니다. 한 스레드로 45분이던 것이 여덟 스레드에서 9분 23초가 됐습니다. 같은 회차로 두 방식을 돌려 결과 파일이 생성 시각 말고는 한 글자도 다르지 않은 것을 확인했습니다.

방식속도전수 탐색
앱 코드 그대로초당 18,700대308분
가지치기초당 121,000대45분

다만 가지치기는 앱 로직을 손으로 옮긴 것이라 어긋날 수 있습니다. 그래서 찾은 것은 전부 앱 코드로 다시 확인합니다. 수백 건뿐이라 비용이 들지 않습니다. 옮기기 전에 차분 검사도 했습니다. 아는 정답 세 건을 포함한 쉰일곱 대와 무작위 삼백만 대에서 두 방식의 결과가 한 건도 다르지 않았습니다.

가린 자리를 여는 것도 앱이 계산합니다

정답을 파일에 실어 보내지 않습니다. 그 파일은 공개 주소라 누구나 열어볼 수 있어서, 거기 정답을 넣으면 가린 의미가 없습니다.

대신 앱이 0부터 9까지 직접 넣어 보고 맞는 하나를 고릅니다. 사용자가 손으로 열 번 넣어 보는 것과 완전히 같은 계산입니다. 그래서 결과를 믿을 수 있습니다.

남은 이야기

처음에는 번호판을 가린 채로만 두려고 했습니다. 가리면 검증이 안 되니 오히려 못 믿을 것이 된다는 지적을 받고 방향을 바꿨습니다. 가리는 것과 검증되는 것은 같이 갈 수 없어 보였는데, 후보를 열 개로 좁혀 두면 둘 다 얻을 수 있었습니다. 가려서 특정 차를 지목하지 않고, 열어 보면 확인은 됩니다.

별자리 로또와 내 이름 로또에는 넣지 않았습니다. 별자리는 행운수 세 개 중 두 개가 강제로 들어가는 구조라 당첨번호가 아예 도달 불가능한 회차가 육 할입니다. 이름은 막히진 않았지만 그럴듯한 이름 팔만 개로는 한 건도 안 나옵니다. 기대치를 한 건으로 올리려면 백만 단위 이름이 필요한데, 그러면 실존하지 않는 이름이 대부분이라 보여줄 만한 것이 못 됩니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.