Skip to content

Commit 880a131

Browse files
No format analysis for ongoing ABC contests (kyuridenamida#286)
* Enable the functionality to skip input format analysis for ongoing ABC contests * Fix format * Fix unit tests
1 parent 9c91981 commit 880a131

File tree

15 files changed

+520
-433
lines changed

15 files changed

+520
-433
lines changed

atcodertools/atcoder_tools.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def main():
4343
if len(sys.argv) < 2 or sys.argv[1] not in ("gen", "test", "submit", "codegen", "compile", "set", "version"):
4444
print("Usage:")
4545
print("{} gen -- to generate workspace".format(sys.argv[0]))
46+
print(
47+
"{} codegen -- to generate code for one problem".format(sys.argv[0]))
4648
print(
4749
"{} compile -- to compile codes in your workspace".format(sys.argv[0]))
4850
print("{} test -- to test codes in your workspace".format(sys.argv[0]))

atcodertools/common/language.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ def from_name(cls, name: str):
123123
name="python",
124124
display_name="Python",
125125
extension="py",
126-
submission_lang_pattern=re.compile(".*Python \\(3.*|.*Python \\(CPython 3.*"),
126+
submission_lang_pattern=re.compile(
127+
".*Python \\(3.*|.*Python \\(CPython 3.*"),
127128
default_code_generator=python.main,
128129
default_template_path=get_default_template_path('py'),
129130
compile_command="python3 -mpy_compile {filename}.py",

atcodertools/constprediction/constants_prediction.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def __init__(self, cands):
3636
self.cands = cands
3737

3838

39+
class FailingToKnowFormatAnalysisAllowedByRuleError(Exception):
40+
def __init__(self, reason):
41+
self.reason = reason
42+
43+
3944
MOD_ANCHORS = ["余り", "あまり", "mod", "割っ", "modulo"]
4045
DECIMAL_ANCHORS = ["誤差", " error "]
4146
LIMIT_ANCHORS = ["時間制限", "Time Limit"]
@@ -206,6 +211,26 @@ def normalize(sentence):
206211
raise MultipleModCandidatesError(limit_cands)
207212

208213

214+
def predict_is_format_analysis_allowed_by_rule(html: str) -> bool:
215+
soup = BeautifulSoup(html, "html.parser")
216+
url_meta_tag = soup.find("meta", property="og:url")
217+
if url_meta_tag is None:
218+
raise FailingToKnowFormatAnalysisAllowedByRuleError(
219+
"No meta tag detected, which is important as a clue to know if the input analysis is allowed.")
220+
221+
# ABC is the target of "No LLM rules" by AtCoder (See https://info.atcoder.jp/entry/llm-abc-rules-ja or https://info.atcoder.jp/entry/llm-abc-rules-en)
222+
is_target_contest_of_no_llm_rule = "/contests/abc" in url_meta_tag["content"]
223+
224+
# If there is no virtual standings link, assume it's ongoing.
225+
is_ongoing_contest = len([tag for tag in soup.find_all(
226+
"a") if "/standings/virtual" in tag.get("href", "")]) == 0
227+
228+
if is_target_contest_of_no_llm_rule and is_ongoing_contest:
229+
return False
230+
231+
return True
232+
233+
209234
def predict_constants(html: str) -> ProblemConstantSet:
210235
try:
211236
yes_str, no_str = predict_yes_no(html)
@@ -233,4 +258,19 @@ def predict_constants(html: str) -> ProblemConstantSet:
233258
"two or more candidates {} are detected as limit".format(e.cands))
234259
timeout = None
235260

236-
return ProblemConstantSet(mod=mod, yes_str=yes_str, no_str=no_str, judge_method=judge, timeout=timeout)
261+
try:
262+
is_format_analysis_allowed_by_rule = predict_is_format_analysis_allowed_by_rule(
263+
html)
264+
except FailingToKnowFormatAnalysisAllowedByRuleError as e:
265+
logger.warning(
266+
"Failed to know whether format analysis is allowed by the contest rules -- ", e.reason)
267+
is_format_analysis_allowed_by_rule = None
268+
269+
return ProblemConstantSet(
270+
mod=mod,
271+
yes_str=yes_str,
272+
no_str=no_str,
273+
judge_method=judge,
274+
timeout=timeout,
275+
is_format_analysis_allowed_by_rule=is_format_analysis_allowed_by_rule,
276+
)

atcodertools/constprediction/models/problem_constant_set.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ def __init__(self,
88
yes_str: str = None,
99
no_str: str = None,
1010
judge_method: Judge = None,
11-
timeout: float = None
11+
timeout: float = None,
12+
is_format_analysis_allowed_by_rule: bool = None,
1213
):
1314
self.mod = mod
1415
self.yes_str = yes_str
1516
self.no_str = no_str
1617
self.judge_method = judge_method
1718
self.timeout = timeout
19+
self.is_format_analysis_allowed_by_rule = is_format_analysis_allowed_by_rule

