AtCoderでテスト実行の自動化！～TypeScriptでAtCoderをしませう～

# はじめに
mediba Advent Calendar 2022 の7日目担当、自称社内AtCoder宣伝大使の@reatoretchです。
自分の所属するBFFチームではTypeScriptで開発を行っているので
本記事ではTypeScriptでAtCoderをするための環境をDockerで作成します。

# AtCoderで使用できる言語環境について
現在AtCoderで使用できる環境や、言語ごとに使用可能なライブラリは以下に記載があります。
対応しているバージョンについてTypeScriptは3.8、nodeは12.16.1となっています（2022/12/07時点）。

https://atcoder.jp/contests/language-test-202001

# テスト実行ツール
有名なものとしてatcoder-cliとAtCoder Toolsという2つがありますが、今回はatcoder-cliを使用したいと思います。
atcoder-cliはonline-judge-toolsに依存しているため、それぞれをatcoder-cliはnpm、online-judge-toolsはpipでインストールする必要があります。

# 構成
以下にディレクトリ構成を示します。

```bash
atcoder_env
├── .login
├── Dockerfile
├── atcoder-cli-nodejs
├── check
├── docker-compose.yml
└── submit
```

docker-composeを使用しました。
テストの実行、提出にはShellScriptを使用しています。

# docker-compose
動作確認した環境がM1 Macだったのでエラー回避のための記述を入れていますが、
入れるとbuildが定数倍遅いので必要なければ消してください。
```yml:docker-compose.yml
version: '3.7'
services:
  dev:
    build:
      context: .
      dockerfile: Dockerfile
    
    # M1 Mac用の記述
    platform: linux/amd64

    # イメージ名を指定
    image: reatoretch/atcoder:dev

    # localとcontainer間のファイルを同期させる
    # ${local}:${container}
    volumes:
    # online-judge-toolsとatocder-cliのコンフィグ・セッション情報
      - ./.login:/root/.login
      - ./atcoder-cli-nodejs:/root/.config/atcoder-cli-nodejs

    # Overrides default command so things don't shut down after the process ends.
    command: /bin/sh -c "while sleep 1000; do :; done"
```

# Dockerfile

`apt-get`でもnodejsやtypescriptを入れることはできますが、
バージョンを指定することができないので`npm`でインストールしています。
nodeのバージョンは12.16.1なので@types/nodeを入れる際にバージョンの指定を忘れるとエラーを吐くので注意してください。
また、あなたの住んでいる場所次第では通信するデフォルトサーバが海外になる可能性があるので、
その場合はコメントアウトしている`sed`を実行している部分を戻してください。
```dockerfile:Dockerfile
# Ubuntuの公式コンテナを軸に環境構築
# 22.04ではaptからpython3.8が入っていなかったので20.04で固定する
FROM ubuntu:20.04

# インタラクティブモードにならないようにする
ARG DEBIAN_FRONTEND=noninteractive
# タイムゾーンを日本に設定
ENV TZ=Asia/Tokyo

# （注）iterm2でしか動かない設定
ENV TERM=xterm-256color

# RUN sed -i 's@archive.ubuntu.com@ftp.jaist.ac.jp/pub/Linux@g' /etc/apt/sources.list

# インフラを整備
RUN apt-get update && \
    apt-get install -y time tzdata tree git curl vim

# C++, Python3, PyPy3をインストール
RUN apt-get update && \
    apt-get install -y gcc-9 g++-9 python3.8 python3-pip pypy3 npm

# 一般的なコマンドで使えるように設定
# e.g. python3.8 main.py => python main.py
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 30 && \
    update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 30 && \
    update-alternatives --install /usr/bin/python python /usr/bin/python3.8 30 && \
    update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 30 && \
    update-alternatives --install /usr/bin/pypy pypy /usr/bin/pypy3 30 && \ 
    update-alternatives --install /usr/bin/node node /usr/bin/nodejs 30

# AtCoderでも使えるPythonライブラリをインストール
RUN pip install -U pip && \
    pip install numpy==1.18.2 scipy==1.4.1 scikit-learn==0.22.2.post1 \
                numba==0.48.0 networkx==2.4

# TypeScriptをインストール
RUN npm install -g typescript@3.8 ts-node 

# nvmをインストール
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

# nodeをインストール
RUN . $HOME/.nvm/nvm.sh && \
    nvm install 12.16.1

# AtCoderでも使用できるTypeScriptのライブラリをインストール
RUN npm init -y && \
    tsc --init && \
    npm install -D @types/node@12 tstl

# コンテスト補助アプリケーションをインストール
RUN pip install online-judge-tools==11.5.1
RUN npm install -g atcoder-cli@2.2.0


RUN apt-get update && \
    apt-get install -y wget

COPY ./submit /usr/local/bin/submit
COPY ./check /usr/local/bin/check

RUN chmod 777 /usr/local/bin/submit && \
    chmod 777 /usr/local/bin/check

WORKDIR /root

```

# ShellScripts
コマンドが長いのでShellScriptにしましたが、この辺はどうにでもなるので自由にしてください。
Vim scriptを書くとVimの内部で実行できるので便利です。（自分はそうしてます）
```bash:check
#!/bin/bash

if [ $# -eq 2 ]; then
  oj t -c "$1 $2" -d ./tests/
else
  echo "Usage: check pypy main.py"
fi
```
```bash:submit
#!/bin/bash

if [ $# -eq 2 ]; then
  if [ "$1" == "pypy" ]; then
    acc s $2 -- --guess-python-interpreter pypy
  else
    acc s $2
  fi
else
  echo "Usage: submit ${language} main.py"
fi
```

# 成果物
以下のページにあるREADMEの通りに実行すれば動作します。

https://github.com/reatoretch/atcoder_env


# 最後に

　ts-nodeではリアルタイムでtranspileしながら実行するのでテスト実行するとACするコードでも実行時間がとても長く見えることがあるのでテストを実行したとしても参考には出来そうにないです。また、TypeScript(JS)は再帰の最大回数が変更できない等、C++など競技プログラミングの花形言語に比べると弱い部分もあるので、もしTypeScriptで戦うときは苦難の道を進むことを覚悟しましょう。
　しかしながら、私の観測範囲ではJS勢としてオレンジコーダーまで確認しているので強くなれないということは決してないです。好きな言語で競技プログラミングを楽しみましょう！