Babashka なら Clojure でも AtCoder ができるんじゃないか？

**AtCoder with Babashka**

Clojure は実行が遅い！ (というか最近のバージョンアップデートで既存のコードも TLE するようになった orz)

Babashka (<https://github.com/babashka/babashka>) ならもうちょっと早く実行できるんじゃないか？という実験と、Clojure でも B 問題くらいならまだ解ける、という話です。


<a id="orgbdf7ddd"></a>

# Install

```sh
git clone https://github.com/MokkeMeguru/atcoder-babashka
cd atcoder-babashka
rm -rf .git
./install.sh
```

babashka が `$HOME/.bbsk` に保存されます。

<a id="org26b1f1b"></a>

# AtCoder をやってみる

サンプルとして、ABC086A Product <https://atcoder.jp/contests/abs/tasks/abc086_a> をやってみましょう。

まずは、環境を立ち上げます。

```sh
make env PROBLEM=https://atcoder.jp/contests/abs/tasks/abc086_a
```

テストの入力、出力、そして編集すべきコード (`codes/abs/abc086_a.clj`) が生成されます。

    python tools/build_env.py https://atcoder.jp/contests/abs/tasks/abc086_a
    2021-04-18 01:00:51,680 - build_env - INFO - start
    2021-04-18 01:00:51,803 - build_env - INFO - migrate test inputs
    2021-04-18 01:00:51,804 - build_env - INFO - migrate test outputs
    2021-04-18 01:00:51,804 - build_env - INFO - migrate source code
    2021-04-18 01:00:51,804 - build_env - INFO - catch file create error codes/abs/abc086_a.clj is already exist
    2021-04-18 01:00:51,804 - build_env - INFO - done


<a id="orgd3b875e"></a>

## コードを書く

コードの生成を確認したら、実際にコードを書いてみましょう。 本レポジトリでは AtCoder の形式としてテンプレートとなりそうなものを、 `tools/templates/temp.clj` として生成しています。

サンプル実装

```clojure
(defn ->input-model [_]
  (let [[a b] (->> (read-line) trim split-by-white (map #(Integer/parseInt %)))]
    [a b]))

(defn solve [[a b]]
  (even? (* a b)))

(defn output [even?]
  (if even?
    (println "Even")
    (println "Odd")))
```


<a id="orgcaba225"></a>

## コードを書いたら、テストを行う

テスト方法は大きく分けて2つあります。

一つは、REPL を用いたもので、こちらはお使いの環境に従って下さい。 
もう一つは、AtCoder のサンプル入力を用いたもので、次のようにしてテストを行うことが出来ます。

```sh
make test PROBLEM=https://atcoder.jp/contests/abs/tasks/abc086_a
```

ログとしては次のようになります。

    python tools/test_code.py https://atcoder.jp/contests/abs/tasks/abc086_a
    2021-04-18 01:11:28,245 - test_code - INFO - start
    Test Case 0 :passed 👍
    Test Case 1 :passed 👍
    2021-04-18 01:11:28,272 - test_code - INFO - end


<a id="org7be9c10"></a>

## テストが通ったら

AtCoder のページより、提出を行って下さい。


<a id="orgd4cb608"></a>

# Q & A


<a id="orga6b534e"></a>

## テンプレートを変えたいんだけど

Makefile の TEMPLATE を変えるか、 `make env` の引数に `TEMPLATE=<path-to-template>` を追加して下さい。

## AtCoder の Clojure 流石におそすぎない？
はい、遅いです。特に競プロゴリゴリしたい言語ではないので、あんまり言語アップデートなどにアンテナを張っていなかったせいです。
ただ、アップデートで AC が TLE に化けているらしいので、ちょっとやだなーと思っています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147520/ff94a634-ee80-d9e6-8add-093eae4fc182.png)

(テストのため、AtCoder に登録したら解くべき精選過去問 10 問を Clojure で解いてみた https://qiita.com/fireflower0/items/92af088fea314a6cbcc2 さんのコードをお借りしました。ありがとうございます。)

<a id="orga082f38"></a>

# その他

Clojure で 競技プログラミング！というのは、趣味でやりたい人を除いて、正直な所全くおすすめできません。 理由としては、

-   人気のあるツールは環境が整っているので、高いスコアが得られやすい
-   知見が少ない (出題者の脳みそも有限なので、過去の問題の知見が生きやすい)
-   知見のアウトプットに苦しい

などが挙げられます。

また、少なくとも AtCoder なら Python 使ったほうが良いです。(メモリとか実行速度とか以前に、許されているライブラリが多すぎるため) あとは C++ (AtCoder Library) とか、それぞれの公式が推しているものを使いましょう。

例えば、Python で組み合わせを計算するならば、

```python
seq = range(10)

import itertools

len(list(itertools.combinations(seq, 2))) == 45
```

とすればアルゴリズムを考えずとも実装できますが (チューニングの話はさておき)、Clojure では

```clojure
(def seq (range 10))

(defn combination
  ([n k]
   (cond
     (or (zero? n) (zero? k)) []
     (< n k) []
     (= n k) (mapv vector (range n) (range n))
     :else (vec (filter some? (combination n k [] 0)))))
  ([n k candidate acc]
   (cond
     (= k (count candidate)) [candidate]
     (<= n acc) nil
     :else (concat (combination n k (conj candidate acc) (inc acc))
                   (combination n k candidate (inc acc))))))

(= 45 (count (combination 10 2)))
```

とだいぶ面倒くさくなります。