【Python入門】Tkinterでマルバツゲームを作ってみよう!【サンプルコード有】【コピペ可】【チュートリアル】
みなさんこんにちは。
今回は↓のような実際に遊べるマルバツゲームをTkinterで作っていこうと思います。
初期化
import tkinter as tk from tkinter import messagebox from functools import partial import random import sys screenHeight = 390 screenWidth = 390 class Application(tk.Frame): def __init__(self,master = None): super().__init__(master) self.mainframe = tk.Frame(self.master) self.mainframe.pack() self.frame1 = tk.Frame(self.master) self.frame1.grid(row=0,column=0,in_=self.mainframe,pady=50) self.cells = [[tk.StringVar() for i in range(3)] for j in range(3)] self.createButtonsWithGrid(cellSize=9,gridSize=3,fontSize=10) def createButtonsWithGrid(self,cellSize,gridSize:int,fontSize=0,cellSpace=0): for i in range(0,gridSize): for j in range(0,gridSize): button = tk.Button( self.frame1, relief="groove", width=cellSize, height=int(cellSize/2), #text=text, textvariable=self.cells[i][j], font=("System",fontSize), command=partial(self.clicked,(i,j)) ) button.grid(column=j,row=i,padx=cellSpace,pady=cellSpace) ~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~~~~~ if __name__ == "__main__": root = tk.Tk() root.title("○×ゲーム") # Screen size root.geometry(str(screenWidth)+"x"+str(screenHeight)) app = Application(master = root) root.mainloop()
初期化は以上のように行っています。
Tkinterではボタンなどのテキストに変数を割り当てることができるので、
文字列で二次元配列を作成しボタンにそれぞれ割り当てています。
#3x3の文字列の二次元配列を作成 self.cells = [[tk.StringVar() for i in range(3)] for j in range(3)] #ボタンの作成 for i in range(0,gridSize): for j in range(0,gridSize): button = tk.Button( self.frame1, relief="groove", width=cellSize, height=int(cellSize/2), #text=text, #ボタンに文字列を割り当てる textvariable=self.cells[i][j], font=("System",fontSize), command=partial(self.clicked,(i,j)) ) button.grid(column=j,row=i,padx=cellSpace,pady=cellSpace)
また以下のようにすることでボタンをグリッド配列にしています。
#行と列にそれぞれボタンを配置 button.grid(column=j,row=i,padx=cellSpace,pady=cellSpace) #pax,pady : ボタン外のスペース
そしてボタンを格納したフレームを中央に配置するために別のフレームを親にしています。
#メインフレームを作成 self.mainframe = tk.Frame(self.master) self.mainframe.pack() self.frame1 = tk.Frame(self.master) #メインフレームを親化 self.frame1.grid(row=0,column=0,in_=self.mainframe,pady=50)
勝ち負けの判定
if p[0] == maxIndex: if p[1] == maxIndex: if (self.checkCell((p[0],p[1]-2),c) and self.checkCell((p[0],p[1]-1),c)): return True elif (self.checkCell((p[0]-2,p[1]),c) and self.checkCell((p[0]-1,p[1]),c)): return True elif (self.checkCell((p[0]-2,p[1]-2),c) and self.checkCell((p[0]-1,p[1]-1),c)): return True elif p[1] == 0: if (self.checkCell((p[0]-2,p[1]),c) and self.checkCell((p[0]-1,p[1]),c)): return True elif (self.checkCell((p[0],p[1]+2),c) and self.checkCell((p[0],p[1]+1),c)): return True elif (self.checkCell((p[0]-2,p[1]+2),c) and self.checkCell((p[0]-1,p[1]+1),c)): return True ~~~~~~~~~~省略~~~~~~~~~ #チェック用関数 def checkCell(self,p,c): return self.cells[p[0]][p[1]].get() == c
以上のように角の場合は横二つを、間のマスの場合は両隣を見て勝ち負けを判定します。
引き分けの判定
以下のようにして空白のマスがあるか確認し、なければ引き分けになるようにしています。
def checkWholeBoard(self): for i in self.cells: for j in i: if (j.get() == ""): return False return True
敵の配置
敵はランダムにでた数字で配置しています。
def setEnemy(self): #置ける場所がない場合は中断 if self.checkWholeBoard(): return (-1,-1) i = random.randint(0,len(self.cells)-1) j = random.randint(0,len(self.cells)-1) #置ける場所が見つかるまで引く while (self.checkCell((i,j),"o") or self.checkCell((i,j),"x")): i = random.randint(0,len(self.cells)-1) j = random.randint(0,len(self.cells)-1) self.changeCell((i,j),"x") return (i,j)