Advertisement
Guest User

Untitled

a guest
Mar 23rd, 2023
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.37 KB | None | 0 0
  1. # "Twisty Little Passages" local testing tool.
  2. #
  3. # Usage: `python3 local_testing_tool.py`
  4.  
  5. import sys
  6. import random
  7.  
  8. NUM_CASES = 100
  9. N = 100000
  10. K = 8000
  11. NEED_CORRECT = 90
  12.  
  13. class Error(Exception):
  14. pass
  15.  
  16. class WrongAnswer(Exception):
  17. pass
  18.  
  19. WRONG_NUM_TOKENS_ERROR = ("Wrong number of tokens: expected {}, found {}.".format)
  20. NOT_INTEGER_ERROR = "Not an integer: {}.".format
  21. INVALID_LINE_ERROR = "Couldn't read a valid line."
  22. ADDITIONAL_INPUT_ERROR = "Additional input after all cases finish: {}.".format
  23. OUT_OF_BOUNDS_ERROR = "Request out of bounds: {}.".format
  24. TOO_FEW_CORRECT_ERROR = "Too few correct answers: {}.".format
  25. INVALID_COMMAND_ERROR = "couldn't understand player command: {}.".format
  26. DID_NOT_GIVE_AN_ESTIMATE_ERROR = "Player did not give an estimate after K rounds."
  27.  
  28.  
  29. def ReadValues(line):
  30. t = line.split()
  31. return t
  32.  
  33. def ConvertToInt(token, min, max):
  34. try:
  35. v = int(token)
  36. except:
  37. raise Error(NOT_INTEGER_ERROR(token[:100]))
  38. if v < min or v > max:
  39. raise Error(OUT_OF_BOUNDS_ERROR(v))
  40. return v
  41.  
  42. def ConvertToAnyInt(token):
  43. try:
  44. v = int(token)
  45. except:
  46. raise Error(NOT_INTEGER_ERROR(token[:100]))
  47. return v
  48.  
  49. def Input():
  50. try:
  51. return input()
  52. except EOFError:
  53. raise
  54. except:
  55. raise Error(INVALID_LINE_ERROR)
  56.  
  57. def Output(line):
  58. try:
  59. print(line)
  60. sys.stdout.flush()
  61. except:
  62. try:
  63. sys.stdout.close()
  64. except:
  65. pass
  66.  
  67. def RunCases():
  68. Output("{}".format(NUM_CASES))
  69. correct = 0
  70. for case_number in range(NUM_CASES):
  71. Output("{} {}".format(N, K))
  72.  
  73. # Construct a graph in adj.
  74. adj = [[] for _ in range(N)]
  75. correct_total_edges = 0
  76. order = [i for i in range(N)]
  77. random.shuffle(order)
  78. for i in range(0, N, 2):
  79. v1 = order[i]
  80. v2 = order[i+1]
  81. adj[v1].append(v2)
  82. adj[v2].append(v1)
  83. correct_total_edges += 1
  84. add = random.randint(0, 4*N)
  85. add = random.randint(0, add)
  86. for j in range(add):
  87. v1 = random.randint(0,N-1)
  88. v2 = random.randint(0,N-1)
  89. if v1 != v2 and v2 not in adj[v1] and len(adj[v1])<N-2 and len(adj[v2])<N-2:
  90. adj[v1].append(v2)
  91. adj[v2].append(v1)
  92. correct_total_edges += 1
  93. complement = random.choice([False, True])
  94. if complement:
  95. correct_total_edges = (N*(N-1))//2 - correct_total_edges
  96.  
  97. # Play the game.
  98. where = random.randint(0,N-1)
  99. for move_number in range(K+1):
  100. # Output current room number (1-based) and number of adjacent passages.
  101. if complement:
  102. Output("{} {}".format(where+1, N-1-len(adj[where])))
  103. else:
  104. Output("{} {}".format(where+1, len(adj[where])))
  105.  
  106. # Get the user's move.
  107. try:
  108. move = ReadValues(Input())
  109. except EOFError:
  110. raise Error(INVALID_LINE_ERROR)
  111. except Error as error:
  112. raise error
  113. if len(move) == 0:
  114. raise Error(INVALID_LINE_ERROR)
  115.  
  116. if move[0] == "E":
  117. # The user provided an estimate.
  118. if len(move) != 2:
  119. raise Error(WRONG_NUM_TOKENS_ERROR(2,len(move)))
  120. estimate = ConvertToAnyInt(move[1])
  121. lo = (correct_total_edges * 2 + 2) // 3
  122. hi = (correct_total_edges * 4) // 3
  123. if lo <= estimate and estimate <= hi:
  124. print(f"Case #{case_number + 1}: Correct -- got {estimate}; exact answer is {correct_total_edges}.", file=sys.stderr)
  125. correct += 1
  126. else:
  127. print(f"Case #{case_number + 1}: Wrong -- got {estimate}; exact answer is {correct_total_edges}; acceptable range is [{lo}, {hi}].", file=sys.stderr)
  128. # Go to the next test case.
  129. break
  130. elif move_number == K:
  131. # The cave is now closed!
  132. raise Error(DID_NOT_GIVE_AN_ESTIMATE_ERROR)
  133. elif move[0] == "W":
  134. # The user took a random exit.
  135. if len(move) != 1:
  136. raise Error(WRONG_NUM_TOKENS_ERROR(1,len(move)))
  137. if complement:
  138. while True:
  139. next = random.randint(0,N-1)
  140. # NOTE: The check for (next != where) was not present at the
  141. # beginning of contest. This would, in rare occasions, introduce
  142. # self-loops. This bug was never present in the real judge.
  143. if next != where and next not in adj[where]:
  144. where = next
  145. break
  146. else:
  147. l = adj[where]
  148. where = l[random.randint(0,len(l)-1)]
  149. elif move[0] == "T":
  150. # The user teleported to a room.
  151. if len(move) != 2:
  152. raise Error(WRONG_NUM_TOKENS_ERROR(1,len(move)))
  153. where = ConvertToInt(move[1], 1, N)
  154. where -= 1
  155. else:
  156. raise Error(INVALID_COMMAND_ERROR(move[0][:1000]))
  157.  
  158. # Check there is no extraneous input from the user.
  159. try:
  160. extra_input = Input()
  161. raise Error(ADDITIONAL_INPUT_ERROR(extra_input[:100]))
  162. except EOFError:
  163. pass
  164.  
  165. # Finished.
  166. print(f"User got {correct} cases correct.", file=sys.stderr)
  167. if correct < NEED_CORRECT:
  168. raise WrongAnswer(TOO_FEW_CORRECT_ERROR(correct))
  169.  
  170. def main():
  171. if len(sys.argv) == 2 and int(sys.argv[1]) < 0:
  172. sys.exit(0)
  173. random.seed(12345)
  174. try:
  175. RunCases()
  176. except Error as error:
  177. print(error, file=sys.stderr)
  178. sys.exit(1)
  179. except WrongAnswer as error:
  180. print(error, file=sys.stderr)
  181. sys.exit(1)
  182.  
  183. if __name__ == "__main__":
  184. main()
  185.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement