def prepare_problem(problem: onlinejudge.type.Problem, *, contest: Optional[onlinejudge.type.Contest] = None, config: Dict[str, Any], session: requests.Session) -> None: table = config.get('templates') if table is None: table = { 'main.cpp': 'main.cpp', 'main.py': 'main.py', 'generate.py': 'generate.py', } logger.info('setting "templates" is not found in your config; use %s', repr(table)) dir = get_directory(problem=problem, contest=contest, config=config) logger.info('use directory: %s', str(dir)) dir.parent.mkdir(parents=True, exist_ok=True) with chdir(dir): url = problem.get_url() html = network.download_html(url, session=session) sample_cases = network.download_sample_cases(url, session=session) # analyze resources = analyzer.prepare_from_html(html, url=url, sample_cases=sample_cases) analyzed = analyzer.run(resources) for dest_str, template in table.items(): dest = pathlib.Path(dest_str) # generate try: code = generator.run(analyzed, template_file=template) except NotImplementedError as e: logger.error('generator failed: %s', e) continue # write dest.parent.mkdir(parents=True, exist_ok=True) if dest.exists(): logger.error('file already exists: %s', str(dest)) else: logger.info('write file: %s', str(dest)) with open(dest, 'wb') as fh: fh.write(code) if code.startswith(b'#!'): os.chmod(dest, os.stat(dest).st_mode | stat.S_IEXEC) # download try: subprocess.check_call( ['oj', 'download', problem.get_url()], stdout=sys.stdout, stderr=sys.stderr) except subprocess.CalledProcessError as e: logger.error('samples downloader failed: %s', e)
def test_agc041_a(self) -> None: url = 'https://atcoder.jp/contests/agc041/tasks/agc041_a' expected = '\r\n'.join([ r'<var>N</var> <var>A</var> <var>B</var>', r'', ]).strip() + '\r\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_no_1073(self) -> None: url = 'https://yukicoder.me/problems/no/1073' expected = { VarName("MOD"): ConstantDecl(name=VarName("MOD"), value="1000000007", type=VarType.ValueInt), } html = download_html(url) self.assertEqual(analyzer.list_constants_from_html(html), expected)
def test_no_100(self) -> None: url = 'https://yukicoder.me/problems/no/100' expected = '\n'.join([ r'$N$', r'$a_1$ $\ldots$ $a_N$', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_apple_trees(self) -> None: url = 'https://community.topcoder.com/stat?c=problem_statement&pm=11213' expected = { VarName("MOD"): ConstantDecl(name=VarName("MOD"), value="1000000007", type=VarType.ValueInt), } html = download_html(url) self.assertEqual(analyzer.list_constants_from_html(html), expected)
def test_agc043_c(self) -> None: """In the statement, `,` are used as `998,244,353`. """ url = 'https://atcoder.jp/contests/agc043/tasks/agc043_c' expected = { VarName("MOD"): ConstantDecl(name=VarName("MOD"), value="998244353", type=VarType.ValueInt), } html = download_html(url) self.assertEqual(analyzer.list_constants_from_html(html), expected)
def test_10760(self): # `double` is used and one of values is a scientific form `1.0E50`. url = 'https://community.topcoder.com/stat?c=problem_statement&pm=10760' expected = TopcoderClassDefinition( class_name='Nisoku', method_name='theMax', formal_arguments=[(TopcoderType.DoubleList, 'cards')], return_type=TopcoderType.Double, ) html = download_html(url) definition = analyzer.parse_topcoder_class_definition(html, url=url) self.assertEqual(definition, expected)
def test_stirling_number_of_the_second_kind(self) -> None: url = 'https://judge.yosupo.jp/problem/stirling_number_of_the_second_kind' expected_input = '\n'.join([ r'$N$', r'', ]).strip() + '\n' expected_output = '\n'.join([ r'$S(N, 0)$ $\cdots$ $S(N, N)$', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected_input) self.assertEqual(analyzer.parse_output_format_string(html, url=url), expected_output)
def test_unionfind(self) -> None: url = 'https://judge.yosupo.jp/problem/unionfind' expected = '\n'.join([ r'$N$ $Q$', r'$t_1$ $u_1$ $v_1$', r'$t_2$ $u_2$ $v_2$', r':', r'$t_Q$ $u_Q$ $v_Q$', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def main(args: Optional[List[str]] = None) -> None: parser = argparse.ArgumentParser() parser.add_argument('url') parser.add_argument('-t', '--template', default='main.cpp') parser.add_argument('-v', '--verbose', action='store_true') parser.add_argument('-c', '--cookie', default=onlinejudge.utils.default_cookie_path) parsed = parser.parse_args(args=args) # configure logging handler = colorlog.StreamHandler() handler.setFormatter( colorlog.ColoredFormatter( '%(log_color)s%(levelname)s%(reset)s:%(name)s:%(message)s')) level = INFO if parsed.verbose: level = DEBUG basicConfig(level=level, handlers=[handler]) # download url = parsed.url problem = onlinejudge.dispatch.problem_from_url(url) if problem is not None: url = problem.get_url() # normalize url url = url.replace('judge.yosupo.jp', 'old.yosupo.jp') # TODO: support the new pages logger.debug('url: %s', url) with onlinejudge.utils.with_cookiejar( onlinejudge.utils.get_default_session(), path=parsed.cookie) as session: html = network.download_html(url, session=session) sample_cases = network.download_sample_cases(url, session=session) logger.debug('sample cases: %s', sample_cases) # analyze resources = analyzer.prepare_from_html(html, url=url, sample_cases=sample_cases) logger.debug('analyzer resources: %s', resources._replace(html=b'...skipped...')) analyzed = analyzer.run(resources) logger.debug( 'analyzed result: %s', analyzed._replace(resources=analyzed.resources._replace( html=b'...skipped...'))) # generate code = generator.run(analyzed, template_file=parsed.template) sys.stdout.buffer.write(code)
def test_no_1039(self) -> None: """In the statement, specified as 「$\bmod 10^9+7$で答えてください。」 """ url = 'https://yukicoder.me/problems/no/1039' expected = { VarName("MOD"): ConstantDecl(name=VarName("MOD"), value="1000000007", type=VarType.ValueInt), } html = download_html(url) self.assertEqual(analyzer.list_constants_from_html(html), expected)
def test_10727(self): # `long` is used. url = 'https://community.topcoder.com/stat?c=problem_statement&pm=10727' expected = TopcoderClassDefinition( class_name='RabbitPuzzle', method_name='theCount', formal_arguments=[(TopcoderType.LongList, 'rabbits'), (TopcoderType.LongList, 'nests'), (TopcoderType.Int, 'K')], return_type=TopcoderType.Int, ) html = download_html(url) definition = analyzer.parse_topcoder_class_definition(html, url=url) self.assertEqual(definition, expected)
def test_no_1000(self) -> None: url = 'https://yukicoder.me/problems/no/1000' expected = '\n'.join([ r'$N\ Q$', r'$A_1\ A_2\ \cdots \ A_N$', r'$c_1\ x_1\ y_1$', r'$c_2\ x_2\ y_2$', r'$\vdots$', r'$c_Q\ x_Q\ y_Q$', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_arc001_3(self) -> None: url = 'https://atcoder.jp/contests/arc001/tasks/arc001_3' expected = '\r\n'.join([ r'', r'<var>c_{11}</var> <var>c_{12}</var> … <var>c_{18}</var>', r'<var>c_{21}</var> <var>c_{22}</var> … <var>c_{28}</var>', r':', r':', r'<var>c_{81}</var> <var>c_{82}</var> … <var>c_{88}</var>', r'', ]).strip() + '\r\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_11026(self): # `String[]` is used. # The type of the return value is a list. url = 'https://community.topcoder.com/stat?c=problem_statement&pm=11026' expected = TopcoderClassDefinition( class_name='RandomApple', method_name='theProbability', formal_arguments=[(TopcoderType.StringList, 'hundred'), (TopcoderType.StringList, 'ten'), (TopcoderType.StringList, 'one')], return_type=TopcoderType.DoubleList, ) html = download_html(url) definition = analyzer.parse_topcoder_class_definition(html, url=url) self.assertEqual(definition, expected)
def test_no_1(self) -> None: url = 'https://yukicoder.me/problems/no/1' expected = '\n'.join([ r'\(N\)', r'\(C\)', r'\(V\)', r'\(S_1\ S_2\ S_3\ \dots\ S_V\)', r'\(T_1\ T_2\ T_3\ \dots\ T_V\)', r'\(Y_1\ Y_2\ Y_3\ \dots\ Y_V\)', r'\(M_1\ M_2\ M_3\ \dots\ M_V\)', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_arc001_4(self) -> None: url = 'https://atcoder.jp/contests/arc001/tasks/arc001_4' expected = '\r\n'.join([ r'', r'<var>N</var>', r'<var>start</var> <var>goal</var>', r'<var>l_0</var> <var>r_0</var>', r'<var>l_1</var> <var>r_1</var>', r'<var>:</var>', r'<var>:</var>', r'<var>l_N</var> <var>r_N</var>', r'', ]).strip() + '\r\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected) self.assertRaises(analyzer.HTMLParserError, lambda: analyzer.parse_output_format_string(html, url=url))
def test_two_edge_connected_components(self) -> None: url = 'https://judge.yosupo.jp/problem/two_edge_connected_components' expected_input = '\n'.join([ r'$N$ $M$', r'$a_0$ $b_0$', r'$a_1$ $b_1$', r':', r'$a_{M - 1}$ $b_{M - 1}$', r'', ]).strip() + '\n' expected_output = '\n'.join([ r'$l$ $v_0$ $v_1$ ... $v_{l-1}$', r'', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected_input) self.assertEqual(analyzer.parse_output_format_string(html, url=url), expected_output)
def test_no_1078(self) -> None: """`<br />` is used in the output format. """ url = 'https://yukicoder.me/problems/no/1078' expected_input = '\n'.join([ r'$N$', r'$S_1\ S_2\ \cdots\ S_N$', r'$T_1\ T_2\ \cdots\ T_N$', r'$U_1\ U_2\ \cdots\ U_N$', ]).strip() + '\n' expected_output = '\n'.join([ r'$a_{1,1} \cdots\ a_{1,N}$<br>$\vdots$<br>$a_{N,1} \cdots\ a_{N,N}$', ]).strip() + '\n' html = download_html(url) self.assertEqual(analyzer.parse_input_format_string(html, url=url), expected_input) self.assertEqual(analyzer.parse_output_format_string(html, url=url), expected_output)
def prepare_problem(problem: onlinejudge.type.Problem, *, contest: Optional[onlinejudge.type.Contest] = None, session: requests.Session) -> None: dir = get_directory(problem=problem, contest=contest) logger.info('use directory: %s', str(dir)) dir.parent.mkdir(parents=True, exist_ok=True) with chdir(dir): url = problem.get_url() html = network.download_html(url, session=session) sample_cases = network.download_sample_cases(url, session=session) dest_str = "main.cpp" dest = pathlib.Path(dest_str) with open("../../../template/template.cpp") as codefile: code = codefile.read().encode('utf-8') # write dest.parent.mkdir(parents=True, exist_ok=True) if dest.exists(): logger.error('file already exists: %s', str(dest)) else: logger.info('write file: %s', str(dest)) with open(dest, 'wb') as fh: fh.write(code) if code.startswith(b'#!'): os.chmod(dest, os.stat(dest).st_mode | stat.S_IEXEC) # download try: subprocess.check_call( ['oj', 'download', problem.get_url()], stdout=sys.stdout, stderr=sys.stderr) except subprocess.CalledProcessError as e: logger.error('samples downloader failed: %s', e)