2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

穴あき問題とビンゴ確率に関する計算機シミュレーション

Posted at

最近,YouTubeチャンネル「予備校のノリで学ぶ「大学の数学・物理」」様において
``ビンゴせずに穴は何個まで開けられるか''
という話題で数学的な解析も含めて解説されていました.

元動画は以下のものです.

本記事では計算機シミュレーションを通して数学に加えてプログラミングの理解を深めていきます.
目標としては,Pythonを用いて抽選回数とビンゴの確率分布を得ることを目標とします.
それでは実装を行っていきます.

パッケージインポート

数値計算パッケージとしてnumpy,グラフ描写のためにmatplotlibをインポートします.

import numpy as np
import matplotlib.pyplot as plt

ビンゴの判定関数

ビンゴカードを$5 \times 5$の配列を使って表現し,穴が開いている部分は$-1$とします.
このように実装することでビンゴの判定が多少簡単になります.
穴が開いている部分を$-1$としたため,縦横斜めいずれかの和が$-5$となればビンゴです.

def checkBingo(card):
  for i in range(5):
    # 横列のチェック.
    if np.sum(card[i]) == -5:
      return True
    # 縦列のチェック
    if np.sum(card[:,i]) == -5:
      return True
    # 斜めのチェック
  if (card[0][0] + card[1][1] + card[2][2] + card[3][3] + card[4][4]) == -5:
      return True
  if (card[0][4] + card[1][3] + card[2][2] + card[3][1] + card[4][0]) == -5:
      return True
  return False

ビンゴカード生成

ビンゴカードは$0 \sim 74$の数字と仮定しています.動画では$1 \sim 75$としていますが,Pythonの$0$番目スタートの仕様に従っています.

注意点としてはrandint関数のような一様乱数を用いてビンゴカードを生成した場合は同じ値を出力する可能性があり,ビンゴカード$1$枚の中で同じ値は存在しないという性質を満たせない可能性があります.

重複しない乱数を実現するために,$0 \sim 74$の連番整数を生成してそれをシャッフルして取り出すことで実装を行います.

生成後の後処理としてビンゴカードの真ん中に$-1$を代入して穴を開ける判定にしておきます.

numberOfcards = 10000

card = np.arange(75)
cards = np.zeros((numberOfcards,5,5))

for i in range(numberOfcards):
  np.random.default_rng().shuffle(card)
  cards[i] = card[:25].reshape(5,5)

  cards[i][2][2] = -1

抽選と結果

抽選番号を生成して番号ごとにビンゴカードに穴を開けていきます.
ビンゴしているカードの枚数と抽選回数を記録していきます.

この結果では抽選回数とビンゴしているカードの枚数の累積分布のようなものが得られます.

lot = np.arange(75)
np.random.default_rng().shuffle(lot)

result = np.zeros(len(lot))

for i in range(len(lot)):
  for j in range(numberOfcards):
    np.place(cards[j],cards[j] == lot[i],-1)
    if checkBingo(cards[j]) == True:
      result[i] += 1
print(result)

結果の描写

最後にmatplotlibを使ってデータの描画を行います.
今回は$10000$枚のビンゴカードを使ってシミュレーションを行いました.
データ数が足りないので,増やすと滑らかなグラフになることが期待できます.

data = np.zeros(len(lot))
for i in range(1,len(data)):
  data[i] = result[i] - result[i-1]
print(data)

plt.bar(np.arange(len(data)), data, width=1.0)

bingo.png

まとめ

YouTubeチャンネル「予備校のノリで学ぶ「大学の数学・物理」」様の動画を基に計算機シミュレーションを使って,理解を深めていきました.
数学と密接に関連がある計算機の世界を少しでも知っていただければ幸いです.

ソースコードまとめ

import numpy as np
import matplotlib.pyplot as plt

def checkBingo(card):
  for i in range(5):
    # 横列のチェック.
    if np.sum(card[i]) == -5:
      return True
    # 縦列のチェック
    if np.sum(card[:,i]) == -5:
      return True
    # 斜めのチェック
  if (card[0][0] + card[1][1] + card[2][2] + card[3][3] + card[4][4]) == -5:
      return True
  if (card[0][4] + card[1][3] + card[2][2] + card[3][1] + card[4][0]) == -5:
      return True
  return False

# ビンゴカードの生成 (10000枚)
numberOfcards = 10000

card = np.arange(75)
cards = np.zeros((numberOfcards,5,5))

for i in range(numberOfcards):
  np.random.default_rng().shuffle(card)
  cards[i] = card[:25].reshape(5,5)

  cards[i][2][2] = -1

lot = np.arange(75)
np.random.default_rng().shuffle(lot)

result = np.zeros(len(lot))

for i in range(len(lot)):
  for j in range(numberOfcards):
    np.place(cards[j],cards[j] == lot[i],-1)
    if checkBingo(cards[j]) == True:
      result[i] += 1
print(result)

data = np.zeros(len(lot))
for i in range(1,len(data)):
  data[i] = result[i] - result[i-1]
print(data)

plt.bar(np.arange(len(data)), data, width=1.0)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?