質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

1350閲覧

tkinterで三目並べ(〇×ゲーム)を作成したい

usagi_

総合スコア1

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/11/30 03:28

編集2022/11/30 04:56

前提

tkinterで三目並べ(〇×ゲーム)を作っています。
一通り作成したものの、以下のようなエラーが出てしまい実行できず困っています。

実現したいこと

  • ボタンを押すと〇×が記載され、三目並べができるようになる

発生している問題・エラーメッセージ

root.bind("<1>", play) NameError: name 'play' is not defined

該当のソースコード

python

1import tkinter as tk 2 3#先行プレイヤー:1 4turn = 1 5 6class MyFrame(tk.Frame): 7 def __init__(self,master = None): 8 super().__init__(master) 9 #判定用配列作成 10 self.init = 0 11 self.board = [[self.init for i in range(3)] for j in range(3)] 12 #ボタン作成 13 w = 15 14 h = 7 15 self.btn = [[tk.Button(self, width=w, height=h) for i in range(3)] for j in range(3)] 16 for i in range(3): 17 for j in range(3): 18 self.btn[j][i].grid(column=j, row=i) 19 20 #データの初期化 21 def init_turn(self): 22 self.board = [[self.init for i in range(3)] for j in range(3)] 23 24 #盤面関連の関数 25 def check_board(self): 26 #垂直方向 27 for i in range(3): 28 if self.board[i][0] != 0: 29 if self.board[i][0] == self.board[i][1] and self.board[i][0] == self.board[i][2]: 30 return self.board[i][0] 31 32 #水平方向 33 for j in range(3): 34 if self.board[0][j] != 0: 35 if self.board[0][j] == self.board[1][j] and self.board[0][j] == self.board[2][j]: 36 return self.board[0][j] 37 38 #対角方向 39 if self.board[1][1] != 0: 40 if self.board[0][0] == self.board[1][1] and self.board[0][0] == self.board[2][2]: 41 return self.board[1][1] 42 elif self.board[0][2] == self.board[1][1] and self.board[0][2] == self.board[2][0]: 43 return self.board[1][1] 44 45 for i in range(3): 46 for j in range(3): 47 if self.board[j][i] == 0: 48 return 0 49 50 return -2 51 52 #プレイヤー交代 53 def change_turn(self): 54 self.turn = - self.turn 55 56 #〇× 57 def play(self): 58 self.e = tk.Entry(self) 59 60 for i in range(3): 61 for j in range(3): 62 if self.e.widget == self.btn[j][i]: 63 if self.turn == 1: 64 self.e.widget["text"] = "〇" 65 self.board[j][i] = 1 66 elif self.turn == -1: 67 self.e.widget["text"] = "×" 68 self.board[j][i] = -1 69 70 self.turn = self.change_turn() 71 72 if self.check_board() == 1: 73 print("先行プレイヤーの勝ちです") 74 self.init_turn() 75 self.init_text() 76 elif self.check_board() == -1: 77 print("後攻プレイヤーの勝ちです") 78 self.init_turn() 79 self.init_text() 80 elif self.check_board() == -2: 81 print("引き分けです") 82 self.init_turn() 83 self.init_text() 84 85 #ボタンのテキストを初期化 86 def init_text(self): 87 for i in range(3): 88 for j in range(3): 89 self.btn[i][j]["text"] = "" 90 91def main(): 92#ウィンドウの作成 93 root = tk.Tk() 94 f = MyFrame(root) 95 f.pack() 96 root.bind("<1>", play) 97 f.mainloop() 98 99if __name__ == '__main__': 100 main() 101 102

試したこと

・クラスを使用しないverの作成(こちらは動作します)

import tkinter as tk from tkinter import messagebox #先行プレイヤー:1 turn = 1 #判定用の配列 init = 0 board = [[init for i in range(3)] for j in range(3)] #データの初期化 def init_turn(): global init, board board = [[init for i in range(3)] for j in range(3)] #盤面関連の関数 def check_board(): global board #垂直方向 for i in range(3): if board[i][0] != 0: if board[i][0] == board[i][1] and board[i][0] == board[i][2]: return board[i][0] #水平方向 for j in range(3): if board[0][j] != 0: if board[0][j] == board[1][j] and board[0][j] == board[2][j]: return board[0][j] #対角方向 if board[1][1] != 0: if board[0][0] == board[1][1] and board[0][0] == board[2][2]: return board[1][1] elif board[0][2] == board[1][1] and board[0][2] == board[2][0]: return board[1][1] #空きマスがない時 for i in range(3): for j in range(3): if board[j][i] == 0: return 0 return -2 #プレイヤー交代 def change_turn(): global turn return turn * (-1) #〇× def play(): global board, turn for i in range(3): for j in range(3): if e.widget == btn[j][i]: if turn == 1: e.widget["text"] = "〇" board[j][i] = 1 elif turn == -1: e.widget["text"] = "×" board[j][i] = -1 turn = change_turn() if check_board() == 1: messagebox.showinfo('finish!', '先行プレイヤーの勝ちです') init_turn() init_text() elif check_board() == -1: messagebox.showinfo('finish!', '後攻プレイヤーの勝ちです') init_turn() init_text() elif check_board() == -2: messagebox.showinfo('finish!', '引き分けです') init_turn() 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("三目並べ") #ボタン作成 w = 15 h = 7 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) root.bind("<1>", play) root.mainloop()

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

動いているソースにある処理の多くが抜けているのが原因ですので、それらを実装すれば動くと思います。

ちなみにボタンを押しても何も起きないのは、動いているソースの

python

1root.bind("<1>", play)

がClass版にないからです。

ただし、先に書いたとおり必要な処理が他にもたくさんあるので、それらを入れないと動きませんが。


追記1

・root.bind("<1>", play) NameError: name 'play' is not defined
root.bind("<1>,MyFrame.play")に変更
以下エラーメッセージ self.tk = master.tk AttributeError: 'Event' object has no attribute 'tk'

rootでのbtnへのメソッドのbindをクラスの外でやるのはべきではありません。
__init__でやりましょう。

外で初期化している turn もよくありません。
内部でself.turn としているように、インスタンス変数にすべきです。 なので __init__で初期化しましょう。

他にもたくさんありそうですが、がんばりましょう。

投稿2022/11/30 04:33

編集2022/11/30 05:52
TakaiY

総合スコア12743

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

usagi_

2022/11/30 04:53 編集

ご回答頂きありがとうございます。 大変恐縮ですが、誤って小さく動かしていた際のコードを記載しておりました。 TakaiY様の貴重なお時間を頂いてしまい申し訳ありません。 只今完全版に修正いたしました。 すると、以下のようなエラーメッセージが出てしまいました。 "e"の引き渡し方が宜しくないのでしょうか。 ・root.bind("<1>", play) NameError: name 'play' is not defined →root.bind("<1>,MyFrame.play")に変更 →以下エラーメッセージ self.tk = master.tk AttributeError: 'Event' object has no attribute 'tk'
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問