2025.07.31(更新日: 2025.08.01)
再び、Pythonで作るビンゴゲーム
はじめに
以前、以下のような記事を書いた。
今読み返してみると、わかりにくかったので、Pythonの実務経験を経た今の私が解説していこう。
今日も指と腕の痛みを理由にして会社を休んでいる。
もちろん実際に痛みが残っている。
しかし、家だと休憩の時間をたっぷりとれる。
そのため、腕と指を労わりながらブログを書いていこう。
全ソースコード
import random
class BingoCard:
def __init__(self):
self.card = self.generate_card()
self.marked = [[False] * 5 for _ in range(5)] # 数字のマーク状態を保持
def generate_card(self):
# 各列 (B, I, N, G, O) ごとに範囲内のランダムな数字を選ぶ
card = []
ranges = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
for start, end in ranges:
column = random.sample(range(start, end + 1), 5)
card.append(column)
card[2][2] = "FREE" # 中央のフリー枠
return card
def mark_number(self, number):
for i in range(5):
for j in range(5):
if self.card[i][j] == number:
self.marked[i][j] = True
def check_bingo(self):
# 行と列でビンゴかどうかをチェック
for i in range(5):
if all(self.marked[i]): # 行のビンゴ
return True
if all([self.marked[j][i] for j in range(5)]): # 列のビンゴ
return True
# 対角線のビンゴをチェック
if all([self.marked[i][i] for i in range(5)]): # 左上から右下
return True
if all([self.marked[i][4 - i] for i in range(5)]): # 右上から左下
return True
return False
def display_card(self):
print("\nB I N G O")
for i in range(5):
for j in range(5):
value = self.card[j][i] # 列ごとに表示
if isinstance(value, int):
print(f"{value:2d}", end=" ")
else:
print(f"{value:>2}", end=" ")
print()
def play_bingo():
card = BingoCard()
card.display_card()
drawn_numbers = set()
while True:
input("Enterで次の番号を引きます...")
number = random.randint(1, 75)
while number in drawn_numbers: # 重複しないようにする
number = random.randint(1, 75)
drawn_numbers.add(number)
print(f"引かれた番号: {number}")
card.mark_number(number)
card.display_card()
if card.check_bingo():
print("ビンゴ!おめでとうございます!")
break
# ゲームを開始
play_bingo()
実行結果
hiroki@shibatahiroshitakanoiMac python % cd /Users/hiroki/Downloads/python ; /usr/bin/env /usr/local/bin/python3.12 /Users/hiroki/.vscode/extensions/ms-python.debugpy-2025.10.0-darwin-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 58612 -- /Users/
hiroki/Downloads/python/bingo.py
B I N G O
8 29 43 59 75
7 18 40 60 62
5 17 FREE 58 67
11 24 41 49 69
4 21 35 51 64
Enterで次の番号を引きます...
引かれた番号: 57
B I N G O
8 29 43 59 75
7 18 40 60 62
5 17 FREE 58 67
11 24 41 49 69
4 21 35 51 64
Enterで次の番号を引きます...
途中省略
引かれた番号: 29
B I N G O
8 29 43 59 75
7 18 40 60 62
5 17 FREE 58 67
11 24 41 49 69
4 21 35 51 64
ビンゴ!おめでとうございます!
hiroki@shibatahiroshitakanoiMac python %
仕様

BINGOの各列に指定範囲内のランダムな数値を5つずつ配置(B : 1~15、I : 16~30、N : 31~45、G : 46~60、O : 61~75)
中央マスは、「FREE」
引かれた番号がカード上にあればマーク
横、縦、斜めのいずれか一列すべてがマーク済みでビンゴ!
Enterキー押下でランダムに番号を引き、ビンゴになるまで繰り返す
同じ番号が2回引かれないように制御
フローチャート
スタート→カードとマーク状態の初期化

カードの表示

プレイヤーにカードを引いてもらう→引かれた番号をマークする→カードを表示


ビンゴ判定

ビンゴの場合

ビンゴではない場合


