Xcodeで競技プログラミング

これは[Competitive Programming (1) Advent Calendar 2020](https://adventar.org/calendars/4969)の8日目の記事です。

# AtCoder Tools for Swift

SwiftでAtCoderを楽しむ方が増えてきたので、kyuridenamidaさん作のAtCoder ToolsをSwift対応させてみました。主にSwift環境について記述しますが、後半でC++の場合についても説明します。

- [AtCoder Tools Swift対応版](https://github.com/firewood/atcoder-tools/tree/swift)<br>`swift` branchにあります。本家にもマージされていますが、こちらには追加のサンプルなどが入っています。

- [AtCoder Tools Xcode対応版](https://github.com/firewood/atcoder-tools/tree/xcode)<br>`xcode` branchにあります。上記の`swift`ブランチに加えてC++用のサンプルが含まれています。

AtCoder Toolsというのは、AtCoderから問題文やサンプルを取得して、ローカルテストや提出までできる超便利ツールです。
詳しくは「[便利！ AtCoder で競技プログラミングをするときに重宝する AtCoder Tools のご紹介](https://qiita.com/noraworld/items/17cd1960b0cd3648f599)」などを読んでみてください。

## インストール方法

バージョン3.6以上のPythonが必要です。本家のAtCoder Toolsはpipでインストール可能ですが、上記の開発版をインストールするにはpoetryもインストールしておく必要があります。以下の手順でインストールできます。

```shell
$ cd (適当な作業ディレクトリを作ってそこに移動する)
$ git clone https://github.com/firewood/atcoder-tools.git
$ cd atcoder-tools
$ git checkout swift      # C++の方は xcode
$ poetry install
```

オプション省略時には、設定ファイルを`~/.atcodertools.toml`として作成する必要があります。`workspace_dir`の指定は必須です。
`swift`ブランチでは　`examples/swift/config.toml` に以下のような設定ファイルを用意してあります。

```toml:examples/swift/config.toml
[codestyle]
#indent_type='tab'
indent_type='space'    # 区切り文字はスペース (default)
#indent_width=4        # インデント幅は4 (default)
#workspace_dir='~/temp/atcoder-tools/examples/swift'
workspace_dir='.'
#lang='python'
lang='swift'
code_generator_toml='./codegen.toml'    # コードジェネレータの指定、おそらく変更する必要はない
template_file='./template.swift'        # コードテンプレートファイルの指定
```

コードジェネレータを指定することで、(浮動小数点の変数の型を変更したりなど)かなり細かいカスタマイズをすることができますが、カスタマイズしたい場合はそれほどないと思います。
コードテンプレートファイルのほうは、自前のライブラリ関数などを追加していくことになると思います。
無指定時のテンプレートファイルは[これ](https://github.com/firewood/atcoder-tools/blob/swift/atcodertools/tools/templates/default_template.swift)です。`template_file`で指定できます。

## コンテストデータの取得

コマンドラインから `atcoder-tools gen abc200` のように呼び出すと、コンテストデータを取得し、`workspace_dir`の下のコンテスト名のディレクトリ(例えば `abc200` )が作成されます。そこに問題毎の`A` `B` `C` `D` `E` `F`のようなディレクトリが作成され、それぞれのディレクトリの下に`main.swift`が生成されます。
`swift`　ブランチでは　`examples/swift/gen.sh` にシェルスクリプトを用意してあります。
このシェルスクリプトでは `gen` コマンドを呼び出したあと、`project_files` にあるプロジェクトファイルをコンテスト名のディレクトリにコピーします。

```
$ cd examples/swift
$ ./gen.sh abc200
```

## Xcodeで編集する

Xcodeで編集するにはCommand Line Toolのプロジェクトを作成する必要があります。
上記の `gen.sh` では　`abc200/A/ProblemA.xcodeproj` が生成されるようになっています。

```
$ cd abc200/A
$ xed .
```

のようにしてプロジェクトを開くと、以下のように、パラメータの入力部分を含んだ`main.swift`が自動生成されているはずです。(問題によっては解析に失敗することもあり、その場合は`main`関数だけが生成されます)
あとはsolve関数の中身を埋めるだけになっています。

```swift:main.swift
import Foundation


func solve(_ N:Int) {
    var ans = 0

    print(ans)
}

func main() {
    var tokenIndex = 0, tokenBuffer = [String]()
    func readString() -> String {
        if tokenIndex >= tokenBuffer.count {
            tokenIndex = 0
            tokenBuffer = readLine()!.split(separator: " ").map { String($0) }
        }
        defer { tokenIndex += 1 }
        return tokenBuffer[tokenIndex]
    }
    func readInt() -> Int { Int(readString())! }
    func readDouble() -> Double { Double(readString())! }
    let N = readInt()
    _ = solve(N)
}

#if DEBUG
let caseNumber = 1
_ = freopen("in_\(caseNumber).txt", "r", stdin)
#endif

main()
```

## Xcodeでデバッグする

AtCoderのように標準入力を前提とするプログラムをデバッグするときは、Xcodeのコンソールに入力を貼りつける必要があります。ただ毎回手入力したくないので、ローカル環境で試すときには、AtCoder Toolsで取得したテストケースのファイルを標準入力にリダイレクトするようにしてみました。(上のコードの`freopen`)
これにより手元(`DEBUG`定義時)ではファイルから、提出時には標準入力から入力できます。提出時にファイルを書き換えたりする必要もありません。`caseNumber`を変えれば任意のテストケースでデバッグできます。
これを行うためにはデバッグ時のカレントディレクトリを入力ファイルのあるディレクトリにしておく必要があります。Product -> Scheme -> Edit Scheme... から変更できます。たとえば`$(PROJECT_DIR)`とするとプロジェクトのディレクトリにできます。そうするとプロジェクトファイルをコピーしたときでも使えます。(`swift`　ブランチのサンプルではこの状態になっています)

![workdir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20902/d00b5df3-6b0e-6ab9-3d57-c277e93bd2cd.png)

実行すると、キーボード入力を待たずに結果が出力され、プログラムが終了するはずです。

![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20902/7638e773-bd2d-1c71-0fe3-d7169c41785c.png)

Xcodeのバージョンによっては`DEBUG`が未定義かもしれません。その場合はプロジェクトのBuild SettingsのSwift Compiler - Custom FlagsのActive Compilation ConditionsのDebugのところに`DEBUG`を追加します。(下図)

![debug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20902/1fee1af8-2885-0195-9fca-57da32781bb7.png)

## まとめてテスト＆提出する

Atcoder Toolsのtestコマンドにより、全てのサンプルでテストできます。これは例えばこういう感じのMakefileを用意しておくといいと思います。([サンプルにあります](https://github.com/firewood/atcoder-tools/blob/swift/examples/swift/A/Makefile))

```makefile:Makefile

.PHONY: test submit resubmit

test: build
	atcoder-tools test

submit: build
	atcoder-tools submit

resubmit: build
	atcoder-tools submit -u

build: a.out

a.out: main.swift
	swiftc $< -o $@
```

この例だと`make`と`make test`は同じで、全てのサンプルをテストします。

![ac.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20902/4e24c1d6-21db-eb4a-f430-2466ec610a47.png)

大丈夫そうであれば`make submit`で提出できます。テストが通らないと提出できませんが、テストケースと完全一致しない場合もあるので、そういうときは手動でコピー＆ペーストして提出してください。
`make resubmit`で再提出可能です。

## C++の場合

ほぼSwiftと同じです。[xcodeブランチ](https://github.com/firewood/atcoder-tools/tree/xcode)の`examples/cpp/`以下にプロジェクトファイルのサンプルがあります。
このサンプルを試すには、[AtCoder Library](https://github.com/atcoder/ac-library)を`/usr/local/include`以下にインストールしてください。(つまり`/usr/local/include/atcoder/modint`などが存在する状態)

## おわりに

私は普段もっぱらC++でコンテストに参加していますが、これからはSwiftでも復習していきたいなと思っています。不具合や改善点などあれば、コメント欄や[Twitter](https://twitter.com/hotpepsi)でぜひ教えていただきたいです。
Xcodeで楽しいAtCoderライフを送りましょう!

# 宣伝

競技プログラミングのコンテストカレンダーを作っていますのでよかったらご利用ください。主に短時間のコンテストを載せています。
自分のGoogle Calendarに追加することもできます。
https://competitiveprogramming.info/calendar

# Swiftでの競技プログラミングで役立つ記事

- [便利！ AtCoder で競技プログラミングをするときに重宝する AtCoder Tools のご紹介
](https://qiita.com/noraworld/items/17cd1960b0cd3648f599)
  - 非常に便利なツール
- [[AtCoder]Swiftでも競プロがしたい！](https://qiita.com/kntkymt/items/4f02c6b90462f354de6d)
  - AtCoderの登録のところから説明している
- [Swift版 競プロ用チートシート(初心者向け)](https://qiita.com/TARDIGRADE/items/71b0a774d7f22418fdf5)
  - AtCoder ABCなどで頻出の基本的なアルゴリズム
- [Swiftで競技プログラミング](https://qiita.com/y_mazun/items/dc2a0cad8da1c0e88a40)
  - 標準入力から変数をタプルで受け取りたい時のテクニック
- [AtCoderSupport](https://github.com/koher/swift-atcoder-support)
  - Swiftによる様々なアルゴリズムと実装例
- [Swift Algorithm Club](https://github.com/raywenderlich/swift-algorithm-club)
  - 大量のアルゴリズムサンプル

# 編集履歴

- 2021-05-03: Swiftブランチが本家に取り込まれたため、記述を更新
- 2021-10-01: 生成されるディレクトリ名をツールの標準の方法にして、gen.shを整えた