Jupyter Notebookで競プロの入力例を受け取る、快適な環境作りを紹介します。
記事でやること
- 競プロしやすいファイル構成を作る
- 標準入力セットをスニペットに登録
- Atcoderから入力例を自動で読み込む
環境
- OS : macOS
- エディター : Visual Studio Code
- 言語 : Python
1. 競プロしやすいファイル構成を作る
まずは、以下のようにフォルダ内に2つのファイルを作成します。
atcoder
|- main.ipynb
|- input.txt
input.txt
ファイルには、入力例を「2つの改行で区切る」形で書き込みます。また、「1つの改行」がある場合、それはある入力例の続きとみなします。自分で作成した入力例も、ここに書き込むことができます。なんかWAになるとき、簡単にコードテストできるので良き。
入力例1(1行目)
入力例1(2行目)
入力例2(1行目)
入力例2(2行目)
入力例3(1行目)
入力例3(2行目)
:
2. 標準入力セットをスニペットに登録
次に、標準入力を受け取るためのスニペットを登録します。スニペットを使うと、入力例が受けとる呪文を毎回書く必要がなくなります。登録の仕方は以下ような感じです。
- vscodeで
cmd+shift+p
。コマンドパレットを開く。 - コマンドパレットに
User snippet
を入力 - 言語はpython.jsonを選択
- 開いたpython.jsonファイルに以下を追加
{
"cp load input": {
"prefix": "cp load input",
"body": [
"input_case = 1",
"with open('./input.txt') as file:",
" input_lines = file.read().split('\\n\\n')[input_case - 1].split('\\n')",
"def input(): return input_lines.pop(0)"
]
},
"cp int": {
"prefix": "cp int",
"body": ["int(input())"]
},
"cp map": {
"prefix": "cp map",
"body": ["map(int, input().split())"]
},
"cp s list": {
"prefix": "cp s list",
"body": ["input().split()"]
},
"cp n list": {
"prefix": "cp n list",
"body": ["list(map(int, input().split()))"]
},
"cp 2d n list": {
"prefix": "cp 2d n list",
"body": ["[list(map(int, input().split())) for i in range(n)]"]
},
"cp 2d s list": {
"prefix": "cp 2d s list",
"body": ["[list(input()) for i in range(n)]"]
},
}
prefix
は、入力サジェストされるワードの指定です。
より正確なルールや言葉に従って命名したい人は、設定を変更してみて下さい。
登録したスニペットを使ってみる
例として、ABCコンテスト312のC問題の入力例を受け取ってみましょう。
まずはinput.txtに、入力例を貼り付けます。(後にこれも自動化する方法を紹介します)
3 4
110 90 120
100 80 120 10000
5 2
100000 100000 100000 100000 100000
100 200
3 2
100 100 100
80 120
次にmain.ipynb
で、先ほど登録したスニペットを利用して、入力例を受け取りましょう。
入力例を受け取るときは、最初にcp load input
スニペットを使用します。これで、input.txtの内容を読み込むコードが記述されます。提出時は、この記述を削除してください。
# cp load inputを使用
input_case = 1
with open('./input.txt') as file:
input_lines = file.read().split('\n\n')[input_case - 1].split('\n')
def input(): return input_lines.pop(0)
# cp mapを使用
n, m = map(int, input().split())
# cp listを使用
a = list(map(int, input().split()))
b = list(map(int, input().split()))
input_case
の数字を変更することで、何番目の入力例を受け取るかを指定できます。
3. Python+Automatorで入力例を自動取得
Atcoderから入力例をポチポチコピーするの面倒ですよね。
それをAutomatorを使って自動化してみましょう。
自動化すると、Atocderの問題URLから自動でinput.txtに入力例を書き込めます。
Atcoderから入力例を取得するPythonコードを作成
まずは、input_reader.py
という名前のPythonファイルを作成します。保存場所はどこでも大丈夫ですが、私の場合は/Users/username/python/app/automator/input_reader.py
に保存しました。
次に、このPythonファイルに以下のコードを書き込みます。
コード内のfile_path
変数にinput.txt
のフルパスを設定して下さい。これは、スクレイピングした文字列をinput.txt
に書き込むのに必要です。
import sys
import requests
from bs4 import BeautifulSoup
def get_problem_examples(url):
try:
r = requests.get(url)
r.raise_for_status() # HTTPエラーがあればここで例外を引き起こすよ
except requests.exceptions.RequestException as err:
print(f"リクエストに問題があったみたいだよ💁♀️: {err}")
sys.exit(1)
soup = BeautifulSoup(r.text, "html.parser")
data = soup.find_all("div", class_="part")
input_data = []
output_data = []
for d in data:
h3 = d.find("h3")
if h3:
pre = d.find("pre")
if h3.string.startswith("入力例"):
input_data.append(pre.text)
if h3.string.startswith("出力例"):
output_data.append(pre.text)
return input_data, output_data
def write_to_file(input_data, output_data, file_path):
if input_data and output_data:
input_data = "\n".join(input_data)
output_data = "\n".join(output_data)
res = input_data + "\n--------Answer--------\n" + output_data
with open(file_path, mode="w") as f:
f.write(res)
def main():
url = sys.argv[1]
# ---- ここ大事! input.txtのフルパスを設定 ----
file_path = "~/input.txt"
# ----------------------------------------
if url.startswith("https://atcoder.jp/contests/"):
input_data, output_data = get_problem_examples(url)
write_to_file(input_data, output_data, file_path)
if __name__ == "__main__":
main()
BeautifulSoupも使うので、pipでインストールしておきましょう。
pip install beautifulsoup4
ショートカットキーで、Automator->Python実行の設定をする
次に、Automatorを使ってPythonスクリプトを実行する設定を行います。
これにより、ショートカットキーを押すだけで先ほど作成したinput_reader.pyが実行されます。
まず、Automatorを起動して、cmd + n
で新規から「クイックアクション」を選択し作成します。それから、ワークフローから「シェルスクリプトを実行」を追加し、以下のスクリプトを入力します。
# クリップボードの内容を取得
clip_content=$(pbpaste)
# input_reader.pyを実行
/opt/homebrew/Caskroom/miniforge/base/envs/python3_8/bin/python /Users/username/python/app/automator/input_reader.py "$clip_content"
ただし、# input_reader.pyを実行
と書かれているところは、ユーザー環境に合わせて記述します。
{pythonコマンドのフルパス} {input_reader.pyのフルパス} "$clip_content"
Pythonコマンドのフルパスはターミナルでwhich python
などと実行し、取得してください。
そしたら 「ワークフローを受け取る項目」を「入力なし」に設定し、保存して完了です。
最後にショートカットキーの設定をします。Macの「システム設定」から「キーボード->キーボードショートカット」と進み、さらに「サービス->一般」からinput_readerをダブルクリックし、ショートカットを設定します。私はcmd + shift + ctrl + r
と設定しました。
これでおしまいです。
実際に使ってみる
- Atcoderの問題ページに行き、URLを
cmd + c
などでコピーする - 先ほど作成したショートカット
cmd + shift + ctrl + r
を実行する
こうすることで、クリップボードにコピーされたURLを入力として、input_reader.py
が実行されます。結果、input.txt
に問題の入力例が出力されます。
最後に
最初はちょっと面倒かもしれませんが、一度設定すれば結構快適です。
もっと良い方法や、ここがわからない、これがうまくいかないということがあれば、ぜひコメントください。