Skip to content

Commit e178f3c

Browse files
committed
Merge github.com:kyuridenamida/atcoder-tools into travis
2 parents fa20db3 + d581057 commit e178f3c

File tree

12 files changed

+195
-168
lines changed

12 files changed

+195
-168
lines changed

AtCoderClient.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
import sys
44
import os
5-
import glob
6-
import subprocess
5+
76
sys.path.append(".")
87
sys.path.append("core")
98
from AtCoder import AtCoder
@@ -19,8 +18,11 @@ class AccountInformation:
1918
from multiprocessing import Pool, Process, cpu_count
2019
from time import sleep
2120

21+
atcoder = None
22+
23+
2224
def prepare_procedure(argv):
23-
atcoder, pid, url = argv
25+
pid, url = argv
2426
samples = []
2527

2628
# データ取得
@@ -41,7 +43,6 @@ def prepare_procedure(argv):
4143
result = None
4244
print("Problem %s: failed to analyze input format." % pid)
4345

44-
4546
dirname = "workspace/%s/%s" % (contestid, pid)
4647
os.makedirs(dirname, exist_ok=True)
4748
solution_name = "%s/%s.cpp" % (dirname, pid)
@@ -56,7 +57,6 @@ def prepare_procedure(argv):
5657
break
5758
backup_id += 1
5859

59-
6060
# 自動生成済みコードを格納
6161
with open(solution_name, "w") as f:
6262
from templates.cpp.cpp_code_generator import code_generator
@@ -76,6 +76,7 @@ def prepare_procedure(argv):
7676

7777

7878
def prepare_workspace(contestid, without_login):
79+
global atcoder
7980
atcoder = AtCoder()
8081
if not without_login:
8182
atcoder.login(AccountInformation.username, AccountInformation.password)
@@ -88,11 +89,12 @@ def prepare_workspace(contestid, without_login):
8889
print("retrying to get task list.")
8990

9091
p = Pool(processes=cpu_count())
91-
p.map(prepare_procedure, [(atcoder, pid, url) for pid, url in plist.items()])
92+
p.map(prepare_procedure, [(pid, url) for pid, url in plist.items()])
9293

9394

