【Python入門】Pygameでマインスイーパーを作ってみよう！


# はじめに
今回は、Pythonのゲームライブラリ「Pygame」を使って、マインスイーパーを作成する方法を紹介します。マインスイーパーはシンプルながらも頭を使うゲームで、プログラミング初心者でも楽しみながら学べる題材です。この記事では、ゲームの基本的な実装から、クリアやゲームオーバーの処理までを丁寧に解説します。

## 必要なライブラリのインストール

まずは、Pygameをインストールしましょう。以下のコマンドを実行してください。

```bash
pip install pygame
```

## マインスイーパーの基本設計

マインスイーパーは、プレイヤーがセルをクリックしていき、地雷を避けながらすべての安全なセルを開けることを目指すゲームです。地雷の数やセルの配置はランダムに決定されます。

### ゲームの構成要素

1. **グリッド**: セルが並ぶ2D配列。
2. **地雷**: ランダムに配置された危険なセル。
3. **数字**: 周囲に存在する地雷の数を表示するセル。
4. **勝敗判定**: 地雷をすべて避けて安全なセルを開けたら勝利、地雷をクリックしたらゲームオーバー。

## 実装コード

以下は、Pygameを使ったマインスイーパーの実装例です。

```python
import pygame
import random
import sys

# 定数の設定
WIDTH, HEIGHT = 400, 400
GRID_SIZE = 9
CELL_SIZE = WIDTH // GRID_SIZE
MINE_COUNT = 10

# 色の設定
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (192, 192, 192)
DARK_GRAY = (160, 160, 160)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

# Pygameの初期化
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Minesweeper")
font = pygame.font.Font(None, 36)

# グリッドを初期化
grid = [[0 for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]
revealed = [[False for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]

# 地雷を配置
mines = set()
while len(mines) < MINE_COUNT:
    x = random.randint(0, GRID_SIZE - 1)
    y = random.randint(0, GRID_SIZE - 1)
    if (x, y) not in mines:
        mines.add((x, y))
        grid[x][y] = -1

# 数値を更新
for x in range(GRID_SIZE):
    for y in range(GRID_SIZE):
        if grid[x][y] == -1:
            continue
        count = 0
        for i in range(max(0, x - 1), min(GRID_SIZE, x + 2)):
            for j in range(max(0, y - 1), min(GRID_SIZE, y + 2)):
                if grid[i][j] == -1:
                    count += 1
        grid[x][y] = count

def draw_grid():
    for x in range(GRID_SIZE):
        for y in range(GRID_SIZE):
            rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
            color = DARK_GRAY if revealed[x][y] else WHITE
            pygame.draw.rect(screen, color, rect)
            pygame.draw.rect(screen, BLACK, rect, 1)

            if revealed[x][y]:
                if grid[x][y] == -1:
                    pygame.draw.circle(screen, RED, rect.center, CELL_SIZE // 4)
                elif grid[x][y] > 0:
                    text = font.render(str(grid[x][y]), True, BLUE)
                    screen.blit(text, text.get_rect(center=rect.center))

def reveal_cell(x, y):
    if revealed[x][y]:
        return
    revealed[x][y] = True
    if grid[x][y] == 0:
        for i in range(max(0, x - 1), min(GRID_SIZE, x + 2)):
            for j in range(max(0, y - 1), min(GRID_SIZE, y + 2)):
                if not revealed[i][j]:
                    reveal_cell(i, j)

def check_win():
    for x in range(GRID_SIZE):
        for y in range(GRID_SIZE):
            if grid[x][y] != -1 and not revealed[x][y]:
                return False
    return True

def display_message(message):
    text = font.render(message, True, BLACK)
    screen.blit(text, text.get_rect(center=(WIDTH // 2, HEIGHT // 2)))
    pygame.display.flip()
    pygame.time.wait(2000)  # 2秒間メッセージを表示
    pygame.quit()
    sys.exit()

# メインループ
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:  # 左クリック
                mx, my = event.pos
                x, y = mx // CELL_SIZE, my // CELL_SIZE
                if grid[x][y] == -1:
                    draw_grid()
                    pygame.display.flip()
                    display_message("Game Over")  # ゲームオーバー
                else:
                    reveal_cell(x, y)
                    if check_win():
                        draw_grid()
                        pygame.display.flip()
                        display_message("You Win!")  # ゲームクリア

    screen.fill(GRAY)
    draw_grid()
    pygame.display.flip()

pygame.quit()
sys.exit()
```

### 追加機能の説明

- **選択済みセルの視覚化**: プレイヤーが選択したセルは灰色で表示され、地雷が配置されていない安全なセルが明示的に区別されます。
- **勝敗判定とメッセージ表示**: ゲームオーバー時には「Game Over」、すべての安全なセルを開けた場合は「You Win!」と画面中央に表示されます。

## 実行方法

コードを実行すると、マインスイーパーが起動します。セルをクリックして地雷を避けながらゲームを進めましょう。ゲームオーバーやゲームクリアが達成されると、それぞれの結果に応じたメッセージが表示されます。

## 実行結果
![スクリーンショット 2024-08-21 17.43.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/72305821-d286-2609-aa41-a9a333691681.png)


## まとめ

この記事では、Pygameを使ったマインスイーパーの作成方法を紹介しました。ゲームの基本機能から視覚的なフィードバック、勝敗の判定まで、実際の開発に役立つ技術を学べたかと思います。Pygameを使った他のゲーム開発にも挑戦してみてください！