AHCのツールについて　第三回　ツール実行方法　（Ubuntu, unix, WSL）

# 自己紹介

(ほとんどの人が)初めまして
uetaと申します。
電気機械系の大学院2年で研究はなぜか統計系統のことをやっています。

# 今回の目的

競技プログラミング特にAtcoderというサイトで提供されるツールの使用方法を説明します。
本サイトではマラソン系のコンテストは<b>Atcoder heuristic Contest</b>、通称AHCと呼ばれています。

今回はこちらで提供されるツールを `Unix系(Ubuntu,centOS...)`や`WSL`で使うときの使用方法です。

割と新しいコンテストだと
以下のようにツールが与えられます。

![Screenshot 2022-12-15 232120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695016/dc11d0d1-0a5a-dd41-e6f7-ac8e8b71ed4b.png)

これです。

# 構成
第一回　[ビジュアライザについて](https://qiita.com/ueta7/items/f3a289d755da30faaa0e)
第二回　[Windowsでの実行方法](https://qiita.com/ueta7/items/31de0301bfce4b95aaf9)
第三回　Ubuntu, WSLでの実行方法　　　←今回

# 今回の流れ
1. 前提知識・このツールでできること
2. 実行する手順（1.rustダウンロード, 2.ツールのダウンロード, 3.実行コマンド) 


## 前提知識・このツールでできること
### 前提知識
- ターミナル　　←存在が分かればいい
- パスの概念　　←ファイル構造やコマンドを用いた移動ができる必要があり

### このツールでできること
・ファイルの実行
・得点の算出
・実行ファイルの可視化
・入力値の生成

ここではインタラクティブとアウトプットオンリーと分けて考えています。
（アウトプットオンリーって名前が正しいのかは要相談）

# 実行する手順

# 1. rustをダウンロードする

rustを入れていない場合（cargoコマンドがないよと言われたとき）
```:rustの入れ方
# Ubuntu
sudo apt install rustc
# centos
sudo yum install rust-toolset
```
（ソース）https://news.mynavi.jp/techplus/article/rust-8/

うまくいかないときは以下参考

https://www.rust-lang.org/ja/learn/get-started

https://qiita.com/ayumi-ikeda/items/c3b4d6997079dcd2f4a2

これで実行できるようになります。

## ２. AtCoderのコンテストサイトからツールをダウンロード

:::note warn
<b>ローカル版</b> を選択しダウンロードします
:::

下にローカル版よりダウンロードした場合のエクスプローラです。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695016/a00bb687-2559-629a-d99d-0ae14f9f79c1.png">

各自の展開したい場所に展開するか、展開後に移動させてください。
まずは、展開（Extract all) します。

そのあと、<b>README.html</b>　を開いてもらうと使い方を確認できます。
（初めに英語ができて、あきらめかけますが下に行くと日本語版があります。）


# 3. 実行コマンド

