カード生成関数について深掘り

はじめに

以下のビンゴゲームの「generate_card()」について深掘りしていこう。

import random

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
CELL_W = 4

def generate_card():
  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]
  card = [[cols[c][r] for c in range(5)] for r in range(5)]
  card[2][2] = "FR"
  return card

def print_card(card, marked=None):
  header = "".join(f"{ch:^{CELL_W}}" for ch in "BINGO")
  print(header)

  for r in range(5):
    cells = []
    for c in range(5):
      v = card[r][c]
      if v == "FR":
        s = "[FR]"
      elif marked and marked[r][c]:
        s = f"[{str(v).rjust(2)}]"  
      else:
        s = f"{str(v).rjust(2)}"

      cells.append(f"{s:^{CELL_W}}")

    print("".join(cells))

def new_marked():
  m = [[False]*5 for _ in range(5)]
  m[2][2] = True # FREEは最初からマーク
  return m

def mark_number(card, marked, n):
  for r in range(5):
    for c in range(5):
      if card[r][c] == n:
        marked[r][c] = True
        return True
  return False

def count_lines(marked):
  lines = 0
  for r in range(5):
    if all(marked[r][c] for c in range(5)): lines += 1
  for c in range(5):
    if all(marked[r][c] for r in range(5)): lines += 1  
  if all(marked[i][i] for i in range(5)): lines += 1
  if all(marked[i][4-i] for i in range(5)): lines += 1  
  return lines

def main():
  card = generate_card()
  marked = new_marked()
  pool = list(range(1, 76))
  random.shuffle(pool)
  history = []
  turn = 0

  print_card(card, marked)
  print("Enter=next  h=history  q=quit") 
  
  while True:
    cmd = input("> ").strip().lower()
    
    if cmd == "q":
      print("Bye!")
      break
    if cmd == "h":
      print(f"Called: {', '.join(map(str, history)) or '(none)'}")
      continue
    # Enter(空文字)以外は無視して続行
    if cmd not in ("",):
      continue

    if not pool:
      print("No numbers left. Draw game.")
      break

    # ここから1ターン進行
    n  = pool.pop()
    history.append(n)
    turn += 1

    mark_number(card, marked, n)
    lines = count_lines(marked)

    print(f"\nTurn {turn}  Called: {n}  Remaining: {len(pool)}  Lines: {lines}")
    print_card(card, marked)

    if lines >= 1:
      print("\nBINGO! congrats!")
      break

if __name__ == "__main__":
  main()

cols

colsについて見ていこう。

import random

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
CELL_W = 4

def generate_card():
  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]
  card = [[cols[c][r] for c in range(5)] for r in range(5)]
  card[2][2] = "FR"
  return card

リスト内包表記になっている。

  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]

B_RANGESは、タプルのリスト。

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]

B_RANGESから、loとhiを取り出している。

  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]

randomモジュールのsampleメソッドに、B_RANGESの範囲とランダム生成する数を渡している。

  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]

最終的に以下のようなcolsが生成される。

card

cardについて見ていこう。

import random

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
CELL_W = 4

def generate_card():
  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]
  card = [[cols[c][r] for c in range(5)] for r in range(5)]
  card[2][2] = "FR"
  return card

colsと同様にリスト内包表記になっている。

  card = [[cols[c][r] for c in range(5)] for r in range(5)]

5回ループを回して、rに0~4が代入される。

  card = [[cols[c][r] for c in range(5)] for r in range(5)]

colsから値を取り出してリストを生成する。

  card = [[cols[c][r] for c in range(5)] for r in range(5)]

r = 0のとき、c = 0からc = 4までのリストが作成される。

次に、r = 1になって、c = 0からc = 4までのリストが作成される。

r = 4まで繰り返される。

最終的に、cardは以下のようになる。

colsと比べると、横→縦にデータが変換されていることが分かる。

cols
card

FREEは、FRで表現する。

import random

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
CELL_W = 4

def generate_card():
  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]
  card = [[cols[c][r] for c in range(5)] for r in range(5)]
  card[2][2] = "FR"
  return card

generate_cardの戻り値は、card。

import random

B_RANGES = [(1, 15), (16, 30), (31, 45), (46, 60), (61, 75)]
CELL_W = 4

def generate_card():
  cols = [random.sample(range(lo, hi + 1), 5) for lo, hi in B_RANGES]
  card = [[cols[c][r] for c in range(5)] for r in range(5)]
  card[2][2] = "FR"
  return card

main関数で使用

以下の部分について見ていこう。

def main():
  card = generate_card()

if __name__ == "__main__":
  main()

まずは、Pythonのお決まりの表記で、main関数が起動する。

if __name__ == "__main__":
  main()

main関数で、generate_cardメソッドを使用して、戻り値をcardに代入するという流れ。

def main():
  card = generate_card()

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です