-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday_04.gleam
76 lines (64 loc) · 1.78 KB
/
day_04.gleam
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
import gleam/bool
import gleam/dict
import gleam/int
import gleam/list
import gleam/option.{type Option}
import gleam/set
import gleam/string
pub fn part_1(input: String) -> Int {
let matching_numbers = count_matching_numbers(input)
matching_numbers
|> list.fold(0, fn(sum, count) {
case count {
0 -> sum
n -> sum + int_pow(2, exponent: n - 1)
}
})
}
pub fn part_2(input: String) -> Int {
let matching_numbers = count_matching_numbers(input)
matching_numbers
|> list.index_fold(
dict.new(),
fn(card_counts, matching_numbers_count, game_index) {
let card_counts = card_counts |> dict.upsert(game_index, inc(_, by: 1))
use <- bool.guard(when: matching_numbers_count == 0, return: card_counts)
let assert Ok(current_card_count) = card_counts |> dict.get(game_index)
list.range(game_index + 1, game_index + 1 + matching_numbers_count - 1)
|> list.fold(card_counts, fn(card_counts, game_index) {
card_counts |> dict.upsert(game_index, inc(_, by: current_card_count))
})
},
)
|> dict.values
|> int.sum
}
fn count_matching_numbers(input: String) -> List(Int) {
input
|> string.trim
|> string.split("\n")
|> list.map(fn(line) {
let assert [winning_numbers, elfs_numbers] =
line
|> string.split(" | ")
|> list.map(number_list_to_numbers)
|> list.map(set.from_list)
set.intersection(winning_numbers, elfs_numbers)
|> set.size
})
}
fn number_list_to_numbers(list: String) -> List(Int) {
list
|> string.split(" ")
|> list.filter_map(int.parse)
}
fn int_pow(base: Int, exponent exponent: Int) -> Int {
case exponent {
0 -> 1
1 -> base
_ -> base * int_pow(base, exponent - 1)
}
}
fn inc(opt: Option(Int), by by: Int) -> Int {
{ opt |> option.unwrap(0) } + by
}