TypeScriptでAtCoderに挑戦してみる

こんにちは、この記事は[TypeScript AdventCalendar](https://qiita.com/advent-calendar/2019/typescript) 8日目の記事です。

## 概要
普段PythonでAtCoderに挑戦しているが、せっかくなので好きなTypeScriptで挑戦してみたい...!!!
ということで、とりあえず簡単なABC(AtCoderの初心者向けコンテスト)の簡単な問題をTypeScriptで解いてみることにしました。


ちなみにJavaScript/TypeScriptで競技プログラミングをする際の注意点はこの記事がよくまとまっています。
~~（どう考えても向いてなさそう）~~
[JavaScript/TypeScriptで競技プログラミングをするには 後編](http://tatamo.81.la/blog/2018/02/09/competitive-programming-using-js-and-ts-02/)

## AtCoderとは
日本最大の競技プログラミングのコンテストサイトです。
週末にはなにかしらのコンテストが開催されています。

https://atcoder.jp

また、対応言語の種類も多いのが特徴で、ばっちりTypeScriptも入っています。バージョンは2.1.6です。
![提出 - AtCoder Beginner Contest 143 - Google Chrome 2019-12-07 11.20.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125528/b018ecc4-0dab-d7f1-7e0a-ff459ee6b0ca.png)

## 環境構築
ローカルで動作確認できるように環境を構築しましょう。
Node.jsやnpmは入っている前提で環境構築を進めます。

まずはnpm initでpackage.jsonを作ります。

```cmd
$ npm init
```

その後、TypeScriptを動かすのに必要なモジュールをインストールします。

```
$ npm install typescript@2.1.6 ts-node @types/node
```

`ts-node`はTypeScriptをコンパイルせずにそのまま動かせるモジュールです。

## ABC-A問題を解いてみる
環境が整ったので、ABC-A問題を解いてみましょう。
今回解く問題は、以下の問題です。

[A - Curtain](https://atcoder.jp/contests/abc143/tasks/abc143_a)

この問題をPythonで解くと以下になります。

```python
def a():
    a_, b = map(int, input().split())
    res = a_ - b * 2
    print(res if res > 0 else 0)


if __name__ == '__main__':
    a()
```

一番簡単な問題なのでロジックも極めてシンプルです。

### ファイル作成

TypeScriptファイルを作成して開きましょう。

```
$ touch index.ts
```

### 入力
まずは標準入力を受け付ける必要があります。
シンプルに `a b` という1行を取り込んで、スペースでsplitすればいいだけです。

ただ、TypeScriptだとここでまずつまづきますｗ

[Node.jsの標準入力と](https://qiita.com/hiroqn@github/items/c927bc97780c34eda562)
こちらの記事を参考に、以下の2つの方法で標準入力を取り込んでみます。

#### readFileSyncを利用する
fsのreadFileSyncを利用します。
割と簡潔に書けますが、**Windowsで動かない** という致命的な欠点があります。

これ以降は、こちらを利用します。

```typescript
import * as fs from 'fs';
 
const input = fs.readFileSync("/dev/stdin", "utf8");
```

#### readlineモジュールを利用する
readlineモジュールを利用します。
Windowsでも動きますが、とにかくコードが複雑です。

最後にreadlineモジュールを用いた、コード例も載せておきます。

```typescript
const lines=[];
const reader = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout
});

reader.on('line', function (line) {
  lines.push(line);
});
reader.on('close', function () {
    // この中に入力が終わった後の処理=ロジックを記載する。
});

```

### 入力したものをsplitして変数にする
入力できれば、あとはスムーズに書けます。
stringであれば`split`を利用して、分割して、変数に代入します。

```typescript
import * as fs from 'fs';

const input = fs.readFileSync("/dev/stdin", "utf8").split(" ");
const a = +input[0];
const b = +input[1];
```

`a`と`b`は`+`をつけることで、string型からnumber型へ変換を行っています。
+をつけないと、後の計算時にエラーになります。

### 計算して出力する
残りは、Pythonなどとほぼほぼ変わらずTypeScript独特のポイントはありません。
ただ計算してロジックを書いて出力するだけです。

出力は、入力とうってかわっておなじみの`console.log()`を利用すればよいので非常に簡単です。

```typescript
import * as fs from 'fs';
 
const input = fs.readFileSync("/dev/stdin", "utf8").split(" ");
const a = +input[0];
const b = +input[1];
 
const res = a - b * 2;
 
if (res > 0) {
	console.log(res);
} else {
	console.log(0);
}
```

## 動作確認する
これで、コードが完成したので動かしてみましょう！
先ほども言ったとおり、このコードはWindowsでは動かないので、Windows環境以外で動かしましょう。

```
$ ./node_modules/.bin/ts-node index.ts
12 4
4
```

問題に記載されている入力例を入力して、出力例通りに出ればOKです。
ちなみに、入力が終わったら、Ctrl+Dを打ってEOF文字を入力する必要があります。

## AtCoderに提出する
最後に、AtCoderに提出してみましょう。
![A - Curtain - Google Chrome 2019-12-07 12.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125528/d1521f0d-6f08-352f-2903-4b9dfb5d7a14.png)

![自分の提出 - AtCoder Beginner Contest 143 - Google Chrome 2019-12-07 12.14.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125528/45179b35-d18c-252f-0c96-1e0a933e346a.png)

`AC`と出れば正解です :tada: :tada::tada: 

## readlineを使ったサンプル例

```typescript
const lines=[];
const reader = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout
});

reader.on('line', function (line) {
  lines.push(line);
});
reader.on('close', function () {
    const input = (lines[0] as string).split(" ");
    const a = +input[0];
    const b = +input[1];

    const res = a - b * 2;
    
    if (res > 0) {
        console.log(res);
    } else {
        console.log(0);
    }
});

```


## 感想
- 案外、標準入力以外はサクッと書ける
- 標準入力だけはめんどくさいのでテンプレート化などの対策が必要
- 今回は、非常に簡単な問題だったけど、複雑なデータ構造(queue, treeなど)を利用する場合、さらに大変そう...

というわけで、本記事は以上になります。
いつかはTypeScriptオンリーでコンテストに参加してみたい...!