Python3 簡単な抽選システムを作る

前回の記事

mi12cp.hatenablog.com

ではcsvファイルをpythonで読み込むことを行いました。 今回はこれを用いて簡単な抽選システムを作ります。

要件

  • とある無料の公演では100名分の座席に対し、200名程度の観覧希望者がいると見込まれる。
  • 公演の三時間前に会場前にて事前応募の申し込みを開始する。
  • 観覧希望者は会場前でもらった応募用紙に希望人数を記入し提出する、申込番号が書かれた半券を持ち帰る。
  • 観覧希望者が複数人のグループの場合、一つの応募用紙に希望人数を記入する。
  • 公演の30分前までに何らかの方法で抽選を行い、会場前に当選した申込番号を印刷して掲示する。

設計

  • 申込番号と希望人数の組は表計算ソフト等で入力し、csvファイルに書き出す。
  • そのcsvファイルをpythonで処理し、当選した申込番号を出力する。

実装

csvファイルの例(applications.csv)

id,num,,,,
1,1,,,,
2,1,,,,
3,1,,,,
4,1,,,,
5,2,,,,
6,2,,,,
7,2,,,,
8,3,,,,
9,3,,,,
10,4,,,,
(省略)
191,1,,,,
192,1,,,,
193,1,,,,
194,1,,,,
195,2,,,,
196,2,,,,
197,2,,,,
198,3,,,,
199,3,,,,
200,4,,,,
,,,,,
,,,,,
,,,,,

プログラム(applications.py)

import sys
import pandas as pd
import random

MAX_COUNT = 100

if (len(sys.argv) != 2):
    print('Usage: # python {} filename.csv'.format(sys.argv[0]))
    quit()
filename = sys.argv[1]
df = pd.read_csv(filename)

applications = []
for index, row in df.dropna(subset=['id']).iterrows():
    applications.append({
        'id': int(row['id']),
        'num': int(row['num'])
    })

# csvファイルの全列挙と合計人数の表示
print('全応募者')
num_sum = 0
for row in applications:
    print('id: {}, num: {}'.format(row['id'], row['num']))
    num_sum += row['num']
print('sum : {}'.format(num_sum))
print()

# 抽選処理
random_list = list(range(0, len(applications)))
random.shuffle(random_list)
applications_passing = []
applications_failure = []
applications_passing_num_count = 0
for index, random_index in enumerate(random_list):
    if applications_passing_num_count >= MAX_COUNT:
        for failure in random_list[index:]:
            applications_failure.append(applications[failure])
        break
    if applications_passing_num_count + applications[random_index]['num'] <= MAX_COUNT:
        applications_passing.append(applications[random_index])
        applications_passing_num_count += applications[random_index]['num']
    else:
        applications_failure.append(applications[random_index])
applications_passing.sort(key=lambda x:x['id'])
applications_failure.sort(key=lambda x:x['id'])

# 当選者・落選者の列挙と合計人数の表示
print('当選者')
passing_sum = 0
for passing in applications_passing:
    print('id: {}, num: {}'.format(passing['id'], passing['num']))
    passing_sum += passing['num']
print('sum : {}'.format(passing_sum))
print()

print('落選者')
failure_sum = 0
for failure in applications_failure:
    print('id: {}, num: {}'.format(failure['id'], failure['num']))
    failure_sum += failure['num']
print('sum : {}'.format(failure_sum))

terminal output

$ python applications.py applications.csv
全応募者
id: 1, num: 1
id: 2, num: 1
id: 3, num: 1
(省略)
id: 198, num: 3
id: 199, num: 3
id: 200, num: 4
sum : 400

当選者
id: 10, num: 4
id: 15, num: 2
id: 22, num: 1
id: 26, num: 2
id: 28, num: 3
id: 32, num: 1
id: 34, num: 1
id: 36, num: 2
id: 37, num: 2
id: 44, num: 1
id: 45, num: 2
id: 49, num: 3
id: 51, num: 1
id: 52, num: 1
id: 53, num: 1
id: 56, num: 2
id: 57, num: 2
id: 64, num: 1
id: 67, num: 2
id: 71, num: 1
id: 75, num: 2
id: 78, num: 3
id: 81, num: 1
id: 83, num: 1
id: 86, num: 2
id: 90, num: 4
id: 91, num: 1
id: 92, num: 1
id: 93, num: 1
id: 95, num: 2
id: 97, num: 2
id: 100, num: 4
id: 103, num: 1
id: 117, num: 2
id: 121, num: 1
id: 122, num: 1
id: 123, num: 1
id: 125, num: 2
id: 128, num: 3
id: 137, num: 2
id: 142, num: 1
id: 146, num: 2
id: 149, num: 3
id: 153, num: 1
id: 156, num: 2
id: 162, num: 1
id: 166, num: 2
id: 171, num: 1
id: 174, num: 1
id: 175, num: 2
id: 182, num: 1
id: 184, num: 1
id: 185, num: 2
id: 186, num: 2
id: 194, num: 1
id: 197, num: 2
id: 199, num: 3
sum : 100

落選者
id: 1, num: 1
id: 2, num: 1
id: 3, num: 1
(省略)
id: 196, num: 2
id: 198, num: 3
id: 200, num: 4
sum : 300

備考

  • ランダムで生成しているので、実行するたびに結果が異なります。毎回同じ結果にしたい場合は一手間加える必要があります。
  • 例えば申し込みの人数の例が一組のみ一人、それ以外が全て二人の場合、選択の仕方によっては100人ちょうどにならない場合がありますが、ここでは考慮していません。