Pythonで数字パズルを作る

Python で 2✕2の数字パズルをつくってみました。Geminiとの合作です。
tkinterライブラリーのボタンを使用しています。コードはこんな感じです。

# number-puzzle
# 2x2 数字パズル
# Version: 0.3.0
# シャッフル機能を追加

import tkinter as tk
from tkinter import messagebox
import random

class NumberPuzzle:
    def __init__(self, master):
        self.master = master
        self.master.title("数字パズル 2x2")
        
        # 内部状態の定義
        self.goal = {1:1, 2:2, 3:3, 4:4}  # ゴール状態
        self.board = self.goal.copy()
        self.empty = 4 
        
        # ボードの初期状態: 位置番号(1-4)をキー、表示数字を値とする
        self.board = {1:1, 2:2, 3:3, 4:4}

        # ピースの色: 空白はシアン
        self.bg = {1: "white", 2: "white", 3: "white", 4: "cyan"}
        self.fg = {1: "black", 2: "black", 3: "black", 4: "#00eeee"}
        # 押下時のピースの色
        self.abg = {1: "#eeeeee", 2: "#eeeeee", 3: "#eeeeee", 4: "#00eeee"}
        self.afg = {1: "black", 2: "black", 3: "black", 4: "#00dddd"}
        
        # 隣接リスト: 各位置に隣接する位置
        self.adj = {1: [2, 3], 2: [1, 4], 3: [1, 4], 4: [2, 3]}
        
        self.buttons = {}
        self.create_widgets()

    def create_widgets(self):
        # パズル本体のグリッド
        self.frame = tk.Frame(self.master)
        self.frame.pack(padx=10, pady=10)

        for i in range(1, 5):
            row, col = (i - 1) // 2, (i - 1) % 2
            btn = tk.Button(self.frame, text=str(self.board[i]), font=("Consolas", 40),
                            width=3, height=1,
                            command=lambda pos=i: self.click_tile(pos))
            btn.grid(row=row, column=col, padx=2, pady=2)
            self.buttons[i] = btn
        
        # 操作用ボタン
        self.shuffle_btn = tk.Button(self.master, text="スタート", font=("Arial", 12, "bold"),
                                     command=self.shuffle_board, bg="#f0f0f0")
        self.shuffle_btn.pack(fill=tk.X, padx=12, pady=5)
        
        self.update_buttons()

    def click_tile(self, pos, is_shuffling=False):
        if self.empty in self.adj[pos]:
            # ピースの移動(データ更新)
            self.board[self.empty] = self.board[pos]
            self.board[pos] = 4
            self.empty = pos
            
            if not is_shuffling:
                self.update_buttons()
                self.check_clear()

    def shuffle_board(self):
        # グラフ上のランダムウォークによるシャッフル(必ず解ける)
        steps = 10
        for _ in range(steps):
            possible_moves = self.adj[self.empty]
            move_to = random.choice(possible_moves)
            self.click_tile(move_to, is_shuffling=True)
        if self.board == self.goal:
            self.shuffle_board()  # ゴール状態なら再シャッフル
        self.update_buttons()

    def update_buttons(self):
        for i in range(1, 5):
            val = self.board[i]
            # ボタンの外観を現在の状態(val)に合わせて更新
            self.buttons[i].config(text=str(val), 
                                   bg=self.bg[val], fg=self.fg[val],
                                   activebackground=self.abg[val],
                                   activeforeground=self.afg[val])

    def check_clear(self):
        if self.board == self.goal:
            messagebox.showinfo("数字パズル", "クリア!\n元の並びに戻りました。")

if __name__ == "__main__":
    root = tk.Tk()
    game = NumberPuzzle(root)
    root.mainloop()

実行するとこんな感じ。[スタート]ボタンでシャッフルします。

関連項目

“” への1件の返信

コメントを残す