我在 Codeforces 中遇到了一个交互问题。我想知道分级器或交互器(根据 Codeforces 的条款)是如何设计的。
假设我想为这个问题创建一个评分器:1. 猜数字。
我对上述问题的解决方案存储在1_Guess_the_Number.py文件中。这是一个正确的解决方案,并被 CF 分级机接受。
#!/usr/bin/env python3
l, r = 1, 1000000
while l != r:
mid = (l + r + 1) // 2
print(mid, flush=True)
response = input()
if response == "<":
r = mid - 1
else:
l = mid
print("!", l)
Run Code Online (Sandbox Code Playgroud)
我创建了以下grader.py文件:
#!/usr/bin/env python3
import sys
INP = 12
def interactor(n):
if n > INP:
return "<"
return ">="
while True:
guess = input()
if guess.startswith("!"):
print(int(guess.split()[1]) == INP, flush=True)
sys.exit()
print(interactor(int(guess)), flush=True)
Run Code Online (Sandbox Code Playgroud)
因此,当我运行时./1_Guess_the_Number.py | ./grader_1.py,我希望它能够正常工作。但在终端中,上述命令无限运行,仅输出以下内容:
<
Run Code Online (Sandbox Code Playgroud)
我不知道出了什么问题。另外,如果有人可以提供任何其他方式,这将非常有帮助。
@user2357112 的评论正确地描述了它不起作用的原因。当您的管道将第一个脚本的输出发送到评分器时,您不会将“grader.py”的响应发送到第一个脚本。
所以我们需要做的是建立双向沟通。
这是一种方法。在评分器中,调用要测试的脚本subprocess并通过管道与其进行通信。我在代码中添加了额外的解释。
1_Guess_the_Number.py和你的一样:
#!/usr/bin/env python3
l, r = 1, 1000000
while l != r:
mid = (l + r + 1) // 2
print(mid, flush=True)
response = input()
if response == "<":
r = mid - 1
else:
l = mid
print("!", l)
Run Code Online (Sandbox Code Playgroud)
grader.py将测试文件的名称作为输入并使用以下命令执行它subprocess.Popen:
# !/usr/bin/env python3
import sys
import subprocess
INP = 12
def interactor(n):
if n > INP:
return "<"
return ">="
def decodeBytes(message):
# Helperfunction to decode the message from stdin
# guess has the format b'12345\r\n'
# rstrip() removes the \r\n, then we decode it as ascii
return message.rstrip().decode('ascii')
if __name__ == '__main__':
print(f'The secret answer is: {INP}')
# get script name:
name = sys.argv[1]
print(f'calling script {name}')
# start script as a subprocess
p = subprocess.Popen(["python3", name], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
# create iterator to read subsequent guesses
stdout_iterator = iter(p.stdout.readline, b"")
# loop over all guesses
for msg_in in stdout_iterator:
#msg_in is a byte array, we need to decode it
guess = decodeBytes(msg_in)
print(f'got msg: {guess}')
if guess.startswith("!"):
final_answer = int(guess.split()[1])
print(f'The final answer is: {final_answer}')
if final_answer == INP:
print('Answer was correct!')
break
print('Answer is wrong!')
break
# we determine the message to send out
msg_out = interactor(int(guess))
print(f'send msg: {msg_out}')
# sending it to the scripts stdin.
p.stdin.write((msg_out + '\n').encode())
# we need to flush stdin, to make sure the message is not stuck in a buffer
p.stdin.flush()
Run Code Online (Sandbox Code Playgroud)
从命令行您可以通过以下方式调用评分器
python grader.py 1_Guess_the_Number.py
Run Code Online (Sandbox Code Playgroud)
打印输出是:
The secret answer is: 12
calling script 1_Guess_the_Number.py
got msg: 500001
send msg: <
got msg: 250001
send msg: <
got msg: 125001
send msg: <
got msg: 62501
send msg: <
got msg: 31251
send msg: <
got msg: 15626
send msg: <
got msg: 7813
send msg: <
got msg: 3907
send msg: <
got msg: 1954
send msg: <
got msg: 977
send msg: <
got msg: 489
send msg: <
got msg: 245
send msg: <
got msg: 123
send msg: <
got msg: 62
send msg: <
got msg: 31
send msg: <
got msg: 16
send msg: <
got msg: 8
send msg: >=
got msg: 12
send msg: >=
got msg: 14
send msg: <
got msg: 13
send msg: <
got msg: ! 12
The final answer is: 12
Answer was correct!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
330 次 |
| 最近记录: |