#!/usr/bin/env python3 """ Local testing tool for Guess the Number Disclaimer: This is NOT the same code used to test your solution when it is submitted. This tool is provided as-is. Its purpose is to help with debugging the interactive problem and it has no ambitions to extensively test all possibilities that are allowed by the problem statement. While the tool tries to yield the same results as the real judging system, this is not guaranteed and the result may differ if the tested program does not use the correct formatting or exhibits other incorrect behavior. The tool also *does not* enforce time and memory limits that are applied to submitted solutions. Feel free to make whatever alterations or augmentations you like. The behavior is controlled by an input data file. The only line of the file contains an integer X, the number to guess. Here is an example file: 123456 The testing tool is run like this on Windows: python guessthenumber_testing_tool.py or on Linux: python3 guessthenumber_testing_tool.py where `arguments` are optional arguments to the program to run. The following show examples for different languages: python3 guessthenumber_testing_tool.py 1.in ./myprogram python3 guessthenumber_testing_tool.py 1.in java -cp . MyProgram python3 guessthenumber_testing_tool.py 1.in python3 myprogram.py The tool logs the complete interaction. If you do not want that, pass `--quiet` (before the data file name). Templated from the local testing tool of ICPC EC-final 2025. """ from __future__ import annotations import argparse import random import subprocess import sys from typing import List, Tuple verbose = True process = None run_id = 0 class WrongAnswer(RuntimeError): pass class EndOfFile(RuntimeError): pass def vprint(*args, **kwargs) -> None: if verbose: print("< ", end="") print(*args, **kwargs) sys.stdout.flush() print(*args, file=process.stdin, flush=True, **kwargs) def vreadline(optional: bool = False) -> str: line = process.stdout.readline() if verbose and line: print(">", line.rstrip("\n")) if not line and not optional: raise EndOfFile() return line def read_case(path: str) -> int: with open(path, "r", encoding="utf-8") as f: tokens = f.read().strip().split() if not tokens: raise ValueError("Input file is empty.") X = int(tokens[0]) return X def start_process(program: List[str], phase: str, bufsize: int | None = None) -> subprocess.Popen: global run_id, process run_id += 1 if verbose: print(f"[run {run_id}] {phase}: {' '.join(program)}") kwargs = { "shell": True, "stdin": subprocess.PIPE, "stdout": subprocess.PIPE, "text": True, } if bufsize is not None: kwargs["bufsize"] = bufsize process = subprocess.Popen(" ".join(program), **kwargs) if process.stdin is None or process.stdout is None: raise RuntimeError("Failed to open pipes.") return process def run_guess(program: List[str], X: int): start_process(program, "Guessing", bufsize=1) pass_data = [] counter = 25 while True: read_str = vreadline().strip() if read_str != "": read_str_split = read_str.split() if len(read_str_split) == 1: guessed_X = int(read_str) if guessed_X <= X: vprint(">=") else: vprint("<") elif len(read_str_split) == 2 and read_str_split[0] == "!": guessed_X = int(read_str_split[1]) if guessed_X != X: raise WrongAnswer(f"Guessed X {guessed_X} != actual X {X}.") break else: raise WrongAnswer(f"Invalid query: {read_str}") counter -= 1 if counter == 0: raise WrongAnswer("Too many guesses.") if process.stdin: process.stdin.close() process.wait() if process.returncode != 0: raise WrongAnswer(f"Guessing phase exit code {process.returncode}.") def main() -> int: parser = argparse.ArgumentParser( usage="%(prog)s [--quiet] data.in program [args...]" ) parser.add_argument( "--quiet", "-q", action="store_true", help="Do not show interactions" ) parser.add_argument("data", help="Input file that controls the behavior of the tool") parser.add_argument("program", nargs=argparse.REMAINDER, help="Program to run") args = parser.parse_args() global verbose verbose = not args.quiet if not args.program: parser.error("Must specify program to run") X = read_case(args.data) run_guess(args.program, X) print(f"Program finished correctly.", file=sys.stderr) return 0 if __name__ == "__main__": try: sys.exit(main()) except WrongAnswer as exc: print(f"Error: {exc}", file=sys.stderr) sys.exit(1)