こんにちは!今回は、Pythonを使って10×10のマインスイーパーゲームを作成しました。
Pythonの標準ライブラリであるtkinterを使用して、シンプルなゲームを作ります。
Pyhonのプログラミングの練習にもなりますので是非参考にしてみてください!
ゲーム画面
完成したゲームの画面は以下の通りです。
コード全体
完成したコードを以下に載せます。
import tkinter as tk
import random
from tkinter import messagebox
# 定数の設定
GRID_SIZE = 10 # グリッドのサイズ
# 難易度に応じた地雷の数
MINES = {
'easy': 10,
'normal': 20,
'hard': 30
}
# グリッドの初期化
def create_grid():
grid = [[' ' for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]
return grid
# 地雷の配置
def place_mines(grid, num_mines):
mines = set()
while len(mines) < num_mines:
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] = 'M' # 地雷を'M'で表示
return grid
# 地雷の数を数える
def count_mines_around(grid, x, y):
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] == 'M':
count += 1
return count
# ヒントの配置
def place_hints(grid):
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] == ' ':
mines_count = count_mines_around(grid, x, y)
if mines_count > 0:
grid[x][y] = str(mines_count)
return grid
# セルを開く
def open_cell(x, y):
if buttons[x][y]['state'] == 'normal':
if grid[x][y] == 'M':
buttons[x][y].config(text='M', bg='red')
game_over(False)
else:
buttons[x][y]['state'] = 'disabled'
if grid[x][y] != ' ':
buttons[x][y].config(text=grid[x][y])
else:
buttons[x][y].config(text='', bg='lightgrey')
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 buttons[i][j]['state'] == 'normal':
open_cell(i, j)
check_win()
# ゲームオーバー処理
def game_over(win):
if win:
messagebox.showinfo("ゲームクリア", "おめでとうございます!すべての地雷を見つけました!")
else:
messagebox.showinfo("ゲームオーバー", "残念!地雷を踏んでしまいました。")
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] == 'M':
buttons[x][y].config(text='M', bg='red')
buttons[x][y]['state'] = 'disabled'
# ゲームクリアのチェック
def check_win():
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] != 'M' and buttons[x][y]['state'] == 'normal':
return
game_over(True)
# GUIの設定
def setup_gui(root):
for x in range(GRID_SIZE):
row = []
for y in range(GRID_SIZE):
button = tk.Button(root, width=2, height=1, command=lambda x=x, y=y: open_cell(x, y))
button.grid(row=x+1, column=y) # 行を1つ下げる
row.append(button)
buttons.append(row)
# リスタートボタンを追加
restart_button = tk.Button(root, text="リスタート", command=restart_game)
restart_button.grid(row=GRID_SIZE+1, columnspan=GRID_SIZE)
# ゲームの再スタート
def restart_game():
global grid, buttons, num_mines
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
buttons[x][y].destroy()
buttons = []
grid = create_grid()
grid = place_mines(grid, num_mines)
grid = place_hints(grid)
setup_gui(root)
# 難易度設定
def set_difficulty(difficulty):
global num_mines
num_mines = MINES[difficulty]
restart_game()
# メイン関数
def main():
global grid, buttons, root, num_mines
num_mines = MINES['normal'] # デフォルトの難易度をnormalに設定
grid = create_grid()
grid = place_mines(grid, num_mines)
grid = place_hints(grid)
root = tk.Tk()
root.title("マインスイーパー")
buttons = []
# 難易度選択ボタンの追加
tk.Button(root, text="Easy", command=lambda: set_difficulty('easy')).grid(row=0, column=0, columnspan=3, sticky='ew')
tk.Button(root, text="Normal", command=lambda: set_difficulty('normal')).grid(row=0, column=3, columnspan=3, sticky='ew')
tk.Button(root, text="Hard", command=lambda: set_difficulty('hard')).grid(row=0, column=6, columnspan=4, sticky='ew')
setup_gui(root)
root.mainloop()
if __name__ == "__main__":
main()
コードの解説
インポートと定数の設定
- tkinterとmessageboxをインポートしてGUIを作成し、メッセージボックスを使用できるようにします。
- randomをインポートして地雷のランダム配置に使用します。
GRID_SIZE
はグリッドのサイズ(10×10)を設定し、NUM_MINES
は地雷の数を設定します。- MINESの中に難易度ごとに地雷の数を入れています。
import tkinter as tk
import random
from tkinter import messagebox
# 定数の設定
GRID_SIZE = 10 # グリッドのサイズ
NUM_MINES = 20 # 地雷の数
# 難易度に応じた地雷の数
MINES = {
'easy': 10,
'normal': 20,
'hard': 30
}
グリッドの初期化
create_grid
関数は10×10のグリッドを作成し、各セルを空白で初期化します。
def create_grid():
grid = [[' ' for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]
return grid
地雷の配置
place_mines
関数はグリッドにランダムに地雷を配置します。地雷は'M'
で表示されます。
def place_mines(grid):
mines = set()
while len(mines) < NUM_MINES:
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] = 'M' # 地雷を'M'で表示
return grid
地雷の数を数える
count_mines_around
関数は指定されたセルの周囲にある地雷の数を数えます。
def count_mines_around(grid, x, y):
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] == 'M':
count += 1
return count
ヒントの配置
place_hints
関数は地雷でないセルに対して、周囲の地雷の数を計算し、その数をセルに設定します。
def place_hints(grid):
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] == ' ':
mines_count = count_mines_around(grid, x, y)
if mines_count > 0:
grid[x][y] = str(mines_count)
return grid
セルを開く
open_cell
関数はセルを開きます。地雷があればゲームオーバーとなり、地雷を赤で表示します。地雷でない場合はその数を表示します。空白セルの場合は周囲のセルも自動的に開きます。
def open_cell(x, y):
if buttons[x][y]['state'] == 'normal':
if grid[x][y] == 'M':
buttons[x][y].config(text='M', bg='red')
game_over(False)
else:
buttons[x][y]['state'] = 'disabled'
if grid[x][y] != ' ':
buttons[x][y].config(text=grid[x][y])
else:
buttons[x][y].config(text='', bg='lightgrey')
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 buttons[i][j]['state'] == 'normal':
open_cell(i, j)
check_win()
ゲームオーバー処理
game_over
関数はゲームオーバー時にメッセージボックスで「ゲームオーバー」または「ゲームクリア」のメッセージを表示し、全てのセルを開いて地雷を表示します。
def game_over(win):
if win:
messagebox.showinfo("ゲームクリア", "おめでとうございます!すべての地雷を見つけました!")
else:
messagebox.showinfo("ゲームオーバー", "残念!地雷を踏んでしまいました。")
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] == 'M':
buttons[x][y].config(text='M', bg='red')
buttons[x][y]['state'] = 'disabled'
ゲームクリアのチェック
check_win
関数は全ての非地雷セルが開かれたかをチェックし、ゲームクリアとしてgame_over(True)
を呼び出します。
def check_win():
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
if grid[x][y] != 'M' and buttons[x][y]['state'] == 'normal':
return
game_over(True)
GUIの設定
setup_gui
関数はグリッド上にボタンを配置し、クリックイベントを設定します。
ゲームを再開しやすいようにリスタートボタンを設置しました。
# GUIの設定
def setup_gui(root):
for x in range(GRID_SIZE):
row = []
for y in range(GRID_SIZE):
button = tk.Button(root, width=2, height=1, command=lambda x=x, y=y: open_cell(x, y))
button.grid(row=x+1, column=y) # 行を1つ下げる
row.append(button)
buttons.append(row)
# リスタートボタンを追加
restart_button = tk.Button(root, text="リスタート", command=restart_game)
restart_button.grid(row=GRID_SIZE+1, columnspan=GRID_SIZE)
ゲームの再スタート
restart_game
関数でゲーム再スタートします。
# ゲームの再スタート
def restart_game():
global grid, buttons, num_mines
for x in range(GRID_SIZE):
for y in range(GRID_SIZE):
buttons[x][y].destroy()
buttons = []
grid = create_grid()
grid = place_mines(grid, num_mines)
grid = place_hints(grid)
setup_gui(root)
難易度設定
最初に定数として設定した地雷の数を利用して難易度を調整する処理です。
# 難易度設定
def set_difficulty(difficulty):
global num_mines
num_mines = MINES[difficulty]
restart_game()
メイン関数
main
関数は全体の流れを管理し、グリッドを生成して地雷の数(デフォルトはnomal)とヒントと難易度ボタンを配置しました。
# メイン関数
def main():
global grid, buttons, root, num_mines
num_mines = MINES['normal'] # デフォルトの難易度をnormalに設定
grid = create_grid()
grid = place_mines(grid, num_mines)
grid = place_hints(grid)
root = tk.Tk()
root.title("マインスイーパー")
buttons = []
# 難易度選択ボタンの追加
tk.Button(root, text="Easy", command=lambda: set_difficulty('easy')).grid(row=0, column=0, columnspan=3, sticky='ew')
tk.Button(root, text="Normal", command=lambda: set_difficulty('normal')).grid(row=0, column=3, columnspan=3, sticky='ew')
tk.Button(root, text="Hard", command=lambda: set_difficulty('hard')).grid(row=0, column=6, columnspan=4, sticky='ew')
setup_gui(root)
root.mainloop()
if __name__ == "__main__":
main()
最後に
シンプルなゲームですが、いざプログラムでコードを書いてみると思ったより長いコードになりました…
今回ブログで紹介したコードを見てゲームを実際に作成したり、コードを改修したりするとよりプログラミングの知識が身につくと思います。(現在プレイしている難易度を画面に表示するなど)
また、pythonでゲームを作ってみたい方は以下の本を参考にしてください。
プログラミング未経験者にもおすすめの本です。
Pythonではじめるゲーム制作 超入門 知識ゼロからのプログラミング&アルゴリズムと数学 新品価格 |