文系忘備録

どこにでもいる文系大学生の忘備録です

MENU

【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)

全体のコード(コピペ可)


Tic-Tac-Toe with TKinter