どうも多浪Fランぼっち底辺大学生です。
今回はPythonのTkinter(ティーキンター)ライブラリを利用して、
マルバツゲーム(三目並べ)を作成していきたいと思います。
また、GUIに実装した内容にしたい
と考えている人に向けた記事となっています。
まず最初に完成形をお見せしますね(^o^)/

少し見にくいかもしれませんが、こんな感じです。
ウィンドウ上のボタンを押せば交互に”○”と”×”が表示され、判定結果がコマンド画面へ表示されます。
一通りpythonを学習した人なら理解できる内容になっています。
ので、分からない箇所があるのなら参考書等で復習してください。
Contents
マルバツゲーム(三目並べ)のソースコード
早速、マルバツゲーム(三目並べ)のソースコードを紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
import tkinter as tk #判定用のデータ(配列)の初期化 def init_data(): global init, data data = [[init for i in range(3)] for j in range(3)] #ルールに則りデータ判定を行う def judge(): global data #縦の探索 for i in range(3): if data[i][0] != 0: if data[i][0] == data[i][1] and data[i][0] == data[i][2]: return data[i][0] #横の探索 for j in range(3): if data[0][j] != 0: if data[0][j] == data[1][j] and data[0][j] == data[2][j]: return data[0][j] #斜めの探索 if data[1][1] != 0: if data[0][0] == data[1][1] and data[0][0] == data[2][2]: return data[1][1] elif data[0][2] == data[1][1] and data[0][2] == data[2][0]: return data[1][1] for i in range(3): for j in range(3): if data[j][i] == 0: return 0 return -2 #プレイヤーの変更 def turn(): global player return player * (-1) #クリックされたボタンにテキスト(〇か✖)を追加 def mark(e): global data, player for i in range(3): for j in range(3): if e.widget == btn[j][i]: if player == 1: e.widget["text"] = "〇" data[j][i] = 1 elif player == -1: e.widget["text"] = "×" data[j][i] = -1 player = turn() if judge() == 1: print("先行プレイヤーの勝利") init_data() init_text() elif judge() == -1: print("後攻プレイヤーの勝利") init_data() init_text() elif judge() == -2: print("引き分けです") init_data() init_text() #ボタンのテキストを初期化 def init_text(): global btn for i in range(3): for j in range(3): btn[i][j]["text"] = "" #ウィンドウの作成 root = tk.Tk() root.title("〇×ゲーム") #先行プレイヤーを1とする player = 1 #判定用配列の作成 init = 0 data = [[init for i in range(3)] for j in range(3)] #ボタンの作成 w = 20 h = 5 btn = [[tk.Button(root, width=w, height=h) for i in range(3)] for j in range(3)] # btn1 = tk.Button(root, width=w, height=h) # btn2 = tk.Button(root, width=w, height=h) # btn3 = tk.Button(root, width=w, height=h) # btn4 = tk.Button(root, width=w, height=h) # btn5 = tk.Button(root, width=w, height=h) # btn6 = tk.Button(root, width=w, height=h) # btn7 = tk.Button(root, width=w, height=h) # btn8 = tk.Button(root, width=w, height=h) # btn9 = tk.Button(root, width=w, height=h) #ボタンをウィンドウに配置 for i in range(3): for j in range(3): btn[j][i].grid(column=j, row=i) # btn1.grid(column=0, row=0) # btn2.grid(column=1, row=0) # btn3.grid(column=2, row=0) # btn4.grid(column=0, row=1) # btn5.grid(column=1, row=1) # btn6.grid(column=2, row=1) # btn7.grid(column=0, row=2) # btn8.grid(column=1, row=2) # btn9.grid(column=2, row=2) #クリックアクション root.bind("<1>", mark) #実行 root.mainloop() |
こんな感じですね(-ω-)/
パッと見「簡単そうなコーディングだな」と分かってもらえたはずです。
マルバツゲーム(三目並べ)作成にあたって、少し解説します
今回のマルバツゲーム(三目並べ)の仕様としては、以下の通りです。
- ウィンドウを作成して、3×3でボタンを配置
- ボタンがクリックされたら、先行後攻を交互にテキスト表示
(先行)player = 1の場合:〇
(後攻)player = -1の場合:× - ボタンが押される度に判定を行う
- 判定結果により、勝敗結果を表示し、ボタンテキストを初期化する
それでは、一応解説していくんで暇なら目を通してみて下さい。
リスト内包表記
1 |
data = [[init for i in range(3)] for j in range(3)] |
この様にリスト内包表記をする事で、3×3のリスト(配列)を生成することが出来ます。
因みに、リスト内の各要素には” init = 0 ”の値が格納されます。
ウィンドウにボタンを設置する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import tkinter as tk #ウィンドウの作成 root = tk.Tk() root.title("〇×ゲーム") #ボタンの作成 w = 20 #ボタン横幅 h = 5 #ボタン縦幅 #各変数に格納する方法① # btn1 = tk.Button(root, width=w, height=h) # btn2 = tk.Button(root, width=w, height=h) # btn3 = tk.Button(root, width=w, height=h) # btn4 = tk.Button(root, width=w, height=h) # btn5 = tk.Button(root, width=w, height=h) # btn6 = tk.Button(root, width=w, height=h) # btn7 = tk.Button(root, width=w, height=h) # btn8 = tk.Button(root, width=w, height=h) # btn9 = tk.Button(root, width=w, height=h) #配列に格納する方法② btn = [[tk.Button(root, width=w, height=h) for i in range(3)] for j in range(3)] #ボタンをウィンドウに配置 #各変数ごとにボタンを配置を指定① # btn1.grid(column=0, row=0) # btn2.grid(column=1, row=0) # btn3.grid(column=2, row=0) # btn4.grid(column=0, row=1) # btn5.grid(column=1, row=1) # btn6.grid(column=2, row=1) # btn7.grid(column=0, row=2) # btn8.grid(column=1, row=2) # btn9.grid(column=2, row=2) #配列に格納されたボタンを読み出し配置② for i in range(3): for j in range(3): btn[j][i].grid(column=j, row=i) |
今回はボタンのサイズを指定して、
1 2 3 |
w = 20 #ボタン横幅 h = 5 #ボタン縦幅 tk.Button(root, width=w, height=h) |
きれいに敷き詰められた3×3のボタンが配置されるように記述しました。
1 |
部品.grid(column=列, row=行) |
配列を使えば、同じような記述を省略できる
btn1 = ~~~
btn2 = ~~~
とボタンを作成して、
btn1.grid(~~~)
btn2.grid(~~~)
と、ほぼ同じ記述を繰り返す方法ですね。
このやり方では、記述やコピペが面倒なので採用していません。
一方、配列を使用することで同じような処理を省略することが可能です。
1 2 3 4 5 6 7 8 9 |
#ボタンの作成 w = 20 #ボタン横幅 h = 5 #ボタン縦幅 btn = [[tk.Button(root, width=w, height=h) for i in range(3)] for j in range(3)] #ボタンをウィンドウに配置 for i in range(3): for j in range(3): btn[j][i].grid(column=j, row=i) |
例えば、ボタンを100個ウィンドウに配置したいとなると、前者のやり方では非効率なので、こちらの方法をおすすめします。
各関数内にグローバル変数を宣言する
各関数内にグローバル変数を宣言しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def init_data(): global init, data ・・・ def judge(): global data ・・・ def turn(): global player ・・・ def mark(e): global data, player ・・・ def init_text(): global btn ・・・ |
グローバル変数を宣言することで、
“”関数外で宣言した変数を直接扱えるようになります。“”
ボタンを左クリックしたとき、〇 or × を表示する
今回はボタンが左クリックされた時に、mark関数(ボタンテキストの追加等々)を呼び出すようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def mark(e): global data, player for i in range(3): for j in range(3): if e.widget == btn[j][i]: if player == 1: e.widget["text"] = "〇" #クリックされたボタンにテキストを追加 data[j][i] = 1 elif player == -1: e.widget["text"] = "×" #クリックされたボタンにテキストを追加 data[j][i] = -1 player = turn() #クリックアクション root.bind("<1>", mark) |
tkinterでマウスの左クリックアクションを指定するには、
1 |
root.bind("<1>", 関数) |
と指定します。
bindメソッドの第一引数 “<1>” の部分ですね。
※他にも、キーボードが押された時やマウスが動いたときなどのイベントもあります。
そして、左クリックされると mark関数 が呼び出されます。
これは、「ウィンドウのどの座標がクリックされたのか?」や「どの部品がクリックされたのか?」などの情報が送られます。
この時、mark関数の引数に e があります。ここでは、
1 2 3 |
for i in range(3): for j in range(3): if e.widget == btn[j][i]: ←ココね(-ω-)/ |
とすることで、どのボタンが押されたのかを特定することが可能です!
クリックされたボタンが特定できれば、白紙だったボタンテキストに〇か×かを追加することが出来ます。
1 |
e.widget["text"] = "任意の文字" |
プレイヤー(”〇” “✖” の)交代
ボタンが押されるごとに〇と×が交互に入れ替わるように、turn関数を設けました。
1 2 3 |
def turn(): global player return player * (-1) |
先行プレイヤーを「1」とし、後攻プレイヤーを「-1」と設定する。
ボタンが押されるごとに、変数player を (-1)倍すれば上手く機能します。
マルバツゲーム(三目並べ)の判定