:::note info
<b>想定ファイル構造</b>
━tools━in━0001.txt
　　　　┃　┗0002.txt ...
 　　　　┠src（ここは手を付けない）
 　　　　┠target（ここは手を付けない）
 　　　　┠cargo.toml（ここは手を付けない）
 　　　　┠cargo.lock（ここは手を付けない）
 　　　　┠README.html(手順書が書いてある）
 　　　　┠seeds.txt
__________以下は実行用ファイルと実行時に生成されるファイル＿＿＿＿＿＿
 　　　　┠output━0001.txt
　　　　　　   ┗0002.txt ...
 　　　　┠score━0001.txt
　　　　　　   ┗0002.txt ...
　 　　　┠score.sh　　←これが100個まとめた時の実行用シェル
　 　　　┠a.py　　　←pythonで実行するときの実行ファイル
　 　　　┗a.cpp　  　←c++で実行するときの実行ファイル
:::

上のようにファイルを作るように考えています
基本的には以上のファイル構造でtoolsの中に移動して実行する必要があります。

<font color="Red">詳しくはREADMEに書かれているためので読みましょう
以下の内容はREADMEの内容を要約したものがメインです。
また、exですべてをまとめて実行できるようにしたものが書かれています。
</font>

## 入力ファイルの生成
seeds.txtに書き込んだ番号の入力値が生成されます。
実行時にtoolsの中までディレクトリを移動する必要があります。

```cmd:入力ファイルの生成
#ディレクトリを移動します（各自環境が合うように変更してください）
cd C:\Users\ueta\Documents\qiita\202212\tools

cargo run --release --bin gen seeds.txt
```

## ・インタラクティブ型の実行例

:::note warn
インタラクティブ（AHC16）の時の想定です
:::

<font color="Red"><b>以下では実行コードを同じツール内に置くことを想定しています。
別の場所にしたい場合は相対パス等を勉強して書き直すとよいと思います。</b></font>


ターミナルより以下のように実行します。

```cmd:aというファイルを実行するとき
#ディレクトリを移動します（各自環境が合うように変更してください）
cd C:\Users\ueta\Documents\qiita\202212\tools

#testerの部分はvisに変わったりもするので要読README
## pythonの実行
cargo run --release --bin tester python a.py < in/0000.txt > out.txt

## c++の実行
g++ -o ./a ./a.cpp
cargo run --release --bin tester ./a < in/0000.txt > out.txt
```

コンテストによっては条件を指定できることがあるのでREADME参照

## ex1. 100個をまとめて実行
100個まとめて実行する場合はそれなりに工夫が必要である。
以下のコードをコピペして、(.sh)として保存する。

```shell: インタラクティブの時の100個の実行.sh
#各自パスの変更が必要
cd /home/ueta/atcoder/contest/tools

#コンパイル(c++の時のみ) ファイルの場所は変更してください。
g++ -o ./a ./a.cpp
#フォルダを作る
mkdir -p output score

#何番から何番まで？
start=0;last=99;

ans=0;
for d in `seq ${start} ${last}`;
do
    j=$(printf "%04d\n" "${d}")
    ##ここに実行コマンドを置く(以下はc++)　ファイルの場所は注意
    cargo run --release --bin tester ./a < ./in/${j}.txt  >./output/${j}.txt 2> ./score/${j}.txt
    ##
    # "Score = " より後の文字列を抽出する（この部分は変わる可能性あり）
    var=$(grep "Score = " ./score/${j}.txt | sed -e 's/[^0-9]//g')
    ans=$(($ans+$var))
    echo $j $var;
done
ans=$(($ans/($last-$start+1)))
echo "Average Score" $ans;
```

これは以下のようにして実行できる
```Terminal
./test100.sh
```

すると1回で100個を回すことができ、その平均値を算出できる。

```
0000 1400
0001 1800
0002 1100
0003 1800
...
0095 1500
0096 1600
0097 1600
0098 1400
0099 1500
Average number 1461
```

また、100では偏りが出るため500回、数千回で算出するといいらしい。（要文献）
（相対評価の時はlogにするといいともいわれている　参考: https://twitter.com/kiri8128/status/1629874801040031744 ）

## ex2. 並列実行用の設定
以下のコードで並列化ができる。
しかし、実行環境の計算能力を超えることはできないため、
並列しすぎるとそれぞれの計算能力が落ちることには注意が必要。

そのため、自分は parallelを導入することで高速化しました。
```
# Ubuntu
sudo apt install parallel
# centOS
sudo yum -y install parallel
```

ダウンロードした後は以下のコードで並列実行ができるようになる。

```shell: インタラクティブの時の並列実行.sh
#各自パスの変更が必要
cd /home/ueta/atcoder/contest/tools

#コンパイル
g++ -o ./a ./a.cpp
#フォルダを作る
mkdir -p output score

#何番から何番まで？
start=0;last=99;
#何個並列するか
para=20

seq ${start} ${last} | parallel --no-notice -j ${para} '
    j=$(printf "%04d\n" "{}")
    cargo run --release --bin tester ./in/${j}.txt >./output/${j}.txt 2>./score/${j}.txt
    var=$(grep "Score = " ./score/${j}.txt | sed -e 's/[^0-9]//g')
    echo $j $var;'

ans=0;
for d in `seq ${start} ${last}`;
do
    j=$(printf "%04d\n" "${d}")
    var=$(grep "Score = " ./score/${j}.txt | sed -e 's/[^0-9]//g')
    ans=$(($ans+$var))
done
ans=$(($ans/($last-$start+1)))
echo "Average Score" $ans;
```


# ・アウトプットオンリーの時の例

:::note warn
アウトプットオンリー([AHC17](https://atcoder.jp/contests/ahc017/tasks/ahc017_a))の想定です。
:::

インタラクティブ型ではなかった場合の例を示します。


アウトプットオンリー時は
1. 実行して「`in.txt`」入力して「`out.txt`」を生成する
2. ファイルをローカルテスタにかける(点数計算,ヴィジュアライズ)

という手順をとる

```cmd:aというファイルを実行するとき
#ディレクトリを移動します（各自環境が合うように変更してください）
cd C:\Users\ueta\Documents\qiita\202212\tools

##コードの実行
#c++の実行コマンド
g++ -o ./a ./a.cpp
./a < in/0000.txt > out.txt

#python　の実行コマンド
python a.py < in/0000.txt > out.txt

#結果の図示と得点計算
cargo run --release --bin vis in/0000.txt out.txt
```

### 並列実行で高速化

 ```
# Ubuntu
sudo apt install parallel
# centOS
sudo yum -y install parallel
```
```sh:test100_parallel.sh
#各自パスの変更が必要
cd /home/ueta/atcoder/contest/tools

#コンパイル(c++の時のみ)
g++ -o ./a ./a.cpp

#フォルダを作る
mkdir -p output score score2
#何番から何番まで？
start=0;last=99;
#何個並列するか
para=20

seq ${start} ${last} | parallel --no-notice -j ${para} '
    j=$(printf "%04d\n" "{}")
    ./a <./in/${j}.txt >./output/${j}.txt
    cargo run --release --bin vis ./in/${j}.txt ./output/${j}.txt >./score/${j}.txt 2>./score2/${j}.txt
    var=$(grep "Score = " ./score2/${j}.txt | sed -e 's/[^0-9]//g')
    echo $j $var;'

ans=0
for d in `seq ${start} ${last}`
do
    j=$(printf "%04d\n" "${d}")
    var=$(grep "Score = " ./score2/${j}.txt | sed -e 's/[^0-9]//g')
    ans=$(($ans+$var))
done
ans=$(($ans/($last-$start+1)))
echo "Average Score" $ans
```

最大100個並列処理し、結果をtxtに出力し、その結果の平均値を算出する仕組みになっています。
これで高速で全パターン試せます。



# まとめ
これで全編終わりました。
ご覧いただきありがとうございました。