Home > Blockchain >  Move and update chess piece on chessboard without clicks Tkinter Python
Move and update chess piece on chessboard without clicks Tkinter Python

Time:06-10

I am trying to make a GUI for the Knight's Tour problem. I already have the solution of the problem in the form of a sorted dictionary. Now I just want the Knight's chess piece to follow the path shown by the saved dictionary and trace it in the GUI. No user input is required, apart from running the script.

# 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)]}

I also have a basic code implemented using Tkinter for the 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()

I am not able to update the position of the Knight chess piece with the for loop. The output in the GUI window is this:enter image description here

I want the result to be something like this:

enter image description here

Is it possible to do so?

TIA!

CodePudding user response:

You can use board.placepiece() to move the chess piece. Also it is better to use .after() instead of for loop in a tkinter application.

First add a function to GameBoard class to draw a line between cells:

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)

Then use .after() to call a function repeatedly instead of a for loop:

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()
  • Related