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

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

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

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

Q&A

1回答

2445閲覧

Pythonの8パズルのプログラムについて

mayataka

総合スコア0

Python

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

0グッド

0クリップ

投稿2020/07/28 04:31

編集2020/07/28 13:43

8パズルのプログラムについて質問です。
以下のような仕様に改良したいです。(回答していただいたプログラムコードも追加しました。)
1.パネルが正解の位置に動かせたらそのパネルを固定したい。
2.空白パネル(pice0)を斜めに交換出来てしまうので、斜め移動できないようにしたい。
どうすればよろしいでしょうか。

import tkinter as tk import random from tkinter import messagebox # 指定された番号がどの位置に表示されているか返却する def searchPiceIndex(pice_num): for idx, num in pice_dict.items(): if pice_num == num: return idx # クリックイベントの定義 def clickPice(event): num = int(event.widget['text']) changePice(num) drawPice() if pice_dict==answer_dict: close() # クリア処理 def close(): messagebox.showinfo('完成',message='完成しました') root.destroy() # 指定した数字のピースと0のピースの入替 def changePice(num): # クリックしたピースと0のピースの位置の特定 num_index = searchPiceIndex(num) zero_index = searchPiceIndex(0) # ピース位置管理の入替 pice_dict[num_index] = 0 pice_dict[zero_index] = num # 表示するピースの入替 pice_label_dict[num_index].configure(text=0) pice_label_dict[zero_index].configure(text=num) # 禁則事項の処理 def canSwapSpacePice(num): zero_idx = searchPiceIndex(0) idx = searchPiceIndex(num) upper_idx = idx - 3 lower_idx = idx + 3 left_idx = idx - 1 right_idx = idx + 1 if (upper_idx == zero_idx): return True elif (lower_idx == zero_idx): return True elif (left_idx!=3)and(left_idx!=6)and(left_idx == zero_idx): return True elif (right_idx!=4)and(right_idx!=7)and(right_idx == zero_idx): return True else: return False # ピース位置管理のランダム生成、解答生成 pice_dict = {} # ピース位置管理 answer_dict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:0} #解答 pice_numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8] # 表示する番号の種類 random_pice_list = random.sample(pice_numbers, 9) # 表示する番号をランダムに並べ替え for idx in range(1, 10): pice_dict[idx] = random_pice_list[idx - 1] # ランダムな値をセット # ウィンドウ生成 root = tk.Tk() root.title('8パズル') root.geometry('400x400') flm = tk.LabelFrame(root) # 画像読み込み pice_image = {} pice_image[0] = tk.PhotoImage(file='./image/0.png') pice_image[1] = tk.PhotoImage(file='./image/1.png') pice_image[2] = tk.PhotoImage(file='./image/2.png') pice_image[3] = tk.PhotoImage(file='./image/3.png') pice_image[4] = tk.PhotoImage(file='./image/4.png') pice_image[5] = tk.PhotoImage(file='./image/5.png') pice_image[6] = tk.PhotoImage(file='./image/6.png') pice_image[7] = tk.PhotoImage(file='./image/7.png') pice_image[8] = tk.PhotoImage(file='./image/8.png') # ピースの配列生成 pice_label_dict = {} def drawPice():  # ピース生成 pice1 = tk.Label(flm, text=pice_dict[1], image = pice_image[pice_dict[1]]) pice1.grid(column=0, row=0, padx=30, pady=30) pice1.bind('<1>', clickPice) pice_label_dict[1] = pice1 pice2 = tk.Label(flm, text=pice_dict[2], image = pice_image[pice_dict[2]]) pice2.grid(column=1, row=0, padx=30, pady=30) pice2.bind('<1>', clickPice) pice_label_dict[2] = pice2 pice3 = tk.Label(flm, text=pice_dict[3], image = pice_image[pice_dict[3]]) pice3.grid(column=2, row=0, padx=30, pady=30) pice3.bind('<1>', clickPice) pice_label_dict[3] = pice3 pice4 = tk.Label(flm, text=pice_dict[4], image = pice_image[pice_dict[4]]) pice4.grid(column=0, row=1, padx=30, pady=30) pice4.bind('<1>', clickPice) pice_label_dict[4] = pice4 pice5 = tk.Label(flm, text=pice_dict[5], image = pice_image[pice_dict[5]]) pice5.bind('<1>', clickPice) pice5.grid(column=1, row=1, padx=30, pady=30) pice_label_dict[5] = pice5 pice6 = tk.Label(flm, text=pice_dict[6], image = pice_image[pice_dict[6]]) pice6.bind('<1>', clickPice) pice6.grid(column=2, row=1, padx=30, pady=30) pice_label_dict[6] = pice6 pice7 = tk.Label(flm, text=pice_dict[7],image = pice_image[pice_dict[7]]) pice7.grid(column=0, row=2, padx=30, pady=30) pice7.bind('<1>', clickPice) pice_label_dict[7] = pice7 pice8 = tk.Label(flm, text=pice_dict[8], image = pice_image[pice_dict[8]]) pice8.grid(column=1, row=2, padx=30, pady=30) pice8.bind('<1>', clickPice) pice_label_dict[8] = pice8 pice0 = tk.Label(flm, text=pice_dict[9], image = pice_image[pice_dict[9]]) pice0.grid(column=2, row=2, padx=30, pady=30) pice0.bind('<1>', clickPice) pice_label_dict[9] = pice0 drawPice() flm.pack(side='top', pady=40) root.mainloop()

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

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

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

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

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

y_waiwai

2020/07/28 04:35

このままではコードが読めないので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
mayataka

2020/07/28 05:03

変更いたしました。お願い致します。
can110

2020/07/28 05:22

