Search code examples
pythoninput

how to run another code line with input function


I made a tictactoe game and added a time limit in the play turn. My problem is how to make the remaining time visible to the player. I don't know how to run different code line like a text displaying the remaining time with input function at the same time.

This is my current code: (the function is part of class)

from inputimeout import inputimeout, TimeoutOccurred

def play_turn(self):
    while True:
        try:
            choice = int(inputimeout(prompt=f"{self.players[self.current_player].name}, choose a move: ", timeout=5))
            if 1 <= int(choice) <= 9 and self.board.update_board(choice, self.players[self.current_player].symbol):
                break
            else:
                print("Invalid move,try again")
        except TimeoutOccurred:
            print("Timed out!!")
            time.sleep(2)
            return
        except ValueError:
            print("Please enter a number between 1 and 9")

Solution

  • You can use python threads to do that. You can use this 2 functions (countdownTimer and getUserInputTimeout) to implement a threat with a input.

    For example:

    import threading
    import time
    from inputimeout import inputimeout, TimeoutOccurred
    
    def countdownTimer(timeout, timer_event):
        for i in range(timeout, 0, -1):
            if timer_event.is_set():
                break  # Exit the loop if the timer event is set
            time.sleep(1)
    
    def getUserInputTimeout(prompt, timeout):
        # Create an event to signal the timer thread to stop
        timer_event = threading.Event()
    
        # Start the countdown timer in a separate thread
        timer_thread = threading.Thread(target=countdownTimer, args=(timeout, timer_event))
        timer_thread.daemon = True  # Set the timer thread as a daemon thread
        timer_thread.start()
    
        try:
            # Loop to wait for user input until timeout or input received
            start_time = time.time()
            while True:
                remaining_time = timeout - int(time.time() - start_time)
                if remaining_time <= 0:
                    raise TimeoutOccurred
                print(f"\rTime left: {remaining_time} seconds: ", end='', flush=True)
                try:
                    choice = inputimeout(prompt='', timeout=1)
                    return choice
                except TimeoutOccurred:
                    pass
        except TimeoutOccurred:
            print("\nTimeout. No input received.")
        finally:
            timer_event.set()
            timer_thread.join()
    
    
    timeout_duration = 5
    
    user_input = getUserInputTimeout(prompt="Answer: ", timeout=timeout_duration)
    if user_input is not None:
        print(f"\nResponse: {user_input}")
    

    Execution:

    enter image description here

    For our code you can implement this way:

    import threading
    import time
    from inputimeout import inputimeout, TimeoutOccurred
    
    def countdownTimer(timeout, timer_event):
        for i in range(timeout, 0, -1):
            if timer_event.is_set():
                break  # Exit the loop if the timer event is set
            time.sleep(1)
    
    def getUserInputTimeout(prompt, timeout):
        # Create an event to signal the timer thread to stop
        timer_event = threading.Event()
    
        # Start the countdown timer in a separate thread
        timer_thread = threading.Thread(target=countdownTimer, args=(timeout, timer_event))
        timer_thread.daemon = True  # Set the timer thread as a daemon thread
        timer_thread.start()
    
        try:
            # Loop to wait for user input until timeout or input received
            start_time = time.time()
            while True:
                remaining_time = timeout - int(time.time() - start_time)
                if remaining_time <= 0:
                    raise TimeoutOccurred
                print(f"\rTime left: {remaining_time} seconds: ", end='', flush=True)
                try:
                    choice = inputimeout(prompt='', timeout=1)
                    return choice
                except TimeoutOccurred:
                    pass
        except TimeoutOccurred:
            print("\nTimeout. No input received.")
        finally:
            timer_event.set()
            timer_thread.join()
    
    
    def play_turn(self):
        while True:
            try:
                choice = int(getUserInputTimeout(prompt=f"{self.players[self.current_player].name}, choose a move: ", timeout=5))
                if 1 <= int(choice) <= 9 and self.board.update_board(choice, self.players[self.current_player].symbol):
                    break
                else:
                    print("Invalid move,try again")
            except TimeoutOccurred:
                print("Timed out!!")
                time.sleep(2)
                return
            except ValueError:
                print("Please enter a number between 1 and 9")