スクラッチカードの得点計算。
part2はメタ的で少し特殊
## 方針
実際に問題を解くのに必要なのは「各カードでmatchしている個数」の情報だけ。
事前に各行でそのカウントを計算してしまうと良い。
part1はそれぞれmatch数から `0, 1, 2, 4, 8, 16` に変換できればあとは足すだけ。
part2はポイントではなくmatch数だけ後続のカードがコピーされ増える、というもの。
これは初期状態ですべて`1`になっている配列を用意し、カードを順に見ていく中で「matchした数だけそのカード枚数を後続の要素に足し込んでいく」という操作で計算できる。
末尾に到達している場合は切り捨てる必要があるが、この問題も入力が調整されて作られているようで、実際には切り捨てる必要のあるものは出てこないようだ。
## 実装
### Rust
1行ずつparseし、matchした数だけ保持しておく。
part1は `1 << n >> 1` でポイントを計算できる。
```rust
struct Solution {
    matches: Vec<usize>,
}
impl Solution {
	...
	fn part1(&self) -> u32 {
        self.matches.iter().map(|n| 1 << n >> 1).sum()
    }
    fn part2(&self) -> u32 {
        let mut v = vec![1; self.matches.len()];
        for (i, n) in self.matches.iter().enumerate() {
            for j in i + 1..(i + 1 + *n).min(v.len()) {
                v[j] += v[i];
            }
        }
        v.iter().sum()
    }
}
```
### Python
matchする数だけが必要なので`int`に変換する必要もなく、単に`str.split()`した結果の集合を使ってカウントを求めることができる。
この場合、実は`":"`でsplitする必要もなく、左側に`Card 13:` のようなものが残っていても `["Card", "13:", ...]`のようにカード番号は`":"`つきで取得されるため集合の計算では上手く除外される。
```python
    def __init__(self, io: TextIO) -> None:
        def match_count(s: str) -> int:
            winning, have = map(str.split, s.split(":")[1].split("|"))
            return len(set(winning) & set(have))
        self.matches = list(map(match_count, io))
```
### OCaml
parseは分割した後にそれぞれ`int list`に変換し、`List.mem ~equal`でカウント。高々5要素のListからの探索なのでこれで十分。
```ocaml
  let parse input =
    let match_count line =
      let to_int_list s =
        String.split s ~on:' '
        |> List.filter ~f:(Fn.non String.is_empty)
        |> List.map ~f:Int.of_string
      in
      String.lsplit2_exn line ~on:':' |> snd |> String.lsplit2_exn ~on:'|'
      |> fun (winning, have) ->
      let w = winning |> to_int_list in
      have |> to_int_list |> List.count ~f:(List.mem w ~equal)
    in
    In_channel.input_lines input |> List.map ~f:match_count
```
part2は`Array`を使うことになる。
```ocaml
  let part2 matches =
    let a = Array.create ~len:(List.length matches) 1 in
    List.iteri matches ~f:(fun i x ->
        List.range (i + 1) (i + 1 + x)
        |> List.iter ~f:(fun j -> a.(j) <- a.(j) + a.(i)));
    Array.fold a ~init:0 ~f:( + ) |> Answer.of_int
```