atcodertools/fmtprediction/predict_format.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ def __init__(self, cands):
1616
self.cands = cands
1717

1818

19-
def predict_format(content: ProblemContent) -> FormatPredictionResult:
19+
class PredictionNotAllowedError(Exception):
20+
pass
21+
22+
23+
def predict_format(content: ProblemContent, is_format_analysis_allowed_by_rule: bool) -> FormatPredictionResult:
24+
if not is_format_analysis_allowed_by_rule:
25+
raise PredictionNotAllowedError
26+
2027
input_format = content.get_input_format()
2128
samples = content.get_samples()
2229

atcodertools/tools/codegen.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from atcodertools.config.config import Config
2020
from atcodertools.constprediction.constants_prediction import predict_constants
2121
from atcodertools.fmtprediction.models.format_prediction_result import FormatPredictionResult
22-
from atcodertools.fmtprediction.predict_format import MultiplePredictionResultsError, NoPredictionResultError, predict_format
22+
from atcodertools.fmtprediction.predict_format import MultiplePredictionResultsError, NoPredictionResultError, PredictionNotAllowedError, predict_format
2323
from atcodertools.tools import get_default_config_path
2424
from atcodertools.tools.envgen import USER_CONFIG_PATH, get_config, output_splitter
2525
from atcodertools.tools.utils import with_color
@@ -89,19 +89,23 @@ def emit_info(text):
8989
emit_error("Failed to download samples.")
9090
raise e
9191

92+
constants = predict_constants(content.original_html)
93+
9294
try:
93-
prediction_result = predict_format(content)
95+
prediction_result = predict_format(
96+
content, constants.is_format_analysis_allowed_by_rule or False)
9497
emit_info(
9598
with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
96-
except (NoPredictionResultError, MultiplePredictionResultsError) as e:
99+
except (NoPredictionResultError, MultiplePredictionResultsError, PredictionNotAllowedError) as e:
97100
prediction_result = FormatPredictionResult.empty_result()
98101
if isinstance(e, NoPredictionResultError):
99102
msg = "No prediction -- Failed to understand the input format"
100-
else:
103+
elif isinstance(e, MultiplePredictionResultsError):
101104
msg = "Too many prediction -- Failed to understand the input format"
105+
elif isinstance(e, PredictionNotAllowedError):
106+
msg = "Format prediction is skipped because it's not allowed by AtCoder rules (At least not allowed in ongoing ABC contests) -- See https://info.atcoder.jp/entry/llm-abc-rules-en"
102107
emit_warning(with_color(msg, Fore.LIGHTRED_EX))
103108

104-
constants = predict_constants(content.original_html)
105109
code_generator = config.code_style_config.code_generator
106110
with open(template_code_path, "r") as f:
107111
template = f.read()

atcodertools/tools/envgen.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
create_code
2525
from atcodertools.fmtprediction.models.format_prediction_result import FormatPredictionResult
2626
from atcodertools.fmtprediction.predict_format import NoPredictionResultError, \
27-
MultiplePredictionResultsError, predict_format
27+
MultiplePredictionResultsError, PredictionNotAllowedError, predict_format
2828
from atcodertools.tools import get_default_config_path
2929
from atcodertools.tools.models.metadata import Metadata
3030
from atcodertools.tools.utils import with_color
@@ -117,19 +117,23 @@ def emit_info(text):
117117
code_file_path,
118118
new_path))
119119

120+
constants = predict_constants(content.original_html)
121+
120122
try:
121-
prediction_result = predict_format(content)
123+
prediction_result = predict_format(
124+
content, constants.is_format_analysis_allowed_by_rule or False)
122125
emit_info(
123126
with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
124-
except (NoPredictionResultError, MultiplePredictionResultsError) as e:
127+
except (NoPredictionResultError, MultiplePredictionResultsError, PredictionNotAllowedError) as e:
125128
prediction_result = FormatPredictionResult.empty_result()
126129
if isinstance(e, NoPredictionResultError):
127130
msg = "No prediction -- Failed to understand the input format"
128-
else:
131+
elif isinstance(e, MultiplePredictionResultsError):
129132
msg = "Too many prediction -- Failed to understand the input format"
133+
elif isinstance(e, PredictionNotAllowedError):
134+
msg = "Format prediction is skipped because it's not allowed by AtCoder rules (At least not allowed in ongoing ABC contests) -- See https://info.atcoder.jp/entry/llm-abc-rules-en"
130135
emit_warning(with_color(msg, Fore.LIGHTRED_EX))
131136

132-
constants = predict_constants(content.original_html)
133137
code_generator = config.code_style_config.code_generator
134138
with open(template_code_path, "r") as f:
135139
template = f.read()

0 commit comments

Comments
 (0)