Python打字游戏开发:实现超时自动退出的倒计时功能
无线程实现打字游戏超时终止方案
问题描述
我正在为学校项目开发一款简易打字游戏,尝试用threading实现倒计时与输入同步运行,希望时间结束时自动终止游戏,但当前只能在按下回车时停止输入,超时终止功能未生效。现寻求无需threading的替代方案。
原代码
import time import datetime import random import threading library = ["Hello","World"] #There will be some text here alphabet = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,":":0} alphabet2 = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,"!":0,":":0} def countdown1(h, m, s): total_seconds = h * 3600 + m * 60 + s while total_seconds > 0: # Timer represents time left on countdown timer = datetime.timedelta(seconds = total_seconds) print(timer, end="\r") # Delays the program one second time.sleep(1) # Reduces total time by one second total_seconds -= 1 print("Start now!") done = False def countdown2(): c = 0 if done: print("You used "+str(c)+" seconds to type!! Good Job!!") while not done: time.sleep(1) c += 1 count = 0 print('You have 1 minute to type the following text') c = random.randint(0,len(library)-1) print(library[c]) print('Type after countdown, hit return after finishing or when the time is up') countdown1(0,0,3) threading.Thread(target=countdown2,daemon = True).start() word = input().replace(" ", "") done = True passage = library[c].replace(" ", "") total = len(passage) for i in passage: if i in alphabet2: alphabet2[i] += 1 letter1 = [] letter2 = [] for i in word: if i in alphabet: alphabet[i] += 1 for key in alphabet.values(): letter1.append(int(key)) for key in alphabet2.values(): letter2.append(int(key)) for j in range(57): count += min(letter1[j],letter2[j]) print('Congrats! You got '+str(count)+'/'+str(total)+' right!')
替代方案(无线程)
可以通过第三方库或平台原生模块实现带超时的输入,无需线程即可在超时后自动终止输入。
跨平台兼容方案(推荐)
使用inputimeout库(需先安装:pip install inputimeout),该库封装了不同平台的实现,调用简单:
import time import datetime import random from inputimeout import inputimeout, TimeoutOccurred library = ["Hello","World"] # 可在此添加更多文本 alphabet = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,":":0} alphabet2 = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,"!":0,":":0} def countdown1(h, m, s): total_seconds = h * 3600 + m * 60 + s while total_seconds > 0: timer = datetime.timedelta(seconds=total_seconds) print(timer, end="\r") time.sleep(1) total_seconds -= 1 print("Start now!") count = 0 print('你有1分钟时间输入下面的文本') c = random.randint(0, len(library)-1) print(library[c]) print('倒计时结束后开始输入,完成后按回车,超时会自动结束') countdown1(0, 0, 3) # 设置超时时间为60秒(1分钟) try: word = inputimeout(prompt='', timeout=60).replace(" ", "") except TimeoutOccurred: print('\n时间到!') word = '' passage = library[c].replace(" ", "") total = len(passage) for i in passage: if i in alphabet2: alphabet2[i] += 1 letter1 = [] letter2 = [] for i in word: if i in alphabet: alphabet[i] += 1 for key in alphabet.values(): letter1.append(int(key)) for key in alphabet2.values(): letter2.append(int(key)) for j in range(57): count += min(letter1[j], letter2[j]) print(f'恭喜!你答对了 {count}/{total} 个字符!')
原生实现(无需额外库)
若不想安装第三方库,可根据平台分别处理:
Windows平台(使用msvcrt)
import time import datetime import random import msvcrt library = ["Hello","World"] alphabet = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,":":0} alphabet2 = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,"!":0,":":0} def countdown1(h, m, s): total_seconds = h * 3600 + m * 60 + s while total_seconds > 0: timer = datetime.timedelta(seconds=total_seconds) print(timer, end="\r") time.sleep(1) total_seconds -= 1 print("Start now!") count = 0 print('你有1分钟时间输入下面的文本') c = random.randint(0, len(library)-1) print(library[c]) print('倒计时结束后开始输入,完成后按回车,超时会自动结束') countdown1(0, 0, 3) start_time = time.time() word = '' timeout = 60 # 1分钟超时 while time.time() - start_time < timeout: if msvcrt.kbhit(): char = msvcrt.getche().decode('utf-8') if char == '\r': # 回车键 break word += char else: print('\n时间到!') word = word.replace(" ", "") passage = library[c].replace(" ", "") total = len(passage) for i in passage: if i in alphabet2: alphabet2[i] += 1 letter1 = [] letter2 = [] for i in word: if i in alphabet: alphabet[i] += 1 for key in alphabet.values(): letter1.append(int(key)) for key in alphabet2.values(): letter2.append(int(key)) for j in range(57): count += min(letter1[j], letter2[j]) print(f'恭喜!你答对了 {count}/{total} 个字符!')
Unix/Linux平台(使用select)
import time import datetime import random import sys import select library = ["Hello","World"] alphabet = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,":":0} alphabet2 = {'a':0,'A':0,'b':0,'B':0,'c':0,'C':0,'d':0,'D':0,'e':0,'E':0,'f':0,'F':0,'g':0,'G':0,'h':0,'H':0,'i':0,'I':0,'J':0,'j':0,'k':0,'K':0,'l':0,'L':0,'m':0,'M':0,'n':0,'N':0,'o':0,'O':0,'p':0,'P':0,'q':0,'Q':0,'r':0,'R':0,'s':0,'S':0,'t':0,'T':0,'u':0,'U':0,'v':0,'V':0,'w':0,'W':0,'x':0,'X':0,'y':0,'Y':0,'z':0,'Z':0,',':0,'.':0,'-':0,"'":0,"!":0,":":0} def countdown1(h, m, s): total_seconds = h * 3600 + m * 60 + s while total_seconds > 0: timer = datetime.timedelta(seconds=total_seconds) print(timer, end="\r") time.sleep(1) total_seconds -= 1 print("Start now!") count = 0 print('你有1分钟时间输入下面的文本') c = random.randint(0, len(library)-1) print(library[c]) print('倒计时结束后开始输入,完成后按回车,超时会自动结束') countdown1(0, 0, 3) timeout = 60 # 1分钟超时 print('开始输入:', end='', flush=True) ready, _, _ = select.select([sys.stdin], [], [], timeout) if ready: word = sys.stdin.readline().strip().replace(" ", "") else: print('\n时间到!') word = '' passage = library[c].replace(" ", "") total = len(passage) for i in passage: if i in alphabet2: alphabet2[i] += 1 letter1 = [] letter2 = [] for i in word: if i in alphabet: alphabet[i] += 1 for key in alphabet.values(): letter1.append(int(key)) for key in alphabet2.values(): letter2.append(int(key)) for j in range(57): count += min(letter1[j], letter2[j]) print(f'恭喜!你答对了 {count}/{total} 个字符!')
方案说明
- 跨平台方案使用
inputimeout,无需关心平台差异,代码简洁,适合快速开发。 - 原生方案调用系统模块,无额外依赖,适合环境受限的场景。
- 两种方案均能在超时后自动终止输入,替代原线程实现的功能,同时避免线程同步问题。
内容的提问来源于stack exchange,提问作者Shujin Liu
相关产品推荐
相关产品推荐