スタート→カードとマーク状態の初期化
play_bingo関数を実行
# ゲームを開始
play_bingo()
BingoCardクラスのインスタンス生成
def play_bingo():
card = BingoCard()
cardの初期化
class BingoCard:
def __init__(self):
self.card = self.generate_card()
def generate_card(self):
# 各列 (B, I, N, G, O) ごとに範囲内のランダムな数字を選ぶ
card = []
ranges = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
for start, end in ranges:
column = random.sample(range(start, end + 1), 5)
card.append(column)
card[2][2] = "FREE" # 中央のフリー枠
return card
randomモジュール使用
import random
sampleメソッド
random.sample(range(1, 15), 5)
[1, 2, 7, 12, 3]
random.sample(range(1, 15), 3)
[2, 7, 13]
戻り値のcard
import pprint
pprint.pprint(card)
[[5, 13, 12, 3, 14],
[23, 20, 26, 25, 30],
[38, 33, 'FREE', 42, 44],
[56, 54, 49, 57, 59],
[70, 67, 63, 68, 62]]
毎回異なる
import pprint
pprint.pprint(card)
[[1, 2, 12, 11, 6],
[19, 21, 30, 20, 29],
[35, 40, 'FREE', 37, 43],
[53, 59, 49, 58, 57],
[68, 65, 75, 66, 72]]
cardインスタンスを生成すると、cardが初期化されている
card = BingoCard()
card.card
[[15, 10, 4, 7, 6], [23, 21, 22, 26, 27], [36, 32, 'FREE', 39, 45], [57, 46, 52, 60, 49], [75, 72, 73, 74, 69]]
こちらも毎回異なる
card = BingoCard()
card.card
[[6, 14, 7, 9, 3], [19, 21, 25, 22, 18], [39, 43, 'FREE', 37, 32], [57, 49, 56, 46, 60], [71, 75, 73, 64, 72]]
数字のマーク状態を保持
self.marked = [[False] * 5 for _ in range(5)]
リスト内包表記
import pprint
pprint.pprint([[False] * 5 for _ in range(5)] )
[[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]]
pprint.pprint([[False] * 3 for _ in range(5)] )
[[False, False, False],
[False, False, False],
[False, False, False],
[False, False, False],
[False, False, False]]
pprint.pprint([[a] * 3 for a in range(5)] )
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
pprint.pprint([_ * 3 for _ in range(5)] )
[0, 3, 6, 9, 12]
カードの表示
card.display_card()
def display_card(self):
print("\nB I N G O")
for i in range(5):
for j in range(5):
value = self.card[j][i] # 列ごとに表示
if isinstance(value, int):
print(f"{value:2d}", end=" ")
else:
print(f"{value:>2}", end=" ")
print()
BINGO
print("\nB I N G O")
hiroki@shibatahiroshitakanoiMac python % cd /Users/hiroki/Downloads/python ; /usr/bin/env /usr/local/bin/python3.12 /Users/hiroki/.vscode/extensions/ms-python.debugpy-2025.10.0-darwin-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 58870 -- /Users/hiroki/Downloads/
python/bingo.py
B I N G O
外側for文
for i in range(5):
内側for文
for j in range(5):
value
value = self.card[j][i]
self.card
import pprint
pprint.pprint(self.card)
[[3, 9, 8, 2, 7],
[27, 29, 30, 20, 18],
[38, 44, 'FREE', 34, 39],
[50, 55, 53, 46, 54],
[65, 67, 66, 70, 69]]
self.card[4][0]
self.card[4][0]
65
数値の場合、右寄せ、右に空白を開けて表示
if isinstance(value, int):
print(f"{value:2d}", end=" ")
print(f"{self.card[0][0]:2d}", end=" ")
3
print(self.card[0][0])
3


数値以外(FREE)の場合、右寄せ(右寄せしなくても結果は変わらない)
else:
print(f"{value:>2}", end=" ")

プレイヤーにカードを引いてもらう→引かれた番号をマークする→カードを表示
while True:
input("Enterで次の番号を引きます...")
number = random.randint(1, 75)
while number in drawn_numbers: # 重複しないようにする
number = random.randint(1, 75)
drawn_numbers.add(number)
print(f"引かれた番号: {number}")
hiroki@shibatahiroshitakanoiMac python % cd /Users/hiroki/Downloads/python ; /usr/bin/env /usr/local/bin/python3.12 /Users/hiroki/.vscode/extensions/ms-python.debugpy-2025.10.0-darwin-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 59249 -- /Users/hiroki/Downloads/
python/bingo.py
B I N G O
9 28 42 53 67
8 16 40 54 61
5 25 FREE 46 70
2 30 43 57 69
13 29 32 51 75
Enterで次の番号を引きます...
Enterを押す

B I N G O
9 28 42 53 67
8 16 40 54 61
5 25 FREE 46 70
2 30 43 57 69
13 29 32 51 75
Enterで次の番号を引きます...
引かれた番号: 9
引かれた番号をマークする
card.mark_number(number)
def mark_number(self, number):
for i in range(5):
for j in range(5):
if self.card[i][j] == number:
self.marked[i][j] = True

import pprint
pprint.pprint(self.marked)
[[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]]
↓

pprint.pprint(self.marked)
[[True, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]]
カードを表示
card.display_card()
B I N G O
9 28 42 53 67
8 16 40 54 61
5 25 FREE 46 70
2 30 43 57 69
13 29 32 51 75
ビンゴ判定
if card.check_bingo():
print("ビンゴ!おめでとうございます!")
break
def check_bingo(self):
# 行と列でビンゴかどうかをチェック
for i in range(5):
if all(self.marked[i]): # 行のビンゴ
return True
if all([self.marked[j][i] for j in range(5)]): # 列のビンゴ
return True
# 対角線のビンゴをチェック
if all([self.marked[i][i] for i in range(5)]): # 左上から右下
return True
if all([self.marked[i][4 - i] for i in range(5)]): # 右上から左下
return True
return False
allで判定
all([True, True])
True
all([True, True, False])
False
all(self.marked[i])
False
self.marked[i] # i = 0(初回ループ)
[True, False, False, False, False]
ビンゴではない

card.check_bingo()
False
While文の最初に戻る

ビンゴの場合は、「ビンゴ!おめでとうございます!」を出力
B I N G O
2 18 38 48 69
5 29 37 59 62
7 19 FREE 52 73
8 24 34 51 64
14 22 42 53 72
ビンゴ!おめでとうございます!
hiroki@shibatahiroshitakanoiMac python %
コメントを残す