一次性打印多行输入后跟字符串,无需等待“Enter”提示
我需要写一个简单的Python程序,它可以在终端的第一行和第二行显示用户输入的内容,然后在第四行显示一个输出字符串,这个输出字符串会在两个输入都输入完后更新。当用户输入第一个内容时,光标会直接跳到第二个输入,下面的所有文本都要能看得见。一旦输入了第二个内容,输出字符串就会更新,而不是在新的一行打印。它的样子大概是这样的:
现在输入的内容是在游戏状态打印后调用的,但作业要求它们和游戏状态同时提示,并且要在各自的行上输入(第一个输入在它的行上,第二个输入在下一行)。
输入函数看起来是这样的。我还没有处理错误信息的部分,所以现在只是简单打印:
def origin_input():
origin = input('Select the source flask: ')
while not origin.isdigit():
print('Invalid input.')
origin = input('Select the source flask: ')
origin = int(origin)
if origin > FLASK_COUNT or origin < 1:
print('Invalid input')
return origin_input()
return origin
def target_input(origin, flasks):
target = input('Select the target flask: ')
while not target.isdigit():
print('Invalid input.')
target = input('Select the target flask: ')
target = int(target)
if target > FLASK_COUNT or target < 1:
print('Invalid input: Input out of range.')
return target_input(origin, flasks)
if target == origin:
print('Target cannot be the same as the source.')
return target_input(origin, flasks)
if flasks[target - 1].sealed: # accounts for 0 index
print('Cannot pour into a sealed flask.')
return target_input(origin, flasks)
if flasks[target - 1].is_full():
print('Target flask is full.')
return target_input(origin, flasks)
return target
输出字符串生成器是这样的。尽管在最后用了print(out_string, end='\r', flush=True)
,它还是在新的一行打印,所以我还在想办法让它正常工作:
def get_flask_str(flasks):
print('\n')
flask_list = []
# generate flask strings
for i, flask in enumerate(flasks):
chem_str = '+--+' + f'\n {i + 1} '
for chem in flask.chemicals[::-1]: # go backwards b/c the top is first in the list
chem_str = f'|{chem}|\n' + chem_str
if flask.sealed:
chem_str = '+--+\n' + chem_str
continue
elif len(flask.chemicals) <= MAX_CHEM: # only if flask is not completely full
diff = MAX_CHEM - len(flask.chemicals) + 1 # account for extra space
while diff > 0:
chem_str = '| |\n' + chem_str
diff -= 1
flask_list.append(chem_str)
# concat multiline strings:
lines_dict = {}
for flask_string in flask_list:
lines = flask_string.split('\n')
for i, line in enumerate(lines):
if i not in lines_dict:
lines_dict[i] = [line]
else:
lines_dict[i].append(line)
out_list = []
for i in lines_dict:
line = lines_dict[i]
out_list.append(' '.join(line))
out_string = ''
for string in out_list[::-1]: # flip right-side up
out_string = string + f'\n{out_string}'
print(out_string, end='\r', flush=True)
这是在主函数中调用这些函数的方式:
gameover = False
while not gameover: # no gameover clause for now
get_flask_str(flasks)
origin = origin_input()
target = target_input(origin, flasks)
oflask = flasks[origin - 1]
tflask = flasks[target - 1]
oflask.pour(tflask)
if tflask.can_seal():
print('Sealed target flask') # temporary line
这里是当前的输出样本:
我尝试过使用没有任何参数的单个输入命令,但显然这不行。我不太确定如何解决Python在输入完成之前就等待输入的问题。
1 个回答
这是我决定采用的解决方案:在现实情况下,更好的方法是使用像tkinter这样的图形用户界面库,但这个项目要求输出必须在终端中进行。
通过使用ANSI转义字符,可以利用os
模块来控制光标的位置。
在程序的开头,先在终端中初始化ANSI转义字符:
os.system("")
你还可以定义一个包含各种ANSI转义字符的字典:
ANSI = {
"RED": "\033[31m",
"GREEN": "\033[32m",
"BLUE": "\033[34m",
"HRED": "\033[41m",
"HGREEN": "\033[42m",
"HBLUE": "\033[44m",
"UNDERLINE": "\033[4m",
"RESET": "\033[0m",
"CLEARLINE": "\033[0K"
}
然后,定义一些函数来清屏、在特定的x和y位置打印内容,以及将光标移动到特定的x和y位置:
def cl():
if os.name == "nt": # windows
os.system("cls")
else: # unix systems
os.system("clear")
def loc_print(x, y, text):
print (f"\033[{y};{x}H{text}")
def loc_cursor(x, y):
print(f"\033[{y};{x}H", end='')
在我的情况下,这三个功能足以满足我在终端中的需求。请原谅我糟糕的代码:
gameover = False
err_msg = ''
while not gameover:
cl()
game_state = get_flask_str(flasks)
loc_print(0, 0, 'Magical Flask Game')
loc_print(0, 3, 'Select source Flask: ')
loc_print(0, 4, 'Select target Flask: ')
loc_print(0, 5, err_msg)
loc_print(0, 6, game_state)
loc_cursor(22, 3)
origin = input()
err_msg = origin_valid(origin)
if err_msg != '':
continue
origin = int(origin)
cl()
loc_print(0, 0, 'Magical Flask Game')
loc_print(0, 3, f'Select source Flask: {origin}')
loc_print(0, 4, 'Select target Flask: ')
loc_print(0, 5, '')
loc_print(0, 6, game_state)
loc_cursor(22, 4)
target = input()
err_msg = target_valid(target, origin, flasks)
while err_msg != '':
cl()
loc_print(0, 0, 'Magical Flask Game')
loc_print(0, 3, f'Select source Flask: {origin}')
loc_print(0, 4, 'Select target Flask: ')
loc_print(0, 5, err_msg)
loc_print(0, 6, game_state)
loc_cursor(22, 4)
target = input()
err_msg = target_valid(target, origin, flasks)
target = int(target)
oflask = flasks[origin - 1]
tflask = flasks[target - 1]
oflask.pour(tflask)
if tflask.can_seal():
err_msg = 'Sealed target flask'
if check_win(flasks):
cl()
game_state = get_flask_str(flasks)
loc_print(0, 0, 'Magical Flask Game')
loc_print(0, 3, f'Select source Flask: {origin}')
loc_print(0, 4, f'Select target Flask: {target}')
loc_print(0, 5, '')
loc_print(0, 6, game_state)
loc_print(0, 13, 'You Win')
gameover = True
The loc_cursor(x, y)
函数可以改变光标的位置,以及在这个位置上写入的内容。虽然这段代码确实需要一些整理,但它正好实现了我想要的效果。