aboutsummaryrefslogtreecommitdiff
path: root/aoc2017-gleam/src/aoc_2017/day_10.gleam
blob: 676e0ee2b43dbd200b6fc539515d28b41e1559ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import gleam/int
import gleam/list
import gleam/result
import gleam/string

const size = 256

const suffix = [17, 31, 73, 47, 23]

fn parse_as_numbers(input: String) {
  input
  |> string.split(",")
  |> list.map(int.parse)
  |> result.values()
}

fn parse_as_bytes(input: String) {
  input
  |> string.to_utf_codepoints
  |> list.map(string.utf_codepoint_to_int)
  |> list.append(suffix)
}

pub fn pt_1(input: String) {
  let twisted = twist(list.range(0, size - 1), parse_as_numbers(input), 0, 0)

  let assert #([first, second, ..], _, _) = twisted
  first * second
}

pub fn pt_2(input: String) {
  megatwist(list.range(0, size - 1), parse_as_bytes(input), 0, 0, 64)
  |> list.sized_chunk(16)
  |> list.map(fold_xor)
  |> string.concat()
}

fn twist(loop: List(Int), lengths: List(Int), skip: Int, index: Int) {
  case lengths {
    [] -> #(loop, skip, index)
    [l, ..ls] ->
      loop
      |> roll(index)
      |> flip(l)
      |> roll({ size - index } % size)
      |> twist(ls, skip + 1, { index + l + skip } % size)
  }
}

fn megatwist(loop, lengths, skip, index, iterations) {
  case iterations {
    0 -> loop
    n -> {
      let #(next_loop, next_skip, next_index) =
        twist(loop, lengths, skip, index)
      megatwist(next_loop, lengths, next_skip, next_index, n - 1)
    }
  }
}

fn roll(list: List(a), by: Int) {
  let #(left, right) = list.split(list, by % size)
  list.append(right, left)
}

fn flip(list: List(a), length: Int) {
  let #(left, right) = list.split(list, length)
  list.append(list.reverse(left), right)
}

fn fold_xor(xs: List(Int)) {
  let assert Ok(n) = list.reduce(xs, int.bitwise_exclusive_or)
  n
  |> int.to_base16()
  |> string.pad_left(to: 2, with: "0")
  |> string.lowercase()
}