i have this chess code. i am studying moves, different chess openings and wondering if i can get the program to play out the moves for me of different openings. I'm not sure the best way to do this, but the most  strightforward seems to be maybe entering a list of moves like this "1.c4 e5 2.e4 f6 3.d4 g5 4.h3 Bb4+ 5.Nc3 Bd6 6.c5 h6 7.cxd6 cxd6 8.Qh5+ Ke7 9.Nd5+ Ke6 10.Bc4 Ne7 11.Nc7#" into the enter move list and have a function that updates the board to each move with a second delay between moves. the program currently accepts one move at a time.

import tkinter as tk
from PIL import Image, ImageTk
import chess
import requests
import re
import threading


def draw_board(board, selected_square=None):
    global board_images
    print("enter draw_board function")
    board_images = {}
    canvas.delete("all")
    canvas_width = 900
    canvas_height = 500
    canvas.config(width=canvas_width, height=canvas_height)
    start_x = 2
    start_y = 2

    for square in chess.SQUARES:
        rank = chess.square_rank(square)
        file = chess.square_file(square)
        x0 = start_x + file * square_size
        y0 = start_y + (7 - rank) * square_size
        if (rank + file) % 2 == 0:
            square_color = "white"
        else:
            square_color = "light gray"
        canvas.create_rectangle(x0, y0, x0 + square_size, y0 + square_size, fill=square_color)

        # Check if the square is selected and draw a highlight
        if square == selected_square:
            canvas.create_rectangle(x0, y0, x0 + square_size, y0 + square_size, fill="yellow")

        piece = board.piece_at(square)
        if piece:
            image = Image.open(PIECE_IMAGES[str(piece)]).resize((square_size, square_size), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(image)
            board_images[square] = photo
            canvas.create_image(x0 + square_size // 2, y0 + square_size // 2, image=photo)
    print("exit draw_board function")


def process_move(move_str, game_board):
    global san_moves, san_number, total_moves

    try:
        # Try parsing move_str as a SAN move
        san_move = game_board.parse_san(move_str)
        if san_move in game_board.legal_moves:
            game_board.push(san_move)
            draw_board(game_board)
            if total_moves == "":
                total_moves = 1
            if total_moves % 2 == 1:
                san_moves += f"{san_number}.{move_str} "
                total_moves += 1
            else:
                san_moves += f"{move_str} "
                total_moves += 1
                san_number += 1
            print("SAN Moves:", san_moves)
            draw_board(game_board)

    except ValueError:
        # If parsing as SAN fails, try parsing move_str as FEN
        try:
            game_board.set_fen(move_str)
            draw_board(game_board)
            print("FEN Set:", move_str)
        except ValueError:
            print(f"Invalid move: {move_str}")


def on_enter(event):
    # Check if the cursor is in the input area
    if event.widget == input_area:
        move_str = move_entry.get()
        submit_message()
    elif event.widget == move_entry:
        submit_move() 

def submit_move():
    global move_entry
    move = move_entry.get()
    print(move)
    process_move(move, game_board)
    move_entry.delete(0, tk.END)  # Clear the entry after the move


def on_square_click(event):
    global selected_square, is_second_click, user_color
    if 1 == 1:
   # if (game_board.turn == chess.WHITE and user_color == "white") or (game_board.turn == chess.BLACK and user_color == "black"):
        print("enter on_square_click function")
    
        file = (event.x + 20) // square_size
        rank = 7 - (event.y + 10) // square_size
        square = chess.square(file, rank)

        if not is_second_click:
            # First click: Select the piece
            move_entry.delete(0, tk.END)
            move_entry.insert(tk.END, chess.square_name(square))
            selected_square = square
            is_second_click = True
            draw_board(game_board, selected_square)
        else:
            # Second click: Generate and process the move
            move = chess.Move(selected_square, square)
            try:
                if move in game_board.legal_moves:
                    # Process the move and update the board
                    process_move(move.uci(), game_board)
                    is_second_click = False
                else:
                    result_label.config(text="Illegal move")
                    draw_board(game_board, selected_square)
                    is_second_click = False
            except ValueError:
                result_label.config(text="Invalid move")
                is_second_click = False
        print("exit on_square_click function")

def extract_moves_from_message(message):
    # Split the message into words
    words = message.split()
    print(f"line 135: {words}")
    # Initialize an empty list to store words with numbers
    words_with_numbers = []
    special_characters_pattern = re.compile(r'[^a-zA-Z0-9]')
    # Iterate over the words and check if they contain a digit
    for word in words:
        # Check if the word contains any digit
        word = re.sub(special_characters_pattern, '', word)
        if any(char.isdigit() for char in word):
            word = word.replace('.', '')
            while word and word[0].isdigit():
                word = word[1:]

            words_with_numbers.append(word)
            print(f"line 145: {word}")
    # Combine the list of words into a single string
    words_with_numbers_str = ' '.join(words_with_numbers)

    print("Words with numbers:", words_with_numbers_str)
    return words_with_numbers_str


def print_history():
    print("\n=== Updated History ===")
    for entry in history:
        print(f"{entry['role']}: {entry['content']}")
    print("=======================")


# Global Variables
user_color = None
history = []
san_moves = ""  # Initialize an empty string to store SAN moves
san_number = 1  # Initialize real number of moves
total_moves = 1

api_url = 'http://127.0.0.1:5000/v1/chat/completions'
headers = {"Content-Type": "application/json"}
initial_fen = chess.STARTING_FEN
game_board = chess.Board(initial_fen)
board = chess.Board()
valid_moves = game_board.legal_moves
board_images = {}
square_size = 60  # Size of a square in the board
selected_square = None
is_second_click = False
move = None

# Create a dictionary to map piece symbols to image filenames
PIECE_IMAGES = {
    "P": "images/Wp.png",
    "p": "images/bp.png",
    "R": "images/WR.png",
    "r": "images/bR.png",
    "N": "images/WN.png",
    "n": "images/bN.png",
    "B": "images/WB.png",
    "b": "images/bB.png",
    "Q": "images/WQ.png",
    "q": "images/bQ.png",
    "K": "images/WK.png",
    "k": "images/bK.png"
}

# Tkinter Window
window = tk.Tk()
window.title("Chess")

# Tkinter Components
canvas = tk.Canvas(window)
canvas.pack()
draw_board(game_board)
canvas.bind("<Button-1>", lambda event: on_square_click(event))
result_label = tk.Label(window)
result_label.place(x=7, y=495)

move_entry = tk.Entry(window)
move_entry.place(x=7, y=520)
move_entry.bind("<Return>", on_enter)

chat_window = tk.Text(window, height=20, width=45, wrap=tk.WORD)
chat_window.place(x=515, y=20)

input_area = tk.Text(window, height=5, width=45, wrap=tk.WORD)
input_area.place(x=515, y=400)
input_area.bind("<Return>", on_enter)

submit_btn = tk.Button(window, text="Player Move", command=submit_move)
submit_btn.place(x=185, y=518)
submit_btn = tk.Button(window, text="Send", command=submit_message)
submit_btn.pack(side=tk.RIGHT, padx=10, pady=10)

clear_history_btn = tk.Button(window, text="Clear History", command=clear_history)
clear_history_btn.place(x=300, y=518)

llm_move_btn = tk.Button(window, text="AI Turn", command=llm_move)
llm_move_btn.place(x=400, y=518)

white_button = tk.Button(window, text="Choose White", command=choose_white)
white_button.place(x=185, y=200)
black_button = tk.Button(window, text="Choose Black", command=choose_black)
black_button.place(x=185, y=240)


window.mainloop()