9495
if __name__ == "__main__":
9596
import argparse
97+
9698
parser = argparse.ArgumentParser()
9799
parser.add_argument("contestid",
98100
help="contest ID")

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,17 @@ $ ../../../tools/tester.py
5555
$ python tester.py
5656
```
5757

58-
If you feel annoyed at typing password many times, you can prepare the account information file.
58+
You can skip to input the username and password using the `--without-login` argument.
5959

60+
`--without-login` 引数を指定するとログインなしでデータをダウンロードできます(一般公開されているコンテストのみ)。
61+
62+
```
63+
$ python3 ./AtCoderClient.py [contestid] --without-login
64+
```
65+
66+
If you feel annoyed at typing password many times, you can prepare an account information file.
67+
68+
もしパスワードを毎回入力するのが面倒くさいならアカウント情報のファイルを作ってください。
6069
```
6170
$ echo "password = 'AtCoder password'; username = 'AtCoder username'" > ./AccountInformation.py # Be careful with the password management!!!
6271
```

benchmark/overall_test.py

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,44 @@
1-
#!/usr/bin/python3
2-
# -*- coding: utf-8 -*-
3-
import sys
4-
sys.path.append("../core")
5-
sys.path.append("..")
6-
from AtCoder import AtCoder
7-
import AccountInformation
8-
import FormatAnalyzer
9-
import FormatPredictor
10-
11-
class NoPatternFoundError(Exception) : pass
12-
13-
if __name__ == "__main__":
14-
atcoder = AtCoder(AccountInformation.username,AccountInformation.password)
15-
succ = fail = 0
16-
17-
print("|問題名|結果|エラーの型|")
18-
print("|-:|:-:|:-|")
19-
for cid in atcoder.get_all_contestids():
20-
plist = atcoder.get_problem_list(cid)
21-
result_md = ""
22-
error = ""
23-
for k,v in plist.items():
24-
try:
25-
informat,samples = atcoder.get_all(v)
26-
result = FormatPredictor.format_predictor(informat,samples)
27-
if result:
28-
pass
29-
else:
30-
raise NoPatternFoundError
31-
result_md = "○"
32-
error = ""
33-
except KeyboardInterrupt:
34-
sys.exit(-1)
35-
except Exception as e:
36-
#print("fail,",v)
37-
result_md = "×"
38-
error = str(type(e))[1:-1]
39-
40-
print("|[%s(%s)](%s)|%s|%s|" % (cid,k,v,result_md,error) )
41-
print("|[%s(%s)](%s)|%s|%s|" % (cid,k,v,result_md,error),file=sys.stderr )
1+
#!/usr/bin/python3
2+
# -*- coding: utf-8 -*-
3+
import sys
4+
5+
sys.path.append("../core")
6+
sys.path.append("..")
7+
from AtCoder import AtCoder
8+
import AccountInformation
9+
import FormatAnalyzer
10+
import FormatPredictor
11+
12+
13+
class NoPatternFoundError(Exception): pass
14+
15+
16+
if __name__ == "__main__":
17+
atcoder = AtCoder()
18+
succ = fail = 0
19+
20+
print("|問題名|結果|エラーの型|")
21+
print("|-:|:-:|:-|")
22+
for cid in atcoder.get_all_contestids():
23+
plist = atcoder.get_problem_list(cid)
24+
result_md = ""
25+
error = ""
26+
for k, v in plist.items():
27+
try:
28+
informat, samples = atcoder.get_all(v)
29+
result = FormatPredictor.format_predictor(informat, samples)
30+
if result:
31+
pass
32+
else:
33+
raise NoPatternFoundError
34+
result_md = "○"
35+
error = ""
36+
except KeyboardInterrupt:
37+
sys.exit(-1)
38+
except Exception as e:
39+
# print("fail,",v)
40+
result_md = "×"
41+
error = str(type(e))[1:-1]
42+
43+
print("|[%s(%s)](%s)|%s|%s|" % (cid, k, v, result_md, error))
44+
print("|[%s(%s)](%s)|%s|%s|" % (cid, k, v, result_md, error), file=sys.stderr)

core/AtCoder.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ class LoginError(Exception):
1515
class SampleParseError(Exception):
1616
pass
1717

18+
1819
class InputParseError(Exception):
1920
pass
2021

21-
class AtCoder:
2222

23-
def __init__(self, username=None, password=None):
23+
class AtCoder:
24+
def __init__(self):
2425
self.cj = http.cookiejar.CookieJar()
2526

2627
self.opener = urllib.request.build_opener(
@@ -45,12 +46,12 @@ def login(self, username=None, password=None):
4546
raise LoginError
4647

4748
def get_problem_list(self, contestid):
48-
'''
49+
"""
4950
入力
5051
contestid#str : http://***.contest.atcoder.jp/)だったら***の部分
5152
出力
5253
#OrderedDict<str:str> : 問題番号("A","B","C",..)→URLのディクショナリ
53-
'''
54+
"""
5455
req = self.opener.open(
5556
"http://%s.contest.atcoder.jp/assignments" % contestid)
5657
soup = BeautifulSoup(req, "html.parser")
@@ -62,26 +63,24 @@ def get_problem_list(self, contestid):
6263
return res
6364

6465
def get_all(self, url):
65-
'''
66+
"""
6667
入力
6768
url#str : 問題ページのURL
6869
出力
6970
#(str,list((str,str))) : 指定したページから得られた(入力形式,[(サンプル入力1,出力1),(サンプル入力2,出力2)...]のリスト)の組
70-
'''
71+
"""
7172
req = self.opener.open(url)
7273
soup = BeautifulSoup(req, "html.parser")
73-
74+
7475
# 英語のほうタグ削除
75-
for e in soup.findAll("span", {"class":"lang-en"}):
76+
for e in soup.findAll("span", {"class": "lang-en"}):
7677
e.extract()
77-
78+
7879
# AtCoder Formatぽかったらそっちはpartタグがついてていい感じなので,そっちを解析する
7980
soup_tmp = soup.select('.part')
80-
if soup_tmp != []:
81+
if soup_tmp:
8182
soup_tmp[0].extract()
8283

83-
84-
8584
def detection_algorithm1():
8685
input_tags = []
8786
output_tags = []
@@ -90,7 +89,7 @@ def detection_algorithm1():
9089
h3tag = tag.find('h3')
9190
if h3tag is None:
9291
continue
93-
section_title = pure_japanese_text(tag.find('h3').get_text()) # 何かいくつかの問題のh3タグ内に変な特殊文字が混じっていてやばい
92+
section_title = pure_japanese_text(tag.find('h3').get_text()) # 何かいくつかの問題のh3タグ内に変な特殊文字が混じっていてやばい
9493

9594
if section_title.startswith("入力例"):
9695
input_tags.append(tag.find('pre'))
@@ -99,7 +98,7 @@ def detection_algorithm1():
9998

10099
if section_title.startswith("出力例"):
101100
output_tags.append(tag.find('pre'))
102-
return (input_format_tag, input_tags, output_tags)
101+
return input_format_tag, input_tags, output_tags
103102

104103
def detection_algorithm2():
105104
pretags = soup.select('pre')
@@ -108,36 +107,36 @@ def detection_algorithm2():
108107
input_tags = sample_tags[0::2]
109108
output_tags = sample_tags[1::2]
110109
input_format_tag = pretags[0]
111-
return (input_format_tag,input_tags,output_tags)
110+
return input_format_tag, input_tags, output_tags
112111

113112
try:
114113
input_format_tag, input_tags, output_tags = detection_algorithm1()
115114
if input_format_tag is None:
116115
raise InputParseError
117116
except Exception:
118117
input_format_tag, input_tags, output_tags = detection_algorithm2()
119-
118+
120119
if len(input_tags) != len(output_tags):
121120
raise SampleParseError
122121
res = [(normalized(in_tag.text), normalized(out_tag.text))
123122
for in_tag, out_tag in zip(input_tags, output_tags)]
124-
123+
125124
if input_format_tag is None:
126125
raise InputParseError
127-
126+
128127
input_format = normalized(input_format_tag.text)
129-
130-
return (input_format, res)
128+
129+
return input_format, res
131130

132131
def get_samples(self, url):
133-
'''
132+
"""
134133
入力
135134
url#str : 問題ページのURL
136135
出力
137136
#list((str,str) : [(サンプル入力1,出力1),(サンプル入力2,出力2)...]のリスト
138137
コメント
139138
get_all()関数のwrapper
140-
'''
139+
"""
141140
return self.get_all(url)[1]
142141

143142
def get_all_contestids(self):
@@ -152,15 +151,15 @@ def get_all_contestids(self):
152151
r'https://([A-Za-z0-9\'~+\-_]+).contest.atcoder.jp')
153152
contest_list = url_re.findall(text)
154153
contest_list = sorted(contest_list)
155-
154+
156155
if previous_list == contest_list:
157156
break
158-
157+
159158
previous_list = contest_list
160159
res += contest_list
161160
page_num += 1
162161
res = sorted(res)
163-
#print(res)
162+
# print(res)
164163
return res
165164

166165
def submit_source_code(self, contestid, pid, lang, source):
@@ -189,5 +188,4 @@ def submit_source_code(self, contestid, pid, lang, source):
189188
}
190189
encoded_postdata = urllib.parse.urlencode(postdata).encode('utf-8')
191190
req = self.opener.open(url, encoded_postdata)
192-
html = req.read().decode('utf-8')
193191
return True

core/Calculator.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CalcNode:
4444

4545
def __init__(self, formula=None):
4646
if formula:
47-
root = parseToCalcNode(formula)
47+
root = parse_to_calc_node(formula)
4848
self.content = root.content
4949
self.lch = root.lch
5050
self.rch = root.rch
@@ -56,10 +56,10 @@ def __init__(self, formula=None):
5656
self.rch = None
5757

5858
def __str__(self, depth=0):
59-
if self.operator != None:
59+
if self.operator is not None:
6060
lv = self.lch.__str__(depth=depth + 1)
6161
rv = self.rch.__str__(depth=depth + 1)
62-
res = ("%s%s%s") % (lv, operator_to_string(self.operator), rv)
62+
res = "%s%s%s" % (lv, operator_to_string(self.operator), rv)
6363
if depth > 0 and (self.operator == add or self.operator == sub):
6464
res = "(%s)" % res
6565
return res
@@ -69,7 +69,7 @@ def __str__(self, depth=0):
6969
return self.content
7070

7171
def get_all_varnames(self):
72-
if self.operator != None:
72+
if self.operator is not None:
7373
lv = self.lch.get_all_varnames()
7474
rv = self.rch.get_all_varnames()
7575
return lv + rv
@@ -78,8 +78,10 @@ def get_all_varnames(self):
7878
else:
7979
return [self.content]
8080

81-
def evaluate(self, variables={}):
82-
if self.operator != None:
81+
def evaluate(self, variables=None):
82+
if variables is None:
83+
variables = {}
84+
if self.operator is not None:
8385
lv = self.lch.evaluate(variables)
8486
rv = self.rch.evaluate(variables)
8587
return self.operator(lv, rv)
@@ -163,14 +165,14 @@ def factor(formula, pos):
163165
raise CalcParseError
164166

165167

166-
def parseToCalcNode(formula):
167-
'''
168+
def parse_to_calc_node(formula):
169+
"""
168170
入力
169171
formula # str : 式
170172
出力
171173
#CalcNode : 構文木の根ノード
172174
173-
'''
175+
"""
174176
res, pos = expr(formula + "$", 0) # $は使わないことにする
175177
if pos != len(formula):
176178
raise CalcParseError

0 commit comments

Comments
 (0)