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()
}
|