CrystalでAtCoder(Log #1)

# 序文

Crystalについては資料が少ないので、学習記録を残してみます。
リファレンス的なものについては、[公式サイト](https://ja.crystal-lang.org/reference/)を参照して下さい。
バージョンは0.33.0です。
最初の題材は、[AtCoder Problems](https://kenkoooo.com/atcoder/#/table/)の[Boot camp for Beginners](https://kenkoooo.com/atcoder/#/training)です。
Apple Siliconにインストールした際の記録は[別記事](https://qiita.com/YTOK/private/dcb59207eeb8d59a2a69)にしました。immatureなので限定公開記事にしています。

# Easy_1

https://atcoder.jp/contests/abc139/tasks/abc139_b

求める答えは、$⌈(B-1) / (A-1)⌉$。変な括弧は切り上げ。

## メソッドの定義
$⌈x/y⌉$を返す`div_ceil(x, y)`関数を定義する。
`x, y ↦ ⌈x/y⌉`であるので関数で間違いはないのだが、Crystalでは値を返す返さないに関わらず、全てメソッドと呼ぶ。
`div_ceil(x, y)`はプログラムそれ自体というグローバルオブジェクト[^1]に関連付けられたメソッド。
**Crystalではすべてがオブジェクトとメソッドで出来ている。**

```crystal:div_ceil.cr
def div_ceil(x, y)
  (x+y-1) // y
end
```

メソッドの定義は`def` … `end`で行う。
ここでは`x`, `y`という引数を受け取って計算し、返り値（オブジェクト）を返している。
引数や返り値の型を明示する必要はない。
整数を与えれば、**デフォルトでは符号付き32ビット整数**として扱われる。
pythonと違って、インデントに入れ子構造を示す役割はない。
値を返すのに`return`文は不要。
`+`, `-`, `*`, `/`, `%`, `**`はそれぞれは加減乗除、剰余、累乗の計算を行う中置演算子。
ただしCrystalでは**演算子`/`は商を実数(小数型)で返す**ので、ここでは都合が悪い。
**整数で返す演算子は`//`**で、商を切り下げて整数型で返す。小数や負数を含む除算でも同じこと(-∞に向かって丸める)。
一文で言うと、`x//y = ⌊x/y⌋`。

## 標準入力を受けとる
```crystal:input.cr
a, b = read_line.split.map(&.to_i)
```

###標準入力
`read_line`は標準入力から１行を読みこむメソッドで、`String`型で返す。[^2]
###文字列の加工
`Object#method`はオブジェクト`Object`に対応した`method`を示す表記で、実際のコードでは`instance.method`の形で書く。
`String#split`は`String`型に対応した`split`メソッド。１つの`String`をホワイトスペースで区切って複数の`String`に分解し、`Array`型で返す。
###`String`と`Array`

`String`は文字列をUTF-8で保持する。UTF-8は１文字に費やすメモリが不定長（1〜4バイト）なので、**ランダムアクセスできない**(`s[i]`は用意されているが`i`に比例したコストがかかり、時間計算量は$O(|S|)$ )になるので注意が必要。

ただし、要素が全てASCII文字であれば、全て1バイトなので原理上ランダムアクセス可能となり、実際$O(1)$となるように実装されている。

競プロでは$O(1)$と見做してよい。

`Array`は配列を表すデータ構造で、不定長が許される。全ての要素の型が同じ必要があるが、Union型も許される。

###マッピングと型変換
`to_i`はオブジェクトを整数型に変換するメソッドで、`map(&.to_i)`は配列等の要素一つ一つを整数型に変換する。
構文を調べていくと奥が深い。このまま覚えるのがよい。
<details><summary>奥が深いとは</summary>
`Array#map(...)`メソッドは元の配列の要素一つ一つを`()`内のブロックに渡して、そのブロックからの返り値からなる新しい配列を返す。
ブロック`&.to_i`はブロック`{|x| x.to_i}`と等価の表現。
`{|x| x.to_i}`というブロックは一変数を`x`に受け取り、`x.to_i`を返す表現。
</details>

###ここまでのまとめ
標準入力が`"4 10"`の場合を例にとると、
`read_line.split.map(&.to_i)`
⇒ `"4 10".split.map(&.to_i)`
⇒ `["4", "10"].map(&.to_i)` ([“4”, “10”]で長さ2の配列)
⇒ `["4".to_i, "10".to_i]` (“4”, “10”は文字列) 
⇒ `[4, 10]` (4, 10は数値)

### 多重代入
ここまでで`a, b = [4, 10]`。
CrystalはPythonのように多重代入が可能。
左辺がコンマ区切り、右辺が`Indexable`(添字でアクセス可能)の場合にこの構文が可能となり、先頭から順にマッチさせられて代入される。

`a, b = [4, 10]`
⇒ `a = [4, 10][0]; b = [4, 10][1] `
⇒ `a = 4; b = 10`

となる。`;`を使用すると複数の文を１行で記述できる。
右辺の要素が余った時は、残った要素は使用されない。足りない場合はランタイムエラーとなる。

##標準出力

```crystal:output.cr
puts div_ceil(b-1, a-1)
```

求める答えは`div_ceil(b-1, a-1)`の値であるから、これを標準出力する。
`puts`は引数を`String`に変換して標準出力するメソッド。
Crystalでは`f(x)`と`f x`は同じ。`f(x, y)`と`f x, y`は同じ。
つまり`puts(div_ceil(b-1, a-1))`でもよい。
`puts(div_ceil b-1, a-1)`でも`puts div_ceil b-1, a-1`でもよい。深さ優先なのか。
`(puts (div_ceil b-1, a-1))`と書くとちょっとLispっぽい。
可読性を考えると、返り値が重要なものは`f(x)`、副作用が重要なものは`f x`が良いのではなかろうか。

##正答例

main関数のような形で書く必要はなく、実行したい処理は地の文に書く。

```crystal:abc139_b.cr
def div_ceil(x, y)
  (x+y-1) // y
end

a, b = read_line.split.map(&.to_i)
puts div_ceil(b-1, a-1)
```

出来上がり。
メソッド定義はC++の様に必ずしも前置である必要はなく、後置でもいける。

```crystal:abc139_b.cr
a, b = read_line.split.map(&.to_i)
puts div_ceil(b-1, a-1)

def div_ceil(x, y)
  (x+y-1) // y
end
```

[^1]: https://ja.crystal-lang.org/reference/syntax_and_semantics/the_program.html
[^2]: https://crystal-lang.org/api/1.0.0/IO.html#read_line(*args,**options):String-instance-method