diff --git a/.envrc b/.envrc index c5c9403..ddaf6a2 100644 --- a/.envrc +++ b/.envrc @@ -1,5 +1,5 @@ export DIRENV_WARN_TIMEOUT=20s -eval "$(devenv direnvrc)" +# eval "$(devenv direnvrc)" -use flake --no-pure-eval +use flake . --no-pure-eval diff --git a/solutions/05.sql b/solutions/05.sql new file mode 100644 index 0000000..7277125 --- /dev/null +++ b/solutions/05.sql @@ -0,0 +1,82 @@ +create or replace table day05_data as + select + if('-' in column0, SPLIT(column0, '-')[1]::long, NULL) as range_start, + if('-' in column0, SPLIT(column0, '-')[2]::long, NULL) as range_end, + if('-' not in column0, column0::long, NULL) as product_id + from read_csv( + 'inputs/05/input.txt', + header = false) + where (range_start is not null and range_end is not null) or product_id is not null +; + +create or replace table day05_test as + select + if('-' in column0, SPLIT(column0, '-')[1]::long, NULL) as range_start, + if('-' in column0, SPLIT(column0, '-')[2]::long + 1, NULL) as range_end, + if('-' not in column0, column0::long, NULL) as product_id + from read_csv( + 'inputs/05/test.txt', + header = false) + where (range_start is not null and range_end is not null) or product_id is not null +; + +create or replace table day05_ranges as + select row_number() over (order by range_start) as range_id, range_start, range_end + from day05_data + where product_id is null; +create or replace table day05_products as + select product_id + from day05_data + where product_id is not null; + +select count(distinct product_id) as part1 +from day05_products +inner join day05_ranges + on product_id between range_start and range_end +; + +create or replace table day05_cleaned_ranges as +with recursive seq(step, range_id, range_start, range_end) as ( + select 0 as step, + range_id, + range_start, + range_end + from day05_ranges + + union all ( + + with res as ( + select distinct + s1.step + 1 as step, + list_min([s1.range_start::long, coalesce(s2.range_start, s1.range_start)]) as range_start, + list_max([s1.range_end, coalesce(s2.range_end, s1.range_end)]) as range_end, + s2.step is not null as changed_smth + from seq s1 + left join seq s2 + on s1.range_id != s2.range_id and + (s1.range_start between s2.range_start and s2.range_end + or s1.range_end between s2.range_start and s2.range_end) + order by range_start + ) + select + step, + row_number() over () as range_id, + range_start, + range_end + from res + where (select count(1) filter (where changed_smth is true) from res) > 0 + and step < 20 + group by step, range_start, range_end +)) +select * +from seq; +; + +select * +from day05_cleaned_ranges +order by step, range_start; + +select sum(range_end - range_start) as part2 +from day05_cleaned_ranges +where step = (select max(step) from day05_cleaned_ranges); + diff --git a/solutions/06.sql b/solutions/06.sql new file mode 100644 index 0000000..956de1e --- /dev/null +++ b/solutions/06.sql @@ -0,0 +1,78 @@ +create or replace table day06_data as + select row_number() over () as line, column0 + from read_csv('inputs/06/input.txt', header=false, delim='\n'); +create or replace table day06_test as + select row_number() over () as line, column0 + from read_csv('inputs/06/test.txt', header=false, delim='\n'); + + +create or replace table day06_input as + with raw as ( + select line as y, + array_filter(split(column0, ' '), lambda x: x != '') as s + from day06_data + ), splitted as ( + select x, y, elem + from raw, + unnest(s) with ordinality as u(elem, x) + ), rotated as ( + select array_agg(elem order by y) as rot + from splitted + group by x + ) + select rot[-1] as op, list_apply(rot[:-2], lambda x: x::int) as num + from rotated; + +select sum( + case when op = '+' then list_sum(num) + when op = '*' then list_product(num) + else 0 + end +)::long as part1 +from day06_input; + +create or replace table day06_input2 as + with rotated as ( + select + x, + array_agg(elem order by line) rot + from day06_data, + unnest(split(column0, '')) with ordinality as u(elem, x) + group by x + order by x + ), cleaned as ( + select + x, + any_value(rot[-1]) as op, + reverse(string_agg(n, '')) as num + from rotated, unnest(array_filter(rot[:-2], lambda x: x != ' ')) as u(n) + group by x + ), with_breaks as ( + select + x, op, num::int as num, + case when lag(x) over (order by x) = x - 1 then 0 else 1 end as is_break + from cleaned + ), with_groups as ( + select + x, op, num, + sum(is_break) over (order by x rows unbounded preceding) as group_id + from with_breaks + ), grouped as ( + select + group_id, + max(op) as op, + array_agg(num) as nums + from with_groups + group by group_id + ) + select * + from grouped; + +select sum( + case when op = '+' then list_sum(nums) + when op = '*' then list_product(nums) + else 0 + end +)::long as part2 +from day06_input2; + diff --git a/solutions/07.sql b/solutions/07.sql new file mode 100644 index 0000000..286d41f --- /dev/null +++ b/solutions/07.sql @@ -0,0 +1,59 @@ +create or replace table day07_data as + select row_number() over () as line, column0 + from read_csv('inputs/07/input.txt', header=false, delim='\n'); +create or replace table day07_test as + select row_number() over () as line, column0 + from read_csv('inputs/07/test.txt', header=false, delim='\n'); + +create or replace table day07_input as + select + line as y, + if(c = 'S', x, null) as starter, + if(c = '^', x, null) as splitter + from day07_test, + unnest(split(column0, '')) with ordinality as u(c, x) + where c != '.' +; + +with recursive seq(y, x) as ( + select + y, + starter as x + from day07_input + where y = 1 + + union all + + select distinct + s.y + 1 as y, + if(m.splitter = s.x, unnest([s.x + 1, s.x - 1]), s.x) as x + from seq as s + left join day07_input as m + on m.y = s.y + 1 and m.splitter = s.x + where s.y <= (select max(y) from day07_input) +) +select count(1) as part1 +from seq s +inner join day07_input m on s.y = m.y - 1 and s.x = m.splitter; + +with recursive seq(y, x) as ( + select + y, + starter as x, + 0 as split + from day07_input + where y = 1 + + union all + + select + s.y + 1 as y, + if(m.splitter = s.x, unnest([s.x + 1, s.x - 1]), s.x) as x, + if(m.splitter = s.x, 1, 0) as split + from seq as s + left join day07_input as m + on m.y = s.y + 1 and m.splitter = s.x + where s.y <= (select max(y) from day07_input) +) +select sum(split) as part2 +from seq s;