簡體   English   中英

無需點擊即可在棋盤上移動和更新棋子 Tkinter Python

[英]Move and update chess piece on chessboard without clicks Tkinter Python

我正在嘗試為 Knight's Tour 問題制作一個 GUI。 我已經以排序字典的形式解決了這個問題。 現在我只希望騎士的棋子遵循保存的字典顯示的路徑並在 GUI 中跟蹤它。 除了運行腳本之外,不需要用戶輸入。

# a solution to the Knight's Tour problem with initial position (7,7) stored in a dictionary 
# with keys as the order of points to visit and values as the coordinates of the points.

board_path_dict = {0: [(7, 7)], 1: [(6, 5)], 2: [(5, 7)], 3: [(7, 6)], 4: [(6, 4)], 5: [(7, 2)], 6: [(6, 0)], 
7: [(4, 1)], 8: [(2, 0)], 9: [(0, 1)], 10: [(1, 3)], 11: [(0, 5)], 12: [(1, 7)], 13: [(3, 6)], 14: [(1, 5)], 
15: [(0, 7)], 16: [(2, 6)], 17: [(4, 7)], 18: [(6, 6)], 19: [(7, 4)], 20: [(6, 2)], 21: [(7, 0)], 
22: [(5, 1)], 23: [(3, 0)], 24: [(1, 1)], 25: [(0, 3)], 26: [(2, 2)], 27: [(1, 0)], 28: [(0, 2)], 
29: [(1, 4)], 30: [(0, 6)], 31: [(2, 7)], 32: [(4, 6)], 33: [(6, 7)], 34: [(7, 5)], 35: [(5, 6)], 
36: [(3, 7)], 37: [(4, 5)], 38: [(5, 3)], 39: [(3, 4)], 40: [(5, 5)], 41: [(6, 3)], 42: [(7, 1)], 
43: [(5, 0)], 44: [(4, 2)], 45: [(6, 1)], 46: [(7, 3)], 47: [(5, 4)], 48: [(3, 5)], 49: [(4, 3)], 
50: [(3, 1)], 51: [(2, 3)], 52: [(4, 4)], 53: [(5, 2)], 54: [(4, 0)], 55: [(3, 2)], 56: [(2, 4)], 
57: [(1, 6)], 58: [(0, 4)], 59: [(2, 5)], 60: [(3, 3)], 61: [(2, 1)], 62: [(0, 0)], 63: [(1, 2)]}

我還有一個使用Tkinter為 GUI 實現的基本代碼。

import tkinter as tk
class GameBoard(tk.Frame):
    def __init__(self, parent, rows=8, columns=8, size=64, color1="#a7ab90", color2="#0e140c"):
        '''size is the size of a square, in pixels'''
        self.rows = rows
        self.columns = columns
        self.size = size
        self.color1 = color1
        self.color2 = color2
        self.pieces = {}
        canvas_width = columns * size
        canvas_height = rows * size
        tk.Frame.__init__(self, parent)
        self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0,
                                width=canvas_width, height=canvas_height, background="khaki")
        self.canvas.pack(side="top", fill="both", expand=True, padx=2, pady=2)

        # this binding will cause a refresh if the user interactively
        # changes the window size
        self.canvas.bind("<Configure>", self.refresh)

    def addpiece(self, name, image, row=0, column=0):
        '''Add a piece to the playing board'''
        self.canvas.create_image(0,0, image=image, tags=(name, "piece"), anchor="c")
        self.placepiece(name, row, column)

    def placepiece(self, name, row, column):
        '''Place a piece at the given row/column'''
        self.pieces[name] = (row, column)
        x0 = (column * self.size) + int(self.size/2)
        y0 = (row * self.size) + int(self.size/2)
        self.canvas.coords(name, x0, y0)

    def refresh(self, event):
        '''Redraw the board, possibly in response to window being resized'''
        xsize = int((event.width-1) / self.columns)
        ysize = int((event.height-1) / self.rows)
        self.size = min(xsize, ysize)
        self.canvas.delete("square")
        color = self.color2
        for row in range(self.rows):
            color = self.color1 if color == self.color2 else self.color2
            for col in range(self.columns):
                x1 = (col * self.size)
                y1 = (row * self.size)
                x2 = x1 + self.size
                y2 = y1 + self.size
                self.canvas.create_rectangle(x1, y1, x2, y2, outline="black", fill=color, tags="square")
                color = self.color1 if color == self.color2 else self.color2
        for name in self.pieces:
            self.placepiece(name, self.pieces[name][0], self.pieces[name][1])
        self.canvas.tag_raise("piece")
        self.canvas.tag_lower("square")
        
if __name__ == "__main__":
    root = tk.Tk()
    root.title("Knight's Tour Problem")
    board = GameBoard(root)
    board.pack(side="top", fill="both", expand="true", padx=10, pady=10)
    # knight = tk.PhotoImage(file = r"C:\Gfg\knight.png")
    knight = tk.PhotoImage(file = "chess_knight.png")
    board.addpiece("knight", knight, 7,7) # initial position of Knight is (7,7) here, but I plan to change that manually as the solution changes
    for i in range(len(board_path_dict)-1):
        cell_1 = board_path_dict[i][0]
        cell_2 = board_path_dict[i+1][0]
        board.canvas.create_line(cell_1[0], cell_1[1], cell_2[0], cell_2[1], width=4.3, fill='red')
        board.canvas.update()
    root.mainloop()

我無法使用 for 循環更新騎士棋子的位置。 GUI 窗口中的輸出是這樣的: 在此處輸入圖像描述

我希望結果是這樣的:

在此處輸入圖像描述

有可能這樣做嗎?

蒂亞!

您可以使用board.placepiece()移動棋子。 此外,最好在 tkinter 應用程序中使用.after()而不是 for 循環。

首先在GameBoard類中添加一個函數來在單元格之間畫一條線:

class GameBoard(tk.Frame):
    ...

    def draw_line(self, x1, y1, x2, y2, width, fill):
        x1 *= self.size
        y1 *= self.size
        x2 *= self.size
        y2 *= self.size
        half = self.size / 2
        self.canvas.create_line(x1+half, y1+half, x2+half, y2+half, width=width, fill=fill)

然后使用.after()重復調用函數而不是 for 循環:

if __name__ == '__main__':
    ...

    board.addpiece("knight", knight, 7,7) # initial position of Knight is (7,7) here, but I plan to change that manually as the solution changes

    def move_piece(i=0):
        if i < len(board_path_dict)-1:
            cell_1 = board_path_dict[i][0]
            cell_2 = board_path_dict[i+1][0]
            # draw the line
            board.draw_line(cell_1[0], cell_1[1], cell_2[0], cell_2[1], width=4.3, fill='red')
            # move the chess piece
            board.placepiece("knight", cell_2[1], cell_2[0])
            board.after(500, move_piece, i+1)

    # start the chess piece moving
    board.after(500, move_piece)
    root.mainloop()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM