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")
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:
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")