今回は五目並べゲームを Python の tkinter を利用して作成していきたいと思います!
Contents
作成する「五目並べゲーム」
今回作成する五目並べゲームは下の図のようなものになります。
プレイヤーは “まだ石が置かれていない” 縦線と横線の交点上に石を置くことができます。
石を置くと、今度はコンピュータが石を置く番になります。
コンピュータが石を置いたら、またプレイヤーが石を置く番に戻ります。
これを繰り返し、同じ色の石が縦方向・横方向・斜め方向のいずれかに連続で5つ並んだ時点でゲームが終了です。
ゲーム終了時には、プレイヤーが勝利したか敗北したかがメッセージボックスで表示されます。
本当は盤面上に空きの交点がなくなった時点でもゲーム終了になるのですが、今回紹介するスクリプトではこのゲーム終了に関してはプログラミングしていません。ここは手抜きです…。
また、調べた感じだと先手の「三三」「四四」禁止のルールがあったりもするようですが、今回は単純に “石が置かれていない” 交点であればどこに石を置いても良いようにしています。
五目並べゲームの作り方
ではこの五目並べゲームの作り方を解説していきます。
この五目並べゲームを作る上でポイントになるのは下記の4点だと思います。
- 盤面上の石の管理
- 五目並べ画面の実現
- 石を置く処理の実現
- 並べられた石のカウント
スポンサーリンク
盤面上の石の管理
まず五目並べを作成する上では、盤面上の石の管理を行う必要があります。
もっと具体的にいうと、どの交点にどの色の石が置かれているかを管理する必要があります。
五目並べゲームでは、プレイヤーが石を置こうとした交点に既に石が置かれていないかを判断する、石が置かれた時に石がいくつ並ぶことになるかをカウントする、といった処理を行う必要があります。
これらを行うためには、どの交点にどの色の石が置かれているかを管理しておく必要があります。
今回紹介するスクリプトにおいては、この盤面上の石の管理を2次元リスト self.board
で行うようにしています。
self.board[y][x]
に (x
, y
) の位置の交点に置かれている石の色を格納することで盤面上の石の管理を行います。
交点の位置は、左上の交点を (0
, 0
) とし、横方向の正方向は右側、縦方向の正方向は下側としています。
この “交点の位置” は後述するキャンバス上の座標とは異なるので注意してください
五目並べにおいては、盤面上の石の状態が変化するのは「石が置かれた」時です。
したがって、石が置かれた時には、この self.board
の更新を行う必要があります。
例えば (x
, y
) の位置の交点に 'black'
の石が置かれる際には、石を置く処理だけでなく下記のような self.board
を更新する処理も合わせて実行する必要があります。
self.board[y][x] = 'black'
五目並べ画面の実現
また、GUI ゲームとして遊べるように、アプリ上に五目並べの画面を表現してやる必要があります。
今回は、この五目並べ画面はキャンバス上に線と円を描画することで表現したいと思います。
盤面は縦方向と横方向にそれぞれ線を描画することで表現します。この線は、キャンバスクラスの create_line
メソッドで描画します。
また石は円を描画することで表現します。この円は、キャンバスクラスの create_oval
メソッドで描画します。
この “石を描画する時のポイント” は下記の2つです。
- プレイヤーによって描画する円の色を変更する
- 縦線と横線の交点を中心に描画する
プレイヤーによって描画する円の色を変更する
ポイントの一つ目は石を置くプレイヤーに応じて描画する円の色を変更する必要がある点です。
描画する円の塗りつぶし色は、create_oval
実行時に fill
オプションを指定することで設定可能です。
ですので、石を置くプレイヤーに応じて fill
に異なる色を指定してやれば、プレイヤーによって円の色を変更することができます。
縦線と横線の交点を中心に描画する
また、五目並べでは石を線と線の交点上に置くのが通常のようなので、今回紹介するスクリプトにおいても線と線の交点上に円を描画するようにします。
このように描画を行うためには、線と線の交点がキャンバス上のどの座標に位置するかを計算する必要があります。要は交点の位置 (x
, y
) からのキャンバス上の座標への変換が必要です。
一番左上の交点のキャンバス上の座標を (self.offset_x
, self.offset_y
)、さらに線と線の間隔を self.interval
とすれば、(x
, y
) の位置の交点は下記の式でキャンバス上の座標 (center_x
, center_y
) に変換することができます。
# (x,y)の交点の座標を計算
center_x = x * self.interval + self.offset_x
center_y = y * self.interval + self.offset_y
各変数は図で表すと下記のようになります。ちょっと分かりにくいですが、(x
, y
) は左上を (0
, 0
) とした交点の位置で、(center_x
, center_y
) はその交点の位置をキャンバス上の座標に変換した座標になります。
これでキャンバス上の円の中心座標が計算できますので、後はこの円の中心座標から create_oval
メソッドに指定する円の開始座標と円の終了座標を求めてやれば良いです。
今回のスクリプトでは下記の式で円の開始座標 (xs
, ys
) と円の終了座標 (xe
, ye
) を計算しています。
# 中心座標から円の開始座標と終了座標を計算
xs = center_x - (self.interval * 0.8) // 2
ys = center_y - (self.interval * 0.8) // 2
xe = center_x + (self.interval * 0.8) // 2
ye = center_y + (self.interval * 0.8) // 2
石を置く処理の実現
五目並べは石を置くことでゲームを進めるものですので、五目並べゲームを作成するためには「石を置く処理」を実現する必要があります。
マウスクリックイベントの受付
今回はこの「石を置く処理」をキャンバス上をマウスでクリックされた際に実行するようにしたいと思います。
これを行うためには、tkinter でのアプリ開発ではお馴染みのイベント受付設定を行う必要があります。
今回紹介するスクリプトでは下記のようにマウスクリックイベントの受付を行なっています。
self.canvas.bind('<ButtonPress>', self.click)
クリック座標から交点の位置への変換
また、五目並べにおいては盤面上の縦線と横線の交点に石が置かれます。ただし、ユーザーがちょうどその交点上をクリックするとは限りませんので、”ユーザーがクリックした位置に一番近い交点” に石を置くようにしたいと思います。
一番左上の交点のキャンバス上の座標を (self.offset_x
, self.offset_y
)、さらに線と線の間隔を self.interval
とすれば、”ユーザーがクリックした位置に一番近い交点” の位置 (ix
, iy
) はユーザーがクリックしたキャンバス上の座標 (x
, y
) から下記のように計算することができます。
ix = (x - self.offset_x + self.interval // 2) // self.interval
iy = (y - self.offset_y + self.interval // 2) // self.interval
あとは、五目並べ画面の実現で解説したように上記で得られる交点の位置をキャンバス上の座標に変換して円を描画すれば、その交点上に石が描画されます。
石が置ける位置
ただし、盤面上の交点であればどこにでも石が置けるというわけではありません。
石が置けるのは “まだ石が置かれていない” 交点になります。
したがって盤面上の石の管理で導入した self.board
を参照し、石を置こうとしている位置に既に石が置かれていないかどうかを確認してから石を置く必要があります。
例えば (x
, y
) の位置に石を置こうとする場合、下記のように self.board[y][x]
が None
であるかどうかを確認してから実際に石を置く処理を実行する必要があります。
if not self.board[y][x]:
# (x,y)に石を置く処理
また前述の通り、石を実際に置いた場合には、石を置いたことを self.board
に記憶させておく必要があります。
スポンサーリンク
並べられた石の数のカウント
五目並べゲームを作成する上で一番のポイントになるのがこの「並べられた石の数のカウント」です。
並べられた石の数のカウントの必要性
五目並べでは、縦方向・横方向・斜め方向に同じ色の石が5つ以上並べられた時点でゲーム終了になります。
このゲーム終了の判断を行うために、各方向に対して同じ色の石がいくつ並べられているかをカウントする必要があります。
並べられた石の数のカウントの実行タイミング
この同じ色の石が並べられている数が変化するのは「石が置かれた」時です。ですので、「石が置かれた」時にこのカウント処理を行い、5つ以上並んでいる際にはゲーム終了の処理を実行する必要があります。
並べられた石の数のカウントの仕方
また、この同じ色の石が並べられている数のカウントを行う際には盤面上のどの交点にどの色の石が置かれているかの情報が必要です。ここで前述で解説した盤面上の石を管理する self.board
が活躍します。
前述の通り、self.board[y][x]
には (x
, y
) の位置の交点に置かれている石の色名が格納されています。
したがって、ある方向 i
・j
に対して (x
, y
) に置かれた石と同じ色の石がいくつ並んでいるかは下記のようにカウントすることができます。
count_num
を1
に初期化するs = 1
に初期化するself.board[y + j * s][x + i * s]
が (x
,y
) に置かれた石の色と同じであるかを調べる- 同じ色の場合
count_num += 1
を実行するs += 1
を実行する- 3. に戻る
s = -1
に初期化するself.board[y + j * s][x + i * s]
が (x
,y
) に置かれた石の色と同じであるかを調べる- 同じ色の場合
count_num += 1
を実行するs -= 1
を実行する- 6. に戻る
最終的な count_num
が、(x
, y
) の位置に石を置いた時に (x
, y
) の位置の交点から方向 i
・j
およびその逆方向に連続して同じ色の石が並んでいる数になります。
i
・j
は 0
と 1
の組み合わせから成る “方向を示すパラメータ” です。例えば i = 1
、j = 1
の場合は、まず 3. と 4. で (x
, y
) から右下方向に対して連続して置かれた同じ色の石の数をカウントすることになります。
さらに、5. 以降は s
が負の値になるので、今度は 6. と 7. で逆方向、つまり (x
, y
) から左上方向に対して連続して置かれた同じ色の石の数をカウントすることになります。
全方向に対してこの石の数のカウントを行い、5
以上の方向が存在した場合はゲーム終了になります。全方向に対して石の数をカウントするためには、五目並べの場合は4方向に対してループを組むようにすれば良いです(逆方向も一緒にカウントするので4方向で良い)。
後述するスクリプトでは、下記の4方向に対してループを行うようにしています。
i = 1
,j = 0
:右方向と左方向i = 1
,j = 1
:右下方向と左上方向i = 0
,j = 1
:上方向と下方向i = -1
,j = 1
:左下方向と右上方向
各方向を図示すると下の図のようになります。上記のように4方向に対して並んでいる石の個数をカウントするようにループを組めば、全方向に対して石が並んでいる個数をカウントできることが分かっていただけると思います。
五目並べゲームのスクリプト
下記がここまで解説してきた内容に基づいて作成した五目並べゲームのスクリプトになります。
# -*- coding:utf-8 -*-
import tkinter
import tkinter.messagebox
import random
# キャンバスの横方向・縦方向のサイズ(px)
CANVAS_SIZE = 400
# ラインの数
NUM_LINE = 10
# 色の設定
BOARD_COLOR = 'burlywood3' # 盤面の背景色
YOUR_COLOR = 'black' # あなたの石の色
COM_COLOR = 'white' # 相手の石の色
# プレイヤーを示す値
YOU = 1
COM = 2
class Gobang():
def __init__(self, master):
'''コンストラクタ'''
self.master = master # 親ウィジェット
self.player = YOU # 次に置く石の色
self.board = None # 盤面上の石を管理する2次元リスト
self.color = { # 石の色を保持する辞書
YOU : YOUR_COLOR,
COM : COM_COLOR
}
self.nextDisk = None
# ウィジェットの作成
self.createWidgets()
# イベントの設定
self.setEvents()
# 五目並べゲームの初期化
self.initGobang()
def createWidgets(self):
'''ウィジェットを作成・配置する'''
# キャンバスの作成
self.canvas = tkinter.Canvas(
self.master,
bg=BOARD_COLOR,
width=CANVAS_SIZE,
height=CANVAS_SIZE,
highlightthickness=0
)
self.canvas.pack(padx=10, pady=10)
def setEvents(self):
'''イベントを設定する'''
# キャンバス上のマウスクリックイベントを受け付ける
self.canvas.bind('<ButtonPress>', self.click)
def initGobang(self):
'''ゲームの初期化を行う'''
# 盤面上の石を管理する2次元リストを作成(最初は全てNone)
self.board = [[None] * (NUM_LINE) for i in range(NUM_LINE)]
# 線と線の間隔(px)を計算
self.interval = CANVAS_SIZE // (NUM_LINE + 1)
# 交点描画位置の左上オフセット
self.offset_x = self.interval
self.offset_y = self.interval
# 縦線を描画
for x in range(NUM_LINE):
# 線の開始・終了座標を計算
xs = x * self.interval + self.offset_x
ys = self.offset_y
xe = xs
ye = (NUM_LINE - 1) * self.interval + self.offset_y
# 線を描画
self.canvas.create_line(
xs, ys,
xe, ye,
)
# 横線を描画
for y in range(NUM_LINE):
# 線の開始・終了座標を計算
xs = self.offset_x
ys = y * self.interval + self.offset_y
xe = (NUM_LINE - 1) * self.interval + self.offset_x
ye = ys
# 線を描画
self.canvas.create_line(
xs, ys,
xe, ye,
)
def drawDisk(self, x, y, color):
'''(x,y)の交点に色がcolorの石を置く(円を描画する)'''
# (x,y)の交点の中心座標を計算
center_x = x * self.interval + self.offset_x
center_y = y * self.interval + self.offset_y
# 中心座標から円の開始座標と終了座標を計算
xs = center_x - (self.interval * 0.8) // 2
ys = center_y - (self.interval * 0.8) // 2
xe = center_x + (self.interval * 0.8) // 2
ye = center_y + (self.interval * 0.8) // 2
# 円を描画する
tag_name = 'disk_' + str(x) + '_' + str(y)
self.canvas.create_oval(
xs, ys,
xe, ye,
fill=color,
)
return tag_name
def getIntersection(self, x, y):
'''キャンバス上の座標を交点の位置に変換'''
ix = (x - self.offset_x + self.interval // 2) // self.interval
iy = (y - self.offset_y + self.interval // 2) // self.interval
return ix, iy
def click(self, event):
'''盤面がクリックされた時の処理'''
if self.player != YOU:
# COMが石を置くターンの時は何もしない
return
# クリックされた位置がどの交点であるかを計算
x, y = self.getIntersection(event.x, event.y)
if x < 0 or x >= NUM_LINE or y < 0 or y >= NUM_LINE:
# 盤面外の交点の場合は何もしない
return
if not self.board[y][x]:
# 石が置かれていない場合はクリックされた位置に石を置く
# 石を置く
self.place(x, y, self.color[self.player])
def place(self, x, y, color):
'''(x,y)の交点に色がcolorの石を置く'''
# (x,y)に石を置く(円を描画する)
self.drawDisk(x, y, color)
# 描画した円の色を管理リストに記憶させておく
self.board[y][x] = color
# 5つ並んだかどうかをチェック
if self.count(x, y, color) >= 5:
self.showResult()
return
# プレイヤーは交互に変更
if self.player == COM:
self.player = YOU
else:
self.player = COM
if self.player == COM:
# 次のプレイヤーがCOMの場合は1秒後にCOMに石を置く場所を決めさせる
self.master.after(1000, self.com)
def count(self, x, y, color):
'''(x,y)に色がcolorの石を置いた時の石の並び数をチェック'''
# チェックする方向をリストに格納
count_dir = [
(1, 0), # 右
(1, 1), # 右下
(0, 1), # 上
(-1, 1), # 左下
]
max = 0 # 石の並び数の最大値
# count_dirの方向に対して石の並び数をチェック
for i, j in count_dir:
# 石の並び数を1に初期化
count_num = 1
# (x,y)から現在の方向に対して1交点ずつ遠ざけながら石が連続しているかをチェック
for s in range(1, NUM_LINE):
xi = x + i * s
yj = y + j * s
if xi < 0 or xi >= NUM_LINE or yj < 0 or yj >= NUM_LINE:
# 盤面外の交点の場合は石は連続していない
break
if self.board[yj][xi] != color:
# 異なる色の石が置かれていれば石は連続していない
break
# 上記以外の場合は石が連続している
count_num += 1
# 次は逆方向をチェック
for s in range(-1, -(NUM_LINE), -1):
xi = x + i * s
yj = y + j * s
if xi < 0 or xi >= NUM_LINE or yj < 0 or yj >= NUM_LINE:
break
if self.board[yj][xi] != color:
break
count_num += 1
# 最大値の置き換え
if max < count_num:
max = count_num
# 石が連続している数の最大値を返却
return max
def showResult(self):
'''ゲーム終了時の結果を表示する'''
# 勝利者は先ほど石を置いたプレイヤー
winner = self.player
# 結果をメッセージボックスで表示する
if winner == YOU:
tkinter.messagebox.showinfo('結果', 'あなたの勝ちです!!!')
else:
tkinter.messagebox.showinfo('結果', 'あなたの負けです...')
def com(self):
'''COMに石を置かせる'''
# 相手が石を置いた時に石が最大で連続する交点の座標を取得
max_list = []
max = 0
for y in range(NUM_LINE):
for x in range(NUM_LINE):
if not self.board[y][x]:
# (x,y)座標に相手が石を置いた場合に石が連続する数を取得
count_num = self.count(x, y, self.color[YOU])
if count_num == max:
max_list.append((x, y))
elif count_num > max:
max_list = []
max_list.append((x, y))
max = count_num
# 石が連続する数が最大になる交点の中から1つの座標をランダムに取得
choice = random.randrange(len(max_list))
x, y = max_list[choice]
# 石を置く
self.place(x, y, COM_COLOR)
# スクリプト処理ここから
app = tkinter.Tk()
app.title('五目並べ')
gobang = Gobang(app)
app.mainloop()
スクリプトを実行すると作成する「五目並べゲーム」で紹介した五目並べゲームが起動します。
スクリプト先頭部分の下記を変更すれば、キャンバスのサイズや盤面上の縦横方向の線の数、盤面や置く石の色などを設定することもできます。
# キャンバスの横方向・縦方向のサイズ(px)
CANVAS_SIZE = 400
# ラインの数
NUM_LINE = 10
# 色の設定
BOARD_COLOR = 'burlywood3' # 盤面の背景色
YOUR_COLOR = 'black' # あなたの石の色
COM_COLOR = 'white' # 相手の石の色
スクリプトの解説
今回は五目並べゲーム作成時のポイントとして挙げた下記の4つの観点からスクリプトを簡単に解説していきたいと思います。
スポンサーリンク
盤面上の石の管理
盤面上の石の管理でも解説したように、盤面上の石の管理は self.board
(Gobang
クラスの属性)で行っています。
この self.board
に対し、各メソッドで下記を行うことで盤面上の石を管理しています。
initGobang
:self.board
の初期化- 全ての要素を
None
に設定
- 全ての要素を
place
:self.board
の更新- 石が置かれる (
x
,y
) 座標に対応する要素self.board[y][x]
に、置かれる石の色名color
を格納
- 石が置かれる (
さらに、下記のメソッドではこの self.board
を参照して処理を行なっています。
count
:各方向に対して同じ色の石がいくつ連続して並んでいるかを確認するために参照click
:クリックされた位置の交点にすでに石が置かれていないかを確認するために参照com
:コンピュータが石を置く位置を決めるのに参照
五目並べ画面の実現
五目並べ画面の実現で解説したように、今回作成する五目並べゲームにおいては盤面自体をキャンバスとし、盤面上の線や盤面上の石はそのキャンバスに図形を描画することで表現しています。
これらの処理は下記のメソッドで実行しています。
createWidgets
:キャンバスを作成initGobang
:線を描画drawDisk
:石を描画
石を置く処理の実現
石を置く処理の実現でも解説したように、今回のスクリプトではキャンバス上をマウスでクリックされた際に石を置くようにしています。
このキャンバス上のマウスクリックのイベント受付を行うために、setEvents
メソッドでキャンバスのインスタンス self.canvas
に bind
メソッドを実行させています。
self.canvas.bind('<ButtonPress>', self.click)
さらにイベントハンドラ click
においては、クリックされた座標を event.x
と event.y
から取得し、それを getIntersection
メソッドに指定することで、クリックされた座標に一番近い交点の位置を取得しています。
この getIntersection
メソッドで行なっているのは石を置く処理の実現で解説した計算になります。
さらに、self.board
を参照して、その交点にすでに石が置かれているかどうかを確認し、置かれていない場合は place
メソッドを実行して実際に石を置く処理を行なっています。
place
メソッドでは、石を置くことを表現するために石の描画を drawDisk
メソッドにより実行し、さらに count
メソッドで石がすでに 5
つ以上並べられているかどうかの確認を行なっています。
5
つ以上並べられている場合は showResult
メソッドで結果を表示します。
また、石が置かれた後はプレイヤーが入れ替わるので、現在のプレイヤーとは異なる方のプレイヤーを self.player
に設定するようにしています。
self.player
は次に石を置くプレイヤーが誰かを示す値を保持する Gobang
クラスの属性です
具体的には次に石を置くプレイヤーによって下記の値を保持しています
YOU
(1
):次に石を置くプレイヤーがユーザーの時COM
(2
):次に石を置くプレイヤーがコンピュータの時
プレイヤーがコンピュータになった際には、コンピュータに石を置かせるために com
メソッドを実行しています(after
メソッドを利用して 1
秒後に com
メソッドを実行するようにしています)。
この com
メソッドでは、全交点の中から「次に相手が石を置いたときに同じ石の並び数が最大になる位置」を見つけ出し、その交点に石を置くようにしています。つまりコンピュータにとって “相手が石を置くと一番不利になる位置” に石を置くようにしています。
なのでこのコンピュータは防戦一方です。この com
メソッドあたりを作り込むことで、もっと強いコンピュータに仕立てることも可能です。
この辺りの制御を行なっているのが com
メソッドの下記部分になります。
# 相手が石を置いた時に石が最大で連続する交点の座標を取得
max_list = []
max = 0
for y in range(NUM_LINE):
for x in range(NUM_LINE):
if not self.board[y][x]:
# (x,y)座標に相手が石を置いた場合に石が連続する数を取得
count_num = self.count(x, y, self.color[YOU])
if count_num == max:
max_list.append((x, y))
elif count_num > max:
max_list = []
max_list.append((x, y))
max = count_num
# 石が連続する数が最大になる交点の中から1つの座標をランダムに取得
choice = random.randrange(len(max_list))
x, y = max_list[choice]
# 石を置く
self.place(x, y, COM_COLOR)
count
は次に説明する同じ石が連続して並んでいる個数の最大値を取得するメソッドになります。
スポンサーリンク
並べられた石のカウント
同じ石が連続して並んでいる個数をカウントする処理は count
メソッドで実行しています。この count
メソッドは先ほど説明した com
メソッドでコンピュータが石を置く位置を決定するために実行したり、place
メソッドでゲーム終了したかどうかを判断するために実行したりしています。
エラー制御などを追加で行っていますが、基本的に count
メソッドがやっていることは並べられた石のカウントで解説した処理の通りです。
ただし、count
メソッドにおいては各方向において一番長く同じ石が連続している個数を返却するようにしています。で、place
メソッドでは、この返却する値が 5
以上の場合はゲームの結果を showResult
を表示するようにしています。
まとめ
このページでは Python の tkinter を用いた「五目並べゲーム」の作り方を解説しました!
この五目並べゲームを作る上でポイントになるのは下記の4点だと思います。
特に最後の「並べられた石のカウント」は五目並べ特有の判断を行う必要があり、ここをうまく実現できるかが五目並べゲームが作れるかどうかの鍵になってくると思います。
また、この判断を行うためには2次元座標を考慮しながら処理を行う必要があります。ここは慣れるまで難しいかもしれませんが、こういったゲームを作りながら実際にプログラミングしてみることで楽しく慣れることができると思います。
2次元座標は、ゲームだけでなく画像処理などさまざまな分野においても活用されるので、2次元座標に慣れておくことに越したことはないと思います!せっかくなのでゲームを作りながら楽しく慣れていきましょう!
五目並べ同様のボードゲームの作り方として、下記ページで「オセロ」の作り方も解説しています!細かい部分は異なりますが、大枠としては今回紹介した五目並べの作り方と似ていますので、いろんなゲームを作ってみたいという方は是非下記ページも読んでみてください!
【Python/tkinter】オセロ(リバーシ)ゲームの作り方オススメ参考書(PR)
簡単なアプリやゲームを作りながら Python について学びたいという方には、下記の Pythonでつくる ゲーム開発 入門講座 がオススメです!ちなみに私が Python を始めるときに最初に買った書籍です!
下記ようなゲームを作成しながら Python の基本が楽しく学べます!素材もダウンロードして利用できるため、作成したゲームの見た目にも満足できると思います。
- すごろく
- おみくじ
- 迷路ゲーム
- 落ち物パズル
- RPG
また本書籍は下記のような構成になっているため、Python 初心者でも内容を理解しやすいです。
- プログラミング・Python の基礎から解説
- 絵を用いた解説が豊富
- ライブラリの使い方から解説(tkitner と Pygame)
- ソースコードの1行1行に注釈
ゲーム開発は楽しくプログラミングを学べるだけでなく、ゲームで学んだことは他の分野のプログラミングにも活かせるものが多いですし(キーボードの入力受付のイベントや定期的な処理・画像や座標を扱い方等)、逆に他の分野のプログラミングで学んだ知識を活かしやすいことも特徴だと思います(例えばコンピュータの動作に機械学習を取り入れるなど)。
プログラミングを学ぶのにゲーム開発は相性抜群だと思います。
Python の基礎や tkinter・Pygame の使い方をご存知なのであれば、下記の 実践編 をいきなり読むのもアリです。
実践編 では「シューティングゲーム」や「アクションゲーム」「3D カーレース」等のより難易度の高いゲームを作りながらプログラミングの力をつけていくことができます!
また、単にゲームを作るのではなく、対戦相手となるコンピュータの動作のアルゴリズムにも興味のある方は下記の「Pythonで作って学べるゲームのアルゴリズム入門」がオススメです。
この本はゲームのコンピュータ(AI)の動作アルゴリズム(思考ルーチン)に対する入門解説本になります。例えばオセロゲームにおけるコンピュータが、どのような思考によって石を置く場所を決めているか等の基本的な知識を得ることが出来ます。
プログラミングを挫折せずに続けていくためには楽しさを味わいながら学習することが大事ですので、特にゲームに興味のある方は、この辺りの参考書と一緒に Python を学んでいくのがオススメです!