this repo has no description
1import gleam/dict
2import gleam/function
3import gleam/io
4import gleam/list
5import gleam/result
6import gleam/set
7import gleam/string
8import simplifile
9import utils/utils
10
11type Type {
12 Tachion
13 Splitter
14}
15
16type Position {
17 Position(x: Int)
18}
19
20type Cell {
21 Cell(pos: Position, typ: Type)
22}
23
24pub fn start() -> Nil {
25 let assert Ok(content) = simplifile.read("inputs/day7.txt")
26 let data = parse(content)
27
28 let _ = io.debug(part1(data))
29 let _ = io.debug(part2(data))
30
31 Nil
32}
33
34fn parse(data: String) {
35 string.split(data, "\n")
36 |> list.index_map(fn(l, _) {
37 list.index_map(string.to_graphemes(l), fn(c, x) {
38 case c {
39 "S" -> Ok(Cell(Position(x), Tachion))
40 "^" -> Ok(Cell(Position(x), Splitter))
41
42 // Should never happen
43 _ -> Error(Nil)
44 }
45 })
46 |> list.filter_map(function.identity)
47 })
48 |> list.filter(fn(x) { !list.is_empty(x) })
49}
50
51type Res {
52 Res(splits: Int, tachions: List(Cell))
53}
54
55fn part1(data: List(List(Cell))) {
56 let res =
57 list.fold(data, Res(0, []), fn(acc, cells_on_line) {
58 let new_tachions =
59 list.map(cells_on_line, fn(c) {
60 case c.typ {
61 Tachion -> #([c], 0, [])
62 Splitter -> {
63 let Position(cx) = c.pos
64 case list.find(acc.tachions, fn(x) { x.pos.x == cx }) {
65 Ok(c) -> #(
66 [
67 Cell(Position(cx - 1), Tachion),
68 Cell(Position(cx + 1), Tachion),
69 ],
70 1,
71 [c],
72 )
73 Error(_) -> #([], 0, [])
74 }
75 }
76 }
77 })
78
79 let used_tachions =
80 list.fold(new_tachions, [], fn(acc, x) { [x.2, ..acc] })
81 |> list.flatten
82 |> list.fold(set.new(), set.insert)
83 |> set.to_list
84
85 let new_splits =
86 acc.splits + list.fold(new_tachions, 0, fn(acc, t) { acc + t.1 })
87
88 let new_tachions =
89 list.map(new_tachions, fn(x) { x.0 })
90 |> list.filter(fn(x) { !list.is_empty(x) })
91 |> list.flatten
92
93 let tachions =
94 list.filter(acc.tachions, fn(x) { !list.contains(used_tachions, x) })
95 |> list.append(new_tachions)
96 |> list.fold(set.new(), set.insert)
97 |> set.to_list
98
99 Res(new_splits, tachions)
100 })
101
102 res.splits
103}
104
105type Cache =
106 dict.Dict(#(Int, Int), Int)
107
108fn rec(
109 line: Int,
110 next: List(List(Cell)),
111 depth: Int,
112 cache: Cache,
113) -> #(Int, Cache) {
114 let next_splitter =
115 utils.list_find_indexes(next, fn(x) {
116 result.is_ok(list.find(x, fn(y) { y.pos.x == line && y.typ == Splitter }))
117 })
118 |> list.filter(fn(x) { x > depth })
119 |> list.first()
120
121 case next_splitter {
122 Ok(lidx) -> {
123 let assert Ok(l) = list.drop(next, lidx) |> list.first
124 let assert Ok(splitter) =
125 list.find(l, fn(y) { y.pos.x == line && y.typ == Splitter })
126
127 // Check left Side
128 let #(left, cache) = case
129 dict.has_key(cache, #(splitter.pos.x - 1, lidx))
130 {
131 True -> {
132 let assert Ok(v) = dict.get(cache, #(splitter.pos.x - 1, lidx))
133 #(v, cache)
134 }
135 False -> rec(splitter.pos.x - 1, next, lidx, cache)
136 }
137 let cache = dict.insert(cache, #(splitter.pos.x - 1, lidx), left)
138
139 // Check right Side
140 let #(right, cache) = case
141 dict.has_key(cache, #(splitter.pos.x + 1, lidx))
142 {
143 True -> {
144 let assert Ok(v) = dict.get(cache, #(splitter.pos.x + 1, lidx))
145 #(v, cache)
146 }
147 False -> rec(splitter.pos.x + 1, next, lidx, cache)
148 }
149 let cache = dict.insert(cache, #(splitter.pos.x + 1, lidx), right)
150
151 #(left + right, cache)
152 }
153 Error(_) -> #(1, cache)
154 }
155}
156
157fn part2(data: List(List(Cell))) {
158 let assert Ok(fl) = list.first(data)
159 let assert Ok(t) = list.first(fl)
160 rec(t.pos.x, data, 0, dict.new()).0
161}