「うまく動かない」という部分を具体的に説明ください。 また、コード中に関数や処理がどのように動いているかの説明文(コメント)を入れてください。
mayataka

2020/07/28 13:45

変更いたしました
guest

回答1

0

上手く作動と言うのは恐らくパズルのピースクリック時に
ピースが入れ替わらないことを言っているのだと推測しての回答です。

ピースが入れ替わっているように見せるにはその都度描画する必要があります。
なのでピース描画部分を関数化して、
clickPice関数内でchangePice関数を呼び出した後に
その関数を呼び出せば入れ替わった配列でピースが再描画されます。

python

1・・・ 2def clickPice(event): 3 num = int(event.widget['text']) 4 changePice(num) 5 6 # ピースの描画 7 drawPice() 8 9 if pice_dict==answer_dict: 10 close() 11・・・ 12root = tk.Tk() 13root.title('8パズル') 14root.geometry('400x400') 15flm = tk.LabelFrame(root) 16 17pice_image = {} 18pice_image[0] = tk.PhotoImage(file='./image/0.png') 19pice_image[1] = tk.PhotoImage(file='./image/1.png') 20pice_image[2] = tk.PhotoImage(file='./image/2.png') 21pice_image[3] = tk.PhotoImage(file='./image/3.png') 22pice_image[4] = tk.PhotoImage(file='./image/4.png') 23pice_image[5] = tk.PhotoImage(file='./image/5.png') 24pice_image[6] = tk.PhotoImage(file='./image/6.png') 25pice_image[7] = tk.PhotoImage(file='./image/7.png') 26pice_image[8] = tk.PhotoImage(file='./image/8.png') 27 28pice_label_dict = {} 29 30# ピースの描画 31def drawPice(): 32 pice1 = tk.Label(flm, text=pice_dict[1], image = pice_image[pice_dict[1]]) 33 pice1.grid(column=0, row=0, padx=30, pady=30) 34 pice1.bind('<1>', clickPice) 35 pice_label_dict[1] = pice1 36 37 pice2 = tk.Label(flm, text=pice_dict[2], image = pice_image[pice_dict[2]]) 38 pice2.grid(column=1, row=0, padx=30, pady=30) 39 pice2.bind('<1>', clickPice) 40 pice_label_dict[2] = pice2 41 42 pice3 = tk.Label(flm, text=pice_dict[3], image = pice_image[pice_dict[3]]) 43 pice3.grid(column=2, row=0, padx=30, pady=30) 44 pice3.bind('<1>', clickPice) 45 pice_label_dict[3] = pice3 46 47 pice4 = tk.Label(flm, text=pice_dict[4], image = pice_image[pice_dict[4]]) 48 pice4.grid(column=0, row=1, padx=30, pady=30) 49 pice4.bind('<1>', clickPice) 50 pice_label_dict[4] = pice4 51 52 pice5 = tk.Label(flm, text=pice_dict[5], image = pice_image[pice_dict[5]]) 53 pice5.bind('<1>', clickPice) 54 pice5.grid(column=1, row=1, padx=30, pady=30) 55 pice_label_dict[5] = pice5 56 57 pice6 = tk.Label(flm, text=pice_dict[6], image = pice_image[pice_dict[6]]) 58 pice6.bind('<1>', clickPice) 59 pice6.grid(column=2, row=1, padx=30, pady=30) 60 pice_label_dict[6] = pice6 61 62 pice7 = tk.Label(flm, text=pice_dict[7], image = pice_image[pice_dict[7]]) 63 pice7.grid(column=0, row=2, padx=30, pady=30) 64 pice7.bind('<1>', clickPice) 65 pice_label_dict[7] = pice7 66 67 pice8 = tk.Label(flm, text=pice_dict[8], image = pice_image[pice_dict[8]]) 68 pice8.grid(column=1, row=2, padx=30, pady=30) 69 pice8.bind('<1>', clickPice) 70 pice_label_dict[8] = pice8 71 72 pice0 = tk.Label(flm, text=pice_dict[9], image = pice_image[pice_dict[9]]) 73 pice0.grid(column=2, row=2, padx=30, pady=30) 74 pice0.bind('<1>', clickPice) 75 pice_label_dict[9] = pice0 76 77# ピースの描画 78drawPice() 79 80flm.pack(side='top', pady=40) 81root.mainloop()

投稿2020/07/28 05:29

yureighost

総合スコア2183

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

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

teamikl

2020/07/28 07:52

少し補足で、再描画の時にラベルが毎回新規作成されてしまうのは、 パフォーマンスに影響するので、対策したほうがいいかも知れません。 ## 確認方法 drawPice関数の末尾で print(pice0) として、クリックを連打すると、ウィジェットのIDの 値が増加するのが見られると思いますが、値が数万になってくるとパフォーマンスに影響します。 具体的には、クリック連打の後、ウィンドウを閉じようとすると少しラグがでたり固まったりします。 1クリックにつき+9 と軽微なので、数百~数千回クリックしないと再現できないかも知れません。 # 手作業での再現は大変なので、百回再描画を再現するコード for _ in range(100): drawPiece() ## 簡単な解決策: name= を付けることでウィジェットの再生成を抑制できます。 (再描画される全てのウィジェットに対して name を付ける) pice0 = tk.Label(~略~, name="label0") ---- ## 他の解決策: - ウィジェット生成は初期化時の一度のみとして、 変更の合ったピースだけ grid() を更新する。 ---- 関連: tkinterが重くなりがち。 https://teratail.com/questions/279694
yureighost

2020/07/28 08:16

これは補足ありがとうございます。 個人的には軽い物ばかり作っていたので負荷対策については考慮できていませんでした。 参考にさせていただきます。
mayataka

2020/07/28 13:44

お二方の回答を参考にさせていただきました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問