画像のように”横”・”縦”・”斜め”を探索して、1直線状3つの要素が等しいかどうかについて判定を行います。
今回のプログラムで言うと、二次元配列(data)の探索が対象ですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
def judge(): global data #縦の探索 for i in range(3): if data[i][0] != 0: if data[i][0] == data[i][1] and data[i][0] == data[i][2]: return data[i][0] #横の探索 for j in range(3): if data[0][j] != 0: if data[0][j] == data[1][j] and data[0][j] == data[2][j]: return data[0][j] #斜めの探索 if data[1][1] != 0: if data[0][0] == data[1][1] and data[0][0] == data[2][2]: return data[1][1] elif data[0][2] == data[1][1] and data[0][2] == data[2][0]: return data[1][1] #勝敗が付かず、空きマスがある場合 for i in range(3): for j in range(3): if data[j][i] == 0: return 0 #勝敗が付かず空きマスもない → 引き分け return -2 |
上(↑)のソースコードのように勝敗・引き分けを判定します。
参考にした書籍
Pythonでつくるゲーム開発 入門講座 実践編
ゼロからやさしくはじめるPython入門
Amazonの試し読みなどで購入を検討してみて下さい。
おすすめですよ(-ω-)/

おわり
以上で、Pythonによるマルバツゲーム(三目並べ)作成に関する紹介を終わります。
まだまだ、本格的に演出や機能を付け足す余地がありますので、
皆さんも色々と試行錯誤してみて下さい。
それでは。
