[pygame] Python でビンゴゲームを作ってみた

# はじめに

私の研究室は月に一回、誕生日の人を祝う誕生日会を行っています。誕生日会では、毎回ミニゲームを行うので誕生日会の為にビンゴゲームを作成しようと私は決心しました。

まずビンゴの数字を出力させる為のプログラム、その次にビンゴカードを出力する為のプログラムそれぞれ分けて作成を行おうと思います。


# Pygame について
扱ったライブラリは pygame というライブラリです。
pygame はゲーム作成用ライブラリで、私は[pygame ドキュメント](https://www.pygame.org/wiki/about)や[本](https://www.amazon.co.jp/%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%92%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E6%A5%BD%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%B9%E3%82%8BPython%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Future-Coders%EF%BC%88NextPublishing%EF%BC%89-%E7%94%B0%E4%B8%AD-%E8%B3%A2%E4%B8%80%E9%83%8E-ebook/dp/B06XRQS8PN)を使って、勉強を行いました。

## 数字を出力させるプログラム

```python:bingo.py
#!/usr/bin/env python3
import sys
import pygame
import pyautogui
from pygame.locals import KEYUP, KEYDOWN, K_ESCAPE, K_SPACE, K_UP, QUIT
import random
import time
pygame.init()

x, y = 800, 600
font = pygame.font.Font(None, 300)
sur = pygame.display.set_mode((x, y))
fps = pygame.time.Clock()


def getnum():
    x = [i for i in range(1, 73)]
    return x


def change_number(sur, nums):  # nums[1-72]
    random.seed()
    num = random.sample(nums, 1)[0]
    text = font.render(str(num), True, (255, 255, 255))
    sur.blit(text, [x / 2 - 100, y / 2 - 100])
    pygame.display.update()


def callchange_number(sur, nums, call):
    if(call == True):
        change_number(sur, nums)
    else:
        num = random.sample(nums, 1)[0]
        text = font.render(str(num), True, (255, 255, 255))
        sur.blit(text, [x / 2 - 100, y / 2 - 100])


def mainloop(nums, call=None):
    while True:
        sur.fill((0, 0, 0))
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit()
                elif event.key == K_SPACE:
                    call = False
                elif event.key == K_UP:
                    call = True
        callchange_number(sur, nums, call)
        fps.tick(30)


def main():
    nums = getnum()
    mainloop(nums)


main()
```

もう少し全体的に綺麗なコードにできるかも、、、、

基本的には mainloop 関数でキーの設定、callchange_number 関数で change_number 関数を呼びだして数字の出力を行っています。

実行結果は[github ページ](https://github.com/taiseiyo/bingo)で確認してみて下さい。

## ビンゴカードを出力する為のプログラム
```python:bingo-card.py

#!/usr/bin/env python3
import sys
import pygame
from pygame.locals import QUIT, MOUSEBUTTONDOWN, MOUSEMOTION, MOUSEBUTTONUP, KEYDOWN, K_SPACE, K_ESCAPE, K_UP, K_LEFT, K_RIGHT, K_DOWN
import pyautogui
import random

pygame.init()
window_x, window_y = pyautogui.size()
window, string_x = (int(window_x/2), window_y), window_x/8
surface = pygame.display.set_mode(window)
fpsclock = pygame.time.Clock()
pink = (255, 182, 193)
bingo_string = pygame.font.SysFont(None, 72)
number_string = pygame.font.SysFont(None, 100)


class BingoCard():

    def __init__(self):
        self.switch, self.count = True,  1
        self.mainloop()

    def generate_num(self, x, y, number):
        for i in range(1, 6):
            if (i * 100 <= x <= (i + 1) * 100):
                surface.blit(
                    number_string.render(str(number), True, (0, 106, 182)), (x, y))

    def draw_normal_object(self):
        for i in range(1, 7):
            pygame.draw.line(surface, (255, 0, 0),
                             (100*i, 100), (100*i, 600), 5)
            pygame.draw.line(surface, (255, 0, 0),
                             (100, 100*i), (600, 100*i), 5)
        surface.blit(bingo_string.render("BINGO CARD", True,
                                         (0, 128, 0)), (string_x, 50))
        pygame.draw.circle(surface, (255, 0, 0), (350, 350), 50)

    def mainloop(self):
        while True:
            for get in pygame.event.get():
                if(get.type == KEYDOWN):
                    if(get.key == K_SPACE):
                        self.switch = False if self.count % 2 == 1 else True
                        self.count = self.count + 1 if self.count < 10 else 1
                    elif(get.key == K_ESCAPE):
                        pygame.quit()
                        sys.exit()

            if(self.switch):
                surface.fill(pink)
                num_list, number2, used_index = [], [], []
                for i in range(1, 6):
                    for j in range(1, 6):
                        number1 = random.randint(15*(i - 1) + 1, 15*i)
                        num_list = num_list + used_index
                        if(number1 not in num_list):
                            self.generate_num(100*i+20, 100*j+30, number1)
                        else:
                            number2 = range(15*(i-1)+1, 15*i)
                            number2 = list(
                                set(number2) - set(num_list)-set(used_index))
                            x = random.randint(0, len(number2)-1)
                            self.generate_num(
                                100*i+20, 100*j+30, number2[x])
                            used_index.append(number2[x])
                        num_list.append(number1)

            self.draw_normal_object()
            fpsclock.tick(40)
            pygame.display.update()


BingoCard()
```
こっちはさっきより綺麗に書けた気がしますがそれでもいらない処理が多いかも、、、、

基本的には、 mainloop 関数で基本的な処理を行ってます。
こちらも、実行結果は[github ページ](https://github.com/taiseiyo/bingo)で確認してみて下さい。



## プログラムの改善点

- bingo-card.py で 1 列に数字の被りがないように行っている処理をもっと綺麗に書けそう

- 人によってはコマンドラインでゲームを行いたい人がいるかも、、、、
   - pygame 出力とコマンドライン出力の両方で実行できるようにする

# まとめ

python には豊富なライブラリがありますがその中でも pygame は簡単にゲーム作成などが可能なので皆さんも遊んでみてはいかがでしょうか？？