day01.gleam

 1import gleam/int
 2import gleam/list
 3import gleam/result
 4import gleam/string
 5
 6const starting_position = 50
 7
 8pub type Movement {
 9  Left(Int)
10  Right(Int)
11}
12
13pub fn part1(input: List(String)) -> Int {
14  let movements = input |> list.filter_map(parse_movement)
15  let #(zero_count, _final_pos) =
16    list.fold(movements, #(0, starting_position), fn(acc, movement) {
17      let #(count, pos) = acc
18      let new_pos = apply_movement(pos, movement)
19      let new_count = case new_pos {
20        0 -> count + 1
21        _ -> count
22      }
23      #(new_count, new_pos)
24    })
25  zero_count
26}
27
28pub fn part2(input: List(String)) -> Int {
29  let movements = input |> list.filter_map(parse_movement)
30  let #(zero_count, _final_pos) =
31    list.fold(movements, #(0, starting_position), fn(acc, movement) {
32      let #(count, pos) = acc
33      let new_pos = apply_movement(pos, movement)
34      let zeroes = zeroes_hit(pos, movement)
35      #(count + zeroes, new_pos)
36    })
37  zero_count
38}
39
40pub fn parse_movement(input: String) -> Result(Movement, Nil) {
41  case string.first(input) {
42    Ok("L") ->
43      input
44      |> string.drop_start(1)
45      |> int.parse
46      |> result.map(Left)
47    Ok("R") ->
48      input
49      |> string.drop_start(1)
50      |> int.parse
51      |> result.map(Right)
52    _ -> Error(Nil)
53  }
54}
55
56fn apply_movement(position: Int, movement: Movement) -> Int {
57  let new_pos = case movement {
58    Left(n) -> position - n
59    Right(n) -> position + n
60  }
61  // Wrap around 0-99 (100 positions)
62  { { new_pos % 100 } + 100 } % 100
63}
64
65fn zeroes_hit(position: Int, movement: Movement) -> Int {
66  let #(steps, going_right) = case movement {
67    Left(n) -> #(n, False)
68    Right(n) -> #(n, True)
69  }
70
71  case going_right {
72    True -> {
73      // Right: hit 0 when (position + k) % 100 == 0
74      let first_hit = { 100 - position } % 100
75      case first_hit {
76        0 -> steps / 100
77        f if f <= steps -> { steps - f } / 100 + 1
78        _ -> 0
79      }
80    }
81    False -> {
82      // Left: hit 0 when (position - k) % 100 == 0, i.e., k == position
83      case position {
84        0 -> steps / 100
85        p if p <= steps -> { steps - p } / 100 + 1
86        _ -> 0
87      }
88    }
89  }
90}