commit 687b84d9a761a00bbaab374b6b524d2a5b21eace Author: Xavier Morel Date: Wed Dec 3 17:00:56 2025 +0100 feat: days 1 2 3 done with duckdb diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..c5c9403 --- /dev/null +++ b/.envrc @@ -0,0 +1,5 @@ +export DIRENV_WARN_TIMEOUT=20s + +eval "$(devenv direnvrc)" + +use flake --no-pure-eval diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..219aaff --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.devenv/ +.direnv/ +inputs/ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..eb4ac68 --- /dev/null +++ b/flake.lock @@ -0,0 +1,225 @@ +{ + "nodes": { + "cachix": { + "inputs": { + "devenv": [ + "devenv" + ], + "flake-compat": [ + "devenv", + "flake-compat" + ], + "git-hooks": [ + "devenv", + "git-hooks" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760971495, + "narHash": "sha256-IwnNtbNVrlZIHh7h4Wz6VP0Furxg9Hh0ycighvL5cZc=", + "owner": "cachix", + "repo": "cachix", + "rev": "c5bfd933d1033672f51a863c47303fc0e093c2d2", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "latest", + "repo": "cachix", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "git-hooks": "git-hooks", + "nix": "nix", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1764449550, + "narHash": "sha256-7ReZCvkQYKHX6gaQaNioROrpk6rPmIBwlRwWZKlfGvs=", + "owner": "cachix", + "repo": "devenv", + "rev": "dfb58ac03bed07b93f629df55034bc50394d3971", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760948891, + "narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760663237, + "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "devenv", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "flake-parts": [ + "devenv", + "flake-parts" + ], + "git-hooks-nix": [ + "devenv", + "git-hooks" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-23-11": [ + "devenv" + ], + "nixpkgs-regression": [ + "devenv" + ] + }, + "locked": { + "lastModified": 1761648602, + "narHash": "sha256-H97KSB/luq/aGobKRuHahOvT1r7C03BgB6D5HBZsbN8=", + "owner": "cachix", + "repo": "nix", + "rev": "3e5644da6830ef65f0a2f7ec22830c46285bfff6", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "devenv-2.30.6", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1761313199, + "narHash": "sha256-wCIACXbNtXAlwvQUo1Ed++loFALPjYUA3dpcUJiXO44=", + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "d1c30452ebecfc55185ae6d1c983c09da0c274ff", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1764517877, + "narHash": "sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2d293cbfa5a793b4c50d17c05ef9e385b90edf6c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs_2" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8b6f6a5 --- /dev/null +++ b/flake.nix @@ -0,0 +1,41 @@ +{ + description = "Advent of Code 2025"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + devenv.url = "github:cachix/devenv"; + }; + + outputs = + { + self, + nixpkgs, + devenv, + ... + }@inputs: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + lib = pkgs.lib; + in + { + devShells.${system}.default = devenv.lib.mkShell { + inherit inputs pkgs; + modules = [ + ( + { pkgs, config, ... }: + { + # languages.enable = true; + packages = with pkgs; [ + duckdb + ]; + + enterShell = '' + echo "Thanks Topaz!" + ''; + } + ) + ]; + }; + }; +} diff --git a/solutions/01.sql b/solutions/01.sql new file mode 100644 index 0000000..d9d5750 --- /dev/null +++ b/solutions/01.sql @@ -0,0 +1,69 @@ +set preserve_insertion_order = true; + +create or replace table day01_data as + select operation, + if(operation[1] == 'L', -1, 1) as multiplier, + operation[2:]::int as add + from read_csv( + 'inputs/01/input.txt', + header = false, + columns = { 'operation': 'VARCHAR' } + ); + +create or replace table day01_test as + select operation, + if(operation[1] == 'L', -1, 1) as multiplier, + operation[2:]::int as add + from read_csv( + 'inputs/01/test.txt', + header = false, + columns = { 'operation': 'VARCHAR' } + ); + +create or replace table day01_data_states as + select + rowid, + operation, + multiplier, + add as raw_add, + floor(add / 100)::int as turns, + add - (turns * 100) as clean_add, + 50 + SUM(clean_add * multiplier) OVER ( + ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + ) as state + from day01_data +; + +with +states as ( + select + lag(abs(state + 100) % 100, 1, 50) over () as previous, + operation, + turns, + abs(state + 100) % 100 as state + from day01_data_states +) +select count(1) as part1 +from states +where state == 0; + +-------------- + +create or replace table day01_part2 as +select + lag(state, 1, 50) over () as raw_previous, + state as raw_current, + operation, + raw_previous % 100 == 0 as went_from_zero, + floor(raw_previous / 100)::int as prev_hundred, + floor(raw_current / 100)::int as current_hundred, + if(not went_from_zero and prev_hundred != current_hundred, 1, NULL) as hundred_change, + if((state + 100) % 100 == 0, 1, NULL) as exact_0, + turns, + turns + coalesce(exact_0, hundred_change, 0) as total_zero_clicks +from day01_data_states; + +select + sum(total_zero_clicks) as part2 +from day01_part2; + diff --git a/solutions/02.sql b/solutions/02.sql new file mode 100644 index 0000000..0b7aae6 --- /dev/null +++ b/solutions/02.sql @@ -0,0 +1,49 @@ +create or replace table day02_data as +with input1 as ( +select unnest(split(column0, ',')) as ranges +from read_csv('inputs/02/input.txt', header=false, delim='\n')) +select + split(ranges, '-')[1]::long as range_start, + split(ranges, '-')[2]::long as range_end +from input1; + +create or replace table day02_test as +with input1 as ( +select unnest(split(column0, ',')) as ranges +from read_csv('inputs/02/test.txt', header=false, delim='\n')) +select + split(ranges, '-')[1]::long as range_start, + split(ranges, '-')[2]::long as range_end +from input1; + +create or replace table day02_product_list as +select unnest(generate_series(range_start, range_end))::string as product_id +from day02_data; + +select sum(product_id::long) as part1 +from day02_product_list +where LENGTH(product_id) % 2 == 0 + and product_id[:(LENGTH(product_id)/2)] == product_id[(LENGTH(product_id)/2)+1:]; + +with split_lengths as ( +select product_id, + length(product_id) as len, + ( + select array_agg(l) + from generate_series(1, length(product_id)-1) as t(l) + where length(product_id) % l == 0 + ) as lengths +from day02_product_list +), +with_chunks as ( +select product_id, chunk_size, + ( + select array_agg(substring(product_id, (j-1)*chunk_size+1, chunk_size)) + from generate_series(1, ceil(length(product_id)/chunk_size)::int) as u(j) + ) as chunks +FROM split_lengths, unnest(lengths) as t(chunk_size) +) +select sum(distinct product_id::long) as part2 +from with_chunks +where length(array_distinct(chunks)) = 1 +; diff --git a/solutions/03.sql b/solutions/03.sql new file mode 100644 index 0000000..f3ef1e7 --- /dev/null +++ b/solutions/03.sql @@ -0,0 +1,69 @@ +create or replace table day03_data as + select bank + from read_csv( + 'inputs/03/input.txt', + header = false, + columns = { 'bank': 'VARCHAR' } + ); +create or replace table day03_test as + select bank + from read_csv( + 'inputs/03/test.txt', + header = false, + columns = { 'bank': 'VARCHAR' } + ); + +with with_best as ( + select bank, + coalesce(( + select max(digit), + from generate_series(2, 9) as t(digit) + where contains(bank[:-2], digit::string) is true + ), 1) as best + from day03_test +), +with_best_pos as ( + select *, + instr(bank, best::string) as best_pos, + bank[best_pos+1:], + coalesce(( + select max(digit) + from generate_series(2, 9) as t(digit) + where contains(bank[best_pos+1:], digit::string) is true + ), 1) as second_best + from with_best +) +select sum(best * 10 + second_best) as part1 +from with_best_pos +; + +with recursive seq as ( + select + bank, + 12 as step, + '' as digits, + 0 as pos, + bank[0:-12] as sub, + from day03_data + + union all + + select + s.bank, + s.step - 1 as new_step, + s.digits || max_digit::string as digits, +s.pos+instr(s.sub, max_digit::string) as new_pos, + s.bank[new_pos+1:-new_step] as sub, + from seq s + join lateral ( + select max(digit) as max_digit + from generate_series(1,9) as t(digit) + where contains(s.sub, digit::string) + ) as m + on s.step > 0 +) +select sum(digits::hugeint) as total +from seq +where step = 0 +; +