#!/usr/bin/env python3 # Run 'python3 testing_tool.py -h' for information on usage. import argparse import subprocess import sys import traceback parser = argparse.ArgumentParser(description=""" Testing tool for the Hangman problem You can compile and run your solution as follows. - Replace S with the hidden string you want to test. - You may have to replace 'python3' by just 'python'. - On Windows, you may have to to replace '/' by '\\'. C++: g++ solution.cpp python3 testing_tool.py -s S ./a.out Java: javac solution.java python3 testing_tool.py -s S java solution Python 3: python3 testing_tool.py -s S python3 ./solution.py The tool is provided as-is, and you should feel free to make whatever alterations or augmentations you like to it. The tool attempts to detect and report common errors, but it is not an exhaustive test. It is not guaranteed that a program that passes this testing tool will be accepted.""", formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('-f', dest='inputfile', metavar='inputfile', default=None, type=argparse.FileType('r'), help='custom input file containing the hidden string') parser.add_argument('-s', dest='x', metavar='S', help='use S as hidden string; this overwrites the -f flag') parser.add_argument('-q', action='store_true', dest='quiet', default=False, help='only output the number of queries required') parser.add_argument('program', nargs='+', help='your solution, as described above') args = parser.parse_args() def write(p, line): assert p.poll() is None, 'Program terminated early' if not args.quiet: print('Write: {}'.format(line), flush=True) p.stdin.write('{}\n'.format(line)) p.stdin.flush() def read(p): assert p.poll() is None, 'Program terminated early' line = p.stdout.readline().strip() assert line != '', 'Read empty line or closed output pipe' if not args.quiet: print('Read: %s' % line, flush=True) t, s = line.split() assert t in ['?', '!'], 'Query should start with ? or !' assert s.islower(), 'You should only print lowercase letters' if t == '?': assert len(set(s)) == len(s), 'In a ?-query you should print each char only once' return t, s if args.x is not None: x = args.x elif args.inputfile is not None: # Read the input file with args.inputfile as f: x = f.readline() else: x = 'banana' def evaluate(t, s): if t == '?': out = [] c = set(s) for i in range(len(x)): if x[i] in c: out.append(i+1) return str(len(out)) + ' ' + ' '.join(map(str, out)) if t == '!': if x == s: return 'correct' if x != s: return 'incorrect' with subprocess.Popen(" ".join(args.program), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) as p: try: queries = 0 while True: t, s = read(p) queries += 1 assert queries <= 7, 'Used too many queries' ans = evaluate(t, s) write(p, ans) if ans == 'correct': assert p.stdout.readline() == '', 'Printed extra data after finding solution' assert p.wait() == 0, 'Did not exit cleanly after finishing' break except: traceback.print_exc() p.kill() finally: sys.stdout.flush() sys.stderr.flush() if args.quiet: print(queries) else: print() print('Number of guesses:', queries) print('Exit code:', p.wait())