+1
-1
2023/day04.livemd
+1
-1
2023/day04.livemd
···
196
196
10378710
197
197
```
198
198
199
-
<!-- livebook:{"offset":11578,"stamp":{"token":"XCP.lXGe3Iu191OYuBQqrLXtyX10eAJRxaC7kWxJhXV-XwPuZXy80YHtfPI-uAobs5Ncg0KyodauGARY5zWPhVt6a96P5flHG1j0LHMDzRblFBObyqrIKaYaIlaYVVUXUtasrA","version":2}} -->
199
+
<!-- livebook:{"offset":11578,"stamp":{"token":"XCP.MkFlr54HtUrLxNpCiRslp5uHY2WvhZ1VtV-O2Kmdgys3ejH3O0uJAEJe8o8FxytUQyFTMJeefRatVMyr9J3CU3x5R4g7Ie-s_vb0vC-AepFre8COUMkA6Ws70S_FqoCSbA","version":2}} -->
+69
-318
2023/day05.livemd
+69
-318
2023/day05.livemd
···
3
3
# Day 05
4
4
5
5
```elixir
6
-
Mix.install([:kino_aoc, {:range_set, path: "../range_set"}])
6
+
Mix.install([:kino_aoc, {:range_set, github: "hauleth/range_set"}])
7
7
```
8
8
9
9
## Parse
···
23
23
```
24
24
25
25
```elixir
26
-
puzzle_input =
27
-
"""
28
-
seeds: 79 14 55 13
26
+
# puzzle_input =
27
+
"""
28
+
seeds: 79 14 55 13
29
29
30
-
seed-to-soil map:
31
-
50 98 2
32
-
52 50 48
30
+
seed-to-soil map:
31
+
50 98 2
32
+
52 50 48
33
33
34
-
soil-to-fertilizer map:
35
-
0 15 37
36
-
37 52 2
37
-
39 0 15
34
+
soil-to-fertilizer map:
35
+
0 15 37
36
+
37 52 2
37
+
39 0 15
38
38
39
-
fertilizer-to-water map:
40
-
49 53 8
41
-
0 11 42
42
-
42 0 7
43
-
57 7 4
39
+
fertilizer-to-water map:
40
+
49 53 8
41
+
0 11 42
42
+
42 0 7
43
+
57 7 4
44
44
45
-
water-to-light map:
46
-
88 18 7
47
-
18 25 70
45
+
water-to-light map:
46
+
88 18 7
47
+
18 25 70
48
48
49
-
light-to-temperature map:
50
-
45 77 23
51
-
81 45 19
52
-
68 64 13
49
+
light-to-temperature map:
50
+
45 77 23
51
+
81 45 19
52
+
68 64 13
53
53
54
-
temperature-to-humidity map:
55
-
0 69 1
56
-
1 0 69
54
+
temperature-to-humidity map:
55
+
0 69 1
56
+
1 0 69
57
57
58
-
humidity-to-location map:
59
-
60 56 37
60
-
56 93 4
61
-
"""
62
-
|> String.trim()
58
+
humidity-to-location map:
59
+
60 56 37
60
+
56 93 4
61
+
"""
62
+
|> String.trim()
63
63
```
64
64
65
65
<!-- livebook:{"output":true} -->
···
72
72
defmodule Mapping do
73
73
@behaviour Access
74
74
75
+
import Kernel, except: [apply: 2]
76
+
75
77
defstruct [:values]
76
78
77
79
def from_list(lst) do
78
-
# true = Enum.all?(lst, fn {a, b} -> Range.size(a) == Range.size(b) end)
79
80
%__MODULE__{values: Enum.sort(lst)}
80
81
end
81
82
82
-
def squash(%__MODULE__{values: from}, %__MODULE__{values: to}) do
83
-
from_list(do_squash(from, to))
84
-
end
85
-
86
-
defp do_squash([], rest), do: rest
87
-
defp do_squash(rest, []), do: rest
88
-
89
-
# a---b
90
-
# c---d
91
-
defp do_squash([{_src, a.._b} | _] = xs, [{_c..d, _out} = v | ys]) when d < a do
92
-
[v | do_squash(xs, ys)]
93
-
end
94
-
95
-
# a---b
96
-
# c---d
97
-
defp do_squash([{_src, _a..b} = v | xs], [{c.._d, _out} | _] = ys) when b < c do
98
-
[v | do_squash(xs, ys)]
99
-
end
100
-
101
-
# a---b
102
-
# c---d
103
-
defp do_squash([{src, range} | xs], [{range, out} | ys]) do
104
-
[{src, out} | do_squash(xs, ys)]
105
-
end
83
+
defp apply({a.._, to}, v), do: v - a + to
106
84
107
-
# a------b
108
-
# c--d
109
-
defp do_squash([{src, a..b} | xs], [{c..d, out} | ys]) when a <= c and b >= d do
110
-
range_match(src, [
111
-
a..(c - 1),
112
-
out,
113
-
(d + 1)..b
114
-
])
115
-
|> Enum.concat(do_squash(xs, ys))
85
+
@impl Access
86
+
def fetch(%__MODULE__{values: list}, key) when is_integer(key) do
87
+
{:ok, sorted_find(list, key)}
116
88
end
117
89
118
-
# a--b
119
-
# c------d
120
-
defp do_squash([{src, a..b} | xs], [{c..d, out} | ys]) when a >= c and b <= d do
121
-
range_match(
122
-
[
123
-
c..(a - 1),
124
-
src,
125
-
(b + 1)..d
126
-
],
127
-
out
128
-
)
129
-
|> Enum.concat(do_squash(xs, ys))
90
+
def fetch(%__MODULE__{values: map}, %RangeSet{ranges: ranges}) do
91
+
ranges
92
+
|> Enum.flat_map(&map_range(&1, map))
93
+
|> RangeSet.new()
94
+
|> then(&{:ok, &1})
130
95
end
131
96
132
-
# a---b
133
-
# c---d
134
-
defp do_squash([{src, a..b} | xs], [{c..d, out} | ys]) when c in a..b and b in c..d do
135
-
{s1, s2} = Range.split(src, Range.size(a..c) - 1)
136
-
{o1, o2} = Range.split(out, Range.size(c..b))
97
+
defp sorted_find([], n), do: n
98
+
defp sorted_find([{a..b, _} = result | _], n) when n in a..b, do: apply(result, n)
99
+
defp sorted_find([{a.._, _} | _], n) when n < a, do: n
100
+
defp sorted_find([_ | rest], n), do: sorted_find(rest, n)
137
101
138
-
[
139
-
{s1, a..(c - 1)},
140
-
{s2, o1},
141
-
{(b + 1)..d, o2}
142
-
]
143
-
|> Enum.concat(do_squash(xs, ys))
144
-
end
102
+
defp map_range(range, []), do: [range]
103
+
defp map_range(_..hi = range, [{lo.._, _} | _]) when lo > hi, do: [range]
104
+
defp map_range(lo.._ = range, [{_..hi, _} | rest]) when lo > hi, do: map_range(range, rest)
145
105
146
-
# a---b
147
-
# c---d
148
-
defp do_squash([{src, a..b} | xs], [{c..d, out} | ys]) when a > c and b > d do
149
-
IO.puts("foo")
150
-
{of, ol} = Range.split(out, Range.size(c..a) - 1)
151
-
{sf, sl} = Range.split(src, Range.size(a..d))
106
+
defp map_range(arg_range, [{fun_range, _} = fun_def | maps]) do
107
+
fun_lo..fun_hi = fun_range
108
+
arg_lo..arg_hi = arg_range
109
+
lo = max(fun_lo, arg_lo)
110
+
hi = min(fun_hi, arg_hi)
152
111
153
112
[
154
-
{c..(a - 1), of},
155
-
{sf, ol},
156
-
{sl, (d + 1)..b}
113
+
apply(fun_def, lo)..apply(fun_def, hi)
114
+
| if(hi < arg_hi, do: map_range((hi + 1)..arg_hi, maps), else: [])
157
115
]
158
-
|> Enum.concat(do_squash(xs, ys))
159
-
end
160
-
161
-
defp range_match(list, a.._) when is_list(list) do
162
-
Enum.reduce(list, {[], a}, fn
163
-
_.._//1 = range, {acc, s} ->
164
-
to = s + Range.size(range) - 1
165
-
{[{range, s..to} | acc], to + 1}
166
-
167
-
_, acc ->
168
-
acc
169
-
end)
170
-
|> elem(0)
171
-
end
172
-
173
-
defp range_match(_.._ = range, list) when is_list(list) do
174
-
for {a, b} <- range_match(list, range), do: {b, a}
175
-
end
176
-
177
-
@impl Access
178
-
def fetch(%__MODULE__{values: list}, key) when is_integer(key) do
179
-
val =
180
-
with {a.._, b.._} <- Enum.find(list, key, fn {range, _} -> key in range end) do
181
-
key - a + b
182
-
end
183
-
184
-
{:ok, val}
185
116
end
186
117
end
187
118
···
198
129
|> Enum.map(&String.split/1)
199
130
|> Enum.map(fn line ->
200
131
[to, from, len] = Enum.map(line, &String.to_integer/1)
201
-
{from..(from + len - 1), to..(to + len - 1)}
132
+
{from..(from + len - 1), to}
202
133
end)
203
134
|> Mapping.from_list()
204
135
end)
205
-
206
-
[seed2soil, soil2fert, fert2water, water2light, light2temp, temp2hum, hum2loc] = mappings
207
136
208
137
seeds =
209
138
seeds
···
226
155
<!-- livebook:{"output":true} -->
227
156
228
157
```
229
-
[79, 14, 55, 13]
230
-
```
231
-
232
-
```elixir
233
-
a = Mapping.from_list([{1..10, 31..40}])
234
-
b = Mapping.from_list([{25..35, 65..75}])
235
-
236
-
k = 30
237
-
238
-
dbg(b[dbg(a[k])])
239
-
dbg(Mapping.squash(a, b))[k]
240
-
```
241
-
242
-
<!-- livebook:{"output":true} -->
243
-
244
-
```
245
-
30
246
-
```
247
-
248
-
<!-- livebook:{"output":true} -->
249
-
250
-
```
251
-
70
252
-
```
253
-
254
-
<!-- livebook:{"output":true} -->
255
-
256
-
```
257
-
foo
258
-
```
259
-
260
-
<!-- livebook:{"output":true} -->
261
-
262
-
```
263
-
%Mapping{values: [{1..5, 71..75}, {6..10, 36..40}, {25..30, 65..70}]}
264
-
```
265
-
266
-
<!-- livebook:{"output":true} -->
267
-
268
-
```
269
-
70
158
+
[1310704671, 312415190, 1034820096, 106131293, 682397438, 30365957, 2858337556, 1183890307,
159
+
665754577, 13162298, 2687187253, 74991378, 1782124901, 3190497, 208902075, 226221606, 4116455504,
160
+
87808390, 2403629707, 66592398]
270
161
```
271
162
272
163
## Part 1
···
280
171
<!-- livebook:{"output":true} -->
281
172
282
173
```
283
-
35
284
-
```
285
-
286
-
```elixir
287
-
squashed = Enum.reduce(mappings, &Mapping.squash/2)
174
+
51752125
288
175
```
289
176
290
-
<!-- livebook:{"output":true} -->
291
-
292
-
```
293
-
foo
294
-
foo
295
-
foo
296
-
```
297
-
298
-
<!-- livebook:{"output":true} -->
299
-
300
-
```
301
-
%Mapping{
302
-
values: [
303
-
{0..0, 27..27},
304
-
{0..5, 28..33},
305
-
{1..10, 40..49},
306
-
{6..59, 7..60},
307
-
{7..10, 59..62},
308
-
{11..14, 52..55},
309
-
{11..52, 0..41},
310
-
{15..41, 0..26},
311
-
{18..24, 90..96},
312
-
{25..55, 18..48},
313
-
{45..58, 74..87},
314
-
{49..51, 34..36},
315
-
{52..53, 37..38},
316
-
{53..60, 49..56},
317
-
{54..56, 56..58},
318
-
{56..64, 61..69},
319
-
{59..63, 95..99},
320
-
{60..80, 53..73},
321
-
{61..67, 63..69},
322
-
{64..76, 70..82},
323
-
{65..92, 69..96},
324
-
{69..69, 39..39},
325
-
{77..99, 45..67},
326
-
{81..87, 83..89},
327
-
{93..96, 49..52},
328
-
{95..97, 97..99},
329
-
{98..99, 50..51}
330
-
]
331
-
}
332
-
```
177
+
## Part 2
333
178
334
179
```elixir
335
180
seeds
336
-
|> Enum.map(&squashed[&1])
337
-
|> Enum.min()
181
+
|> Enum.chunk_every(2)
182
+
|> Enum.map(fn [start, length] -> start..(start + length - 1) end)
183
+
|> RangeSet.new()
184
+
|> then(&Enum.reduce(mappings, &1, fn map, r -> map[r] end))
185
+
|> RangeSet.min()
338
186
```
339
187
340
188
<!-- livebook:{"output":true} -->
341
189
342
190
```
343
-
14
191
+
12634632
344
192
```
345
193
346
-
```elixir
347
-
Enum.map(seeds, &squashed[&1])
348
-
```
349
-
350
-
<!-- livebook:{"output":true} -->
351
-
352
-
```
353
-
[72, 15, 56, 14]
354
-
```
355
-
356
-
```elixir
357
-
seeds =
358
-
Enum.chunk_every(seeds, 2)
359
-
|> Enum.map(fn [a, b] -> a..(a + b) end)
360
-
|> RangeSet.new()
361
-
362
-
mappings
363
-
|> Enum.reduce(seeds, fn map, curr ->
364
-
IO.puts("")
365
-
IO.inspect(map, label: :map)
366
-
IO.inspect(curr, label: :curr)
367
-
inputs = RangeSet.new(for {from, _} <- map.values, do: from)
368
-
mapped = IO.inspect(RangeSet.intersection(inputs, curr), label: :inter)
369
-
left = IO.inspect(RangeSet.difference(curr, mapped), label: :diff)
370
-
371
-
mapped =
372
-
mapped.ranges
373
-
|> Enum.map(fn a..b -> map[a]..map[b]//1 end)
374
-
|> RangeSet.new()
375
-
|> IO.inspect(label: :mapped)
376
-
377
-
IO.inspect(RangeSet.union(left, mapped))
378
-
end)
379
-
```
380
-
381
-
<!-- livebook:{"output":true} -->
382
-
383
-
```
384
-
385
-
map: %Mapping{values: [{50..97, 52..99}, {98..99, 50..51}]}
386
-
curr: RangeSet.new([55..68, 79..93])
387
-
inter: RangeSet.new([55..68, 79..93])
388
-
diff: RangeSet.new([])
389
-
mapped: RangeSet.new([57..70, 81..95])
390
-
RangeSet.new([57..70, 81..95])
391
-
392
-
map: %Mapping{values: [{0..14, 39..53}, {15..51, 0..36}, {52..53, 37..38}]}
393
-
curr: RangeSet.new([57..70, 81..95])
394
-
inter: RangeSet.new([])
395
-
diff: RangeSet.new([57..70, 81..95])
396
-
mapped: RangeSet.new([])
397
-
RangeSet.new([57..70, 81..95])
398
-
399
-
map: %Mapping{
400
-
values: [{0..6, 42..48}, {7..10, 57..60}, {11..52, 0..41}, {53..60, 49..56}]
401
-
}
402
-
curr: RangeSet.new([57..70, 81..95])
403
-
inter: RangeSet.new([57..60])
404
-
diff: RangeSet.new([61..70, 81..95])
405
-
mapped: RangeSet.new([53..56])
406
-
RangeSet.new([53..56, 61..70, 81..95])
407
-
408
-
map: %Mapping{values: [{18..24, 88..94}, {25..94, 18..87}]}
409
-
curr: RangeSet.new([53..56, 61..70, 81..95])
410
-
inter: RangeSet.new([53..56, 61..70, 81..94])
411
-
diff: RangeSet.new([95..95])
412
-
mapped: RangeSet.new([46..49, 54..63, 74..87])
413
-
RangeSet.new([46..49, 54..63, 74..87, 95..95])
414
-
415
-
map: %Mapping{values: [{45..63, 81..99}, {64..76, 68..80}, {77..99, 45..67}]}
416
-
curr: RangeSet.new([46..49, 54..63, 74..87, 95..95])
417
-
inter: RangeSet.new([46..49, 54..63, 74..76, 77..87, 95..95])
418
-
diff: RangeSet.new([])
419
-
mapped: RangeSet.new([45..55, 63..63, 78..80, 82..85, 90..99])
420
-
RangeSet.new([45..55, 63..63, 78..80, 82..85, 90..99])
421
-
422
-
map: %Mapping{values: [{0..68, 1..69}, {69..69, 0..0}]}
423
-
curr: RangeSet.new([45..55, 63..63, 78..80, 82..85, 90..99])
424
-
inter: RangeSet.new([45..55, 63..63])
425
-
diff: RangeSet.new([78..80, 82..85, 90..99])
426
-
mapped: RangeSet.new([46..56, 64..64])
427
-
RangeSet.new([46..56, 64..64, 78..80, 82..85, 90..99])
428
-
429
-
map: %Mapping{values: [{56..92, 60..96}, {93..96, 56..59}]}
430
-
curr: RangeSet.new([46..56, 64..64, 78..80, 82..85, 90..99])
431
-
```
432
-
433
-
```elixir
434
-
light2temp[74]
435
-
```
436
-
437
-
<!-- livebook:{"output":true} -->
438
-
439
-
```
440
-
78
441
-
```
442
-
443
-
<!-- livebook:{"offset":13391,"stamp":{"token":"XCP.YBvV3LijXOIMnujrbQ1UcVgKkKIgzTxWiEVKN6_kRQO7Z54rqDRPZT7cgjsENw1cakYqdxjdW8l0ZieLojSPU1k_oMLqBh0-YpWLbT9dUfZRNKIxmeQgwwCEGOzZ2hdsVw","version":2}} -->
194
+
<!-- livebook:{"offset":8450,"stamp":{"token":"XCP.9I0OWZix2U9jQ5DLHq6aPMZLzaSvoWmFrdBbv9pxQfaL_IHSsv0UiMHQgeLV96EpUjfWS_hLXKNfPjSWsmdceQyf2OEIe1gAC7o2oOp3S4I9UlfKFypRqLfs3Jo6p-UtGQ","version":2}} -->