aboutsummaryrefslogtreecommitdiff
path: root/aoc2017-gleam/src/aoc_2017/day_14.gleam
blob: 2a7491294d3587a3f0e97908c3034fed09e398b3 (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
78
79
80
81
82
import aoc_2017/day_10.{pt_2 as knot}
import gleam/int
import gleam/list
import gleam/result
import gleam/set
import gleam/string
import helpers/set_state

pub fn pt_1(input: String) {
  use acc, row <- list.fold(make_rows(input), 0)
  let count = row |> knot() |> popcount()
  acc + count
}

fn make_rows(input: String) {
  use row <- list.map(list.range(0, 127))
  input <> "-" <> int.to_string(row)
}

fn popcount(hex_number: String) -> Int {
  let assert Ok(n) = int.base_parse(hex_number, 16)
  let assert Ok(digits) = int.digits(n, 2)

  use acc, digit <- list.fold(digits, 0)
  case digit {
    1 -> acc + 1
    _ -> acc
  }
}

pub fn pt_2(input: String) {
  let grid = set_state.start_actor(make_grid(input))

  find_next_group(grid, 0)
}

fn make_grid(input: String) {
  let raw_grid =
    list.map(make_rows(input), fn(row) {
      row
      |> knot()
      |> int.base_parse(16)
      |> result.map(int.to_base2)
      |> result.map(string.pad_left(_, with: "0", to: 128))
      |> result.map(string.to_graphemes)
    })
    |> result.values

  {
    use total_acc, row, i <- list.index_fold(raw_grid, set.new())
    use acc, bit, j <- list.index_fold(row, total_acc)
    case bit {
      "1" -> set.insert(acc, #(i, j))
      _zero -> acc
    }
  }
}

fn find_next_group(actor, count) {
  case set_state.pop(actor) {
    Ok(p) -> {
      list.each(neighbors(p), remove_neighbor(actor, _))
      find_next_group(actor, count + 1)
    }
    Error(Nil) -> count
  }
}

fn neighbors(of: #(Int, Int)) {
  let #(i, j) = of
  [#(i + 1, j), #(i - 1, j), #(i, j + 1), #(i, j - 1)]
}

fn remove_neighbor(actor, point) {
  case set_state.check(actor, point) {
    True -> {
      set_state.drop(actor, point)
      list.each(neighbors(point), remove_neighbor(actor, _))
    }
    False -> Nil
  }
}