generated from janezicmatej/aoc-template
	Compare commits
	
		
			9 Commits
		
	
	
		
			000002509e
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 00000340e7 | |||
| 0000033060 | |||
| 000003208e | |||
| 000003103e | |||
| 0000030073 | |||
| 00000290eb | |||
| 0000028054 | |||
| 00000270f6 | |||
| 00000260b8 | 
							
								
								
									
										188
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										188
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -17,6 +17,18 @@ version = "1.0.2" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "ahash" | ||||||
|  | version = "0.8.11" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if", | ||||||
|  |  "once_cell", | ||||||
|  |  "version_check", | ||||||
|  |  "zerocopy", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "aho-corasick" | name = "aho-corasick" | ||||||
| version = "1.1.3" | version = "1.1.3" | ||||||
| @@ -36,6 +48,7 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" | |||||||
| name = "aoc" | name = "aoc" | ||||||
| version = "48.0.0" | version = "48.0.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  |  "cached", | ||||||
|  "hashbrown 0.15.2", |  "hashbrown 0.15.2", | ||||||
|  "itertools", |  "itertools", | ||||||
|  "num-integer", |  "num-integer", | ||||||
| @@ -87,6 +100,39 @@ version = "1.3.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" | checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "cached" | ||||||
|  | version = "0.54.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae" | ||||||
|  | dependencies = [ | ||||||
|  |  "ahash", | ||||||
|  |  "cached_proc_macro", | ||||||
|  |  "cached_proc_macro_types", | ||||||
|  |  "hashbrown 0.14.5", | ||||||
|  |  "once_cell", | ||||||
|  |  "thiserror", | ||||||
|  |  "web-time", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "cached_proc_macro" | ||||||
|  | version = "0.23.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa" | ||||||
|  | dependencies = [ | ||||||
|  |  "darling", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn 2.0.90", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "cached_proc_macro_types" | ||||||
|  | version = "0.1.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.0.78" | version = "1.0.78" | ||||||
| @@ -115,6 +161,41 @@ version = "0.8.3" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "darling" | ||||||
|  | version = "0.20.10" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" | ||||||
|  | dependencies = [ | ||||||
|  |  "darling_core", | ||||||
|  |  "darling_macro", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "darling_core" | ||||||
|  | version = "0.20.10" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" | ||||||
|  | dependencies = [ | ||||||
|  |  "fnv", | ||||||
|  |  "ident_case", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "strsim", | ||||||
|  |  "syn 2.0.90", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "darling_macro" | ||||||
|  | version = "0.20.10" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" | ||||||
|  | dependencies = [ | ||||||
|  |  "darling_core", | ||||||
|  |  "quote", | ||||||
|  |  "syn 2.0.90", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "dotenvy" | name = "dotenvy" | ||||||
| version = "0.15.6" | version = "0.15.6" | ||||||
| @@ -275,6 +356,16 @@ version = "0.12.3" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "hashbrown" | ||||||
|  | version = "0.14.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" | ||||||
|  | dependencies = [ | ||||||
|  |  "ahash", | ||||||
|  |  "allocator-api2", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "hashbrown" | name = "hashbrown" | ||||||
| version = "0.15.2" | version = "0.15.2" | ||||||
| @@ -366,6 +457,12 @@ dependencies = [ | |||||||
|  "tokio-native-tls", |  "tokio-native-tls", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "ident_case" | ||||||
|  | version = "1.0.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "idna" | name = "idna" | ||||||
| version = "0.3.0" | version = "0.3.0" | ||||||
| @@ -535,9 +632,9 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "once_cell" | name = "once_cell" | ||||||
| version = "1.16.0" | version = "1.20.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "openssl" | name = "openssl" | ||||||
| @@ -562,7 +659,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn", |  "syn 1.0.107", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -616,18 +713,18 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "proc-macro2" | name = "proc-macro2" | ||||||
| version = "1.0.69" | version = "1.0.92" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "unicode-ident", |  "unicode-ident", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "quote" | name = "quote" | ||||||
| version = "1.0.33" | version = "1.0.37" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
| ] | ] | ||||||
| @@ -829,6 +926,12 @@ dependencies = [ | |||||||
|  "windows-sys 0.48.0", |  "windows-sys 0.48.0", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "strsim" | ||||||
|  | version = "0.11.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "1.0.107" | version = "1.0.107" | ||||||
| @@ -840,6 +943,17 @@ dependencies = [ | |||||||
|  "unicode-ident", |  "unicode-ident", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "syn" | ||||||
|  | version = "2.0.90" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "unicode-ident", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "system-configuration" | name = "system-configuration" | ||||||
| version = "0.5.1" | version = "0.5.1" | ||||||
| @@ -875,6 +989,26 @@ dependencies = [ | |||||||
|  "winapi", |  "winapi", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "thiserror" | ||||||
|  | version = "1.0.69" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" | ||||||
|  | dependencies = [ | ||||||
|  |  "thiserror-impl", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "thiserror-impl" | ||||||
|  | version = "1.0.69" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn 2.0.90", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "tinyvec" | name = "tinyvec" | ||||||
| version = "1.6.0" | version = "1.6.0" | ||||||
| @@ -1000,6 +1134,12 @@ version = "0.2.15" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "version_check" | ||||||
|  | version = "0.9.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "want" | name = "want" | ||||||
| version = "0.3.0" | version = "0.3.0" | ||||||
| @@ -1037,7 +1177,7 @@ dependencies = [ | |||||||
|  "once_cell", |  "once_cell", | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn", |  "syn 1.0.107", | ||||||
|  "wasm-bindgen-shared", |  "wasm-bindgen-shared", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -1071,7 +1211,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2", |  "proc-macro2", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn", |  "syn 1.0.107", | ||||||
|  "wasm-bindgen-backend", |  "wasm-bindgen-backend", | ||||||
|  "wasm-bindgen-shared", |  "wasm-bindgen-shared", | ||||||
| ] | ] | ||||||
| @@ -1092,6 +1232,16 @@ dependencies = [ | |||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "web-time" | ||||||
|  | version = "1.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" | ||||||
|  | dependencies = [ | ||||||
|  |  "js-sys", | ||||||
|  |  "wasm-bindgen", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "winapi" | name = "winapi" | ||||||
| version = "0.3.9" | version = "0.3.9" | ||||||
| @@ -1232,3 +1382,23 @@ dependencies = [ | |||||||
|  "cfg-if", |  "cfg-if", | ||||||
|  "windows-sys 0.48.0", |  "windows-sys 0.48.0", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "zerocopy" | ||||||
|  | version = "0.7.35" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" | ||||||
|  | dependencies = [ | ||||||
|  |  "zerocopy-derive", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "zerocopy-derive" | ||||||
|  | version = "0.7.35" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn 2.0.90", | ||||||
|  | ] | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ authors.workspace = true | |||||||
| repository.workspace = true | repository.workspace = true | ||||||
|  |  | ||||||
| [dependencies] | [dependencies] | ||||||
|  | cached = "0.54.0" | ||||||
| hashbrown = "0.15.2" | hashbrown = "0.15.2" | ||||||
| itertools = "0.13.0" | itertools = "0.13.0" | ||||||
| num-integer = "0.1.46" | num-integer = "0.1.46" | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								data/examples/20.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								data/examples/20.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | ############### | ||||||
|  | #...#...#.....# | ||||||
|  | #.#.#.#.#.###.# | ||||||
|  | #S#...#.#.#...# | ||||||
|  | #######.#.#.### | ||||||
|  | #######.#.#...# | ||||||
|  | #######.#.###.# | ||||||
|  | ###..E#...#...# | ||||||
|  | ###.#######.### | ||||||
|  | #...###...#...# | ||||||
|  | #.#####.#.###.# | ||||||
|  | #.#...#.#.#...# | ||||||
|  | #.#.#.#.#.#.### | ||||||
|  | #...#...#...### | ||||||
|  | ############### | ||||||
							
								
								
									
										5
									
								
								data/examples/21.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								data/examples/21.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | 029A | ||||||
|  | 980A | ||||||
|  | 179A | ||||||
|  | 456A | ||||||
|  | 379A | ||||||
							
								
								
									
										4
									
								
								data/examples/22.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								data/examples/22.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | 1 | ||||||
|  | 2 | ||||||
|  | 3 | ||||||
|  | 2024 | ||||||
							
								
								
									
										32
									
								
								data/examples/23.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								data/examples/23.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | kh-tc | ||||||
|  | qp-kh | ||||||
|  | de-cg | ||||||
|  | ka-co | ||||||
|  | yn-aq | ||||||
|  | qp-ub | ||||||
|  | cg-tb | ||||||
|  | vc-aq | ||||||
|  | tb-ka | ||||||
|  | wh-tc | ||||||
|  | yn-cg | ||||||
|  | kh-ub | ||||||
|  | ta-co | ||||||
|  | de-co | ||||||
|  | tc-td | ||||||
|  | tb-wq | ||||||
|  | wh-td | ||||||
|  | ta-ka | ||||||
|  | td-qp | ||||||
|  | aq-cg | ||||||
|  | wq-ub | ||||||
|  | ub-vc | ||||||
|  | de-ta | ||||||
|  | wq-aq | ||||||
|  | wq-vc | ||||||
|  | wh-yn | ||||||
|  | ka-de | ||||||
|  | kh-ta | ||||||
|  | co-tc | ||||||
|  | wh-qp | ||||||
|  | tb-vc | ||||||
|  | td-yn | ||||||
							
								
								
									
										47
									
								
								data/examples/24.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								data/examples/24.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | x00: 1 | ||||||
|  | x01: 0 | ||||||
|  | x02: 1 | ||||||
|  | x03: 1 | ||||||
|  | x04: 0 | ||||||
|  | y00: 1 | ||||||
|  | y01: 1 | ||||||
|  | y02: 1 | ||||||
|  | y03: 1 | ||||||
|  | y04: 1 | ||||||
|  |  | ||||||
|  | ntg XOR fgs -> mjb | ||||||
|  | y02 OR x01 -> tnw | ||||||
|  | kwq OR kpj -> z05 | ||||||
|  | x00 OR x03 -> fst | ||||||
|  | tgd XOR rvg -> z01 | ||||||
|  | vdt OR tnw -> bfw | ||||||
|  | bfw AND frj -> z10 | ||||||
|  | ffh OR nrd -> bqk | ||||||
|  | y00 AND y03 -> djm | ||||||
|  | y03 OR y00 -> psh | ||||||
|  | bqk OR frj -> z08 | ||||||
|  | tnw OR fst -> frj | ||||||
|  | gnj AND tgd -> z11 | ||||||
|  | bfw XOR mjb -> z00 | ||||||
|  | x03 OR x00 -> vdt | ||||||
|  | gnj AND wpb -> z02 | ||||||
|  | x04 AND y00 -> kjc | ||||||
|  | djm OR pbm -> qhw | ||||||
|  | nrd AND vdt -> hwm | ||||||
|  | kjc AND fst -> rvg | ||||||
|  | y04 OR y02 -> fgs | ||||||
|  | y01 AND x02 -> pbm | ||||||
|  | ntg OR kjc -> kwq | ||||||
|  | psh XOR fgs -> tgd | ||||||
|  | qhw XOR tgd -> z09 | ||||||
|  | pbm OR djm -> kpj | ||||||
|  | x03 XOR y03 -> ffh | ||||||
|  | x00 XOR y04 -> ntg | ||||||
|  | bfw OR bqk -> z06 | ||||||
|  | nrd XOR fgs -> wpb | ||||||
|  | frj XOR qhw -> z04 | ||||||
|  | bqk OR frj -> z07 | ||||||
|  | y03 OR x01 -> nrd | ||||||
|  | hwm AND bqk -> z03 | ||||||
|  | tgd XOR rvg -> z12 | ||||||
|  | tnw OR pbm -> gnj | ||||||
							
								
								
									
										39
									
								
								data/examples/25.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								data/examples/25.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | ##### | ||||||
|  | .#### | ||||||
|  | .#### | ||||||
|  | .#### | ||||||
|  | .#.#. | ||||||
|  | .#... | ||||||
|  | ..... | ||||||
|  |  | ||||||
|  | ##### | ||||||
|  | ##.## | ||||||
|  | .#.## | ||||||
|  | ...## | ||||||
|  | ...#. | ||||||
|  | ...#. | ||||||
|  | ..... | ||||||
|  |  | ||||||
|  | ..... | ||||||
|  | #.... | ||||||
|  | #.... | ||||||
|  | #...# | ||||||
|  | #.#.# | ||||||
|  | #.### | ||||||
|  | ##### | ||||||
|  |  | ||||||
|  | ..... | ||||||
|  | ..... | ||||||
|  | #.#.. | ||||||
|  | ###.. | ||||||
|  | ###.# | ||||||
|  | ###.# | ||||||
|  | ##### | ||||||
|  |  | ||||||
|  | ..... | ||||||
|  | ..... | ||||||
|  | ..... | ||||||
|  | #.... | ||||||
|  | #.#.. | ||||||
|  | #.#.# | ||||||
|  | ##### | ||||||
| @@ -200,10 +200,16 @@ mod tests { | |||||||
|     use super::*; |     use super::*; | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_part_one() { |     fn test_part_one() { | ||||||
|         assert_eq!(part_one(&aoc::template::read_file("examples", 15)), Some(10092)); |         assert_eq!( | ||||||
|  |             part_one(&aoc::template::read_file("examples", 15)), | ||||||
|  |             Some(10092) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_part_two() { |     fn test_part_two() { | ||||||
|         assert_eq!(part_two(&aoc::template::read_file("examples", 15)), Some(9021)); |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 15)), | ||||||
|  |             Some(9021) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -91,4 +91,3 @@ pub fn part_two(input: &str) -> Option<String> { | |||||||
| } | } | ||||||
|  |  | ||||||
| aoc::solution!(18); | aoc::solution!(18); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -66,6 +66,9 @@ mod tests { | |||||||
|     } |     } | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_part_two() { |     fn test_part_two() { | ||||||
|         assert_eq!(part_two(&aoc::template::read_file("examples", 19)), Some(16)); |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 19)), | ||||||
|  |             Some(16) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										135
									
								
								src/bin/20.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/bin/20.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | use std::collections::VecDeque; | ||||||
|  |  | ||||||
|  | use aoc::grid_vec::{Direction, Grid, Point}; | ||||||
|  | use hashbrown::HashMap; | ||||||
|  |  | ||||||
|  | fn parse_input(input: &str) -> (Grid, Point, Point) { | ||||||
|  |     let mut grid: Grid = input.parse().unwrap(); | ||||||
|  |     let start = grid.find(b'S').unwrap(); | ||||||
|  |     let end = grid.find(b'E').unwrap(); | ||||||
|  |  | ||||||
|  |     grid[start] = b'.'; | ||||||
|  |     grid[end] = b'.'; | ||||||
|  |  | ||||||
|  |     (grid, start, end) | ||||||
|  | } | ||||||
|  | fn bfs( | ||||||
|  |     grid: &Grid, | ||||||
|  |     start: Point, | ||||||
|  |     limit: Option<usize>, | ||||||
|  |     cheat: bool, | ||||||
|  |     visited: &mut HashMap<Point, usize>, | ||||||
|  |     queue: &mut VecDeque<(Point, usize)>, | ||||||
|  | ) { | ||||||
|  |     visited.clear(); | ||||||
|  |     queue.clear(); | ||||||
|  |  | ||||||
|  |     queue.push_back((start, 0)); | ||||||
|  |  | ||||||
|  |     while let Some((p, l)) = queue.pop_front() { | ||||||
|  |         if visited.contains_key(&p) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         visited.insert(p, l); | ||||||
|  |  | ||||||
|  |         for d in Direction::CROSS { | ||||||
|  |             let n = p + d; | ||||||
|  |  | ||||||
|  |             let nv = grid.get(&n); | ||||||
|  |             let uwnv = *nv.unwrap_or(&b'#'); | ||||||
|  |             let valid_neigh = (cheat && nv.is_some()) || uwnv == b'.'; | ||||||
|  |             let valid_length = l < limit.unwrap_or(usize::MAX); | ||||||
|  |             let unvisited = !visited.contains_key(&n); | ||||||
|  |  | ||||||
|  |             if valid_neigh && valid_length && unvisited { | ||||||
|  |                 queue.push_back((n, l + 1)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn get_cheat_neighbours_and_benchmark( | ||||||
|  |     grid: &Grid, | ||||||
|  |     start: Point, | ||||||
|  |     cheat_limit: usize, | ||||||
|  | ) -> HashMap<Point, Vec<(Point, usize)>> { | ||||||
|  |     let mut map = HashMap::<Point, Vec<(Point, usize)>>::new(); | ||||||
|  |  | ||||||
|  |     let mut reuse_queue = VecDeque::new(); | ||||||
|  |     let mut reuse_visited = HashMap::new(); | ||||||
|  |  | ||||||
|  |     let mut valid_points = HashMap::new(); | ||||||
|  |  | ||||||
|  |     bfs( | ||||||
|  |         grid, | ||||||
|  |         start, | ||||||
|  |         None, | ||||||
|  |         false, | ||||||
|  |         &mut valid_points, | ||||||
|  |         &mut reuse_queue, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     for (&s, _) in valid_points.iter() { | ||||||
|  |         bfs( | ||||||
|  |             grid, | ||||||
|  |             s, | ||||||
|  |             Some(cheat_limit), | ||||||
|  |             true, | ||||||
|  |             &mut reuse_visited, | ||||||
|  |             &mut reuse_queue, | ||||||
|  |         ); | ||||||
|  |         for (&point, &length) in reuse_visited.iter().filter(|(&p, _)| grid[p] == b'.') { | ||||||
|  |             map.entry(s).or_default().push((point, length)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     map | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn cheated_bfs( | ||||||
|  |     grid: &Grid, | ||||||
|  |     start: Point, | ||||||
|  |     end: Point, | ||||||
|  |     cheat_limit: usize, | ||||||
|  |     increase_limit: usize, | ||||||
|  | ) -> usize { | ||||||
|  |     let neighbours = get_cheat_neighbours_and_benchmark(grid, start, cheat_limit); | ||||||
|  |  | ||||||
|  |     let mut reuse_queue = VecDeque::new(); | ||||||
|  |  | ||||||
|  |     let mut from_start = HashMap::new(); | ||||||
|  |     let mut from_end = HashMap::new(); | ||||||
|  |  | ||||||
|  |     bfs(grid, start, None, false, &mut from_start, &mut reuse_queue); | ||||||
|  |     bfs(grid, end, None, false, &mut from_end, &mut reuse_queue); | ||||||
|  |  | ||||||
|  |     let benchmark = from_start[&end]; | ||||||
|  |  | ||||||
|  |     let mut count = 0; | ||||||
|  |  | ||||||
|  |     for node in from_start.keys() { | ||||||
|  |         for (neigh, cheat_dist) in neighbours[node].iter() { | ||||||
|  |             let start_dist = from_start[node]; | ||||||
|  |             let end_dist = from_end[neigh]; | ||||||
|  |  | ||||||
|  |             let dist = start_dist + cheat_dist + end_dist; | ||||||
|  |             if dist < benchmark && dist.abs_diff(benchmark) >= increase_limit { | ||||||
|  |                 count += 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     count | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     let (grid, start, end) = parse_input(input); | ||||||
|  |     cheated_bfs(&grid, start, end, 2, 100).into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<usize> { | ||||||
|  |     let (grid, start, end) = parse_input(input); | ||||||
|  |     cheated_bfs(&grid, start, end, 20, 100).into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(20); | ||||||
							
								
								
									
										162
									
								
								src/bin/21.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/bin/21.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | |||||||
|  | use std::collections::VecDeque; | ||||||
|  |  | ||||||
|  | use hashbrown::HashMap; | ||||||
|  | use itertools::Itertools; | ||||||
|  |  | ||||||
|  | use cached::proc_macro::cached; | ||||||
|  | use cached::SizedCache; | ||||||
|  |  | ||||||
|  | #[rustfmt::skip] | ||||||
|  | #[allow(clippy::type_complexity)] | ||||||
|  | const NUMPAD: [(u8, [Option<(u8, u8)>; 4]); 11] = [ | ||||||
|  |     (b'0', [Some((b'2', b'^')), Some((b'A', b'>')), None, None]), | ||||||
|  |     (b'1', [Some((b'2', b'>')), Some((b'4', b'^')), None, None]), | ||||||
|  |     (b'2', [Some((b'0', b'v')), Some((b'1', b'<')), Some((b'3', b'>')), Some((b'5', b'^')),]),  | ||||||
|  |     (b'3', [Some((b'2', b'<')), Some((b'6', b'^')), Some((b'A', b'v')), None,]),  | ||||||
|  |     (b'4', [Some((b'1', b'v')), Some((b'5', b'>')), Some((b'7', b'^')), None,]),  | ||||||
|  |     (b'5', [Some((b'2', b'v')), Some((b'4', b'<')), Some((b'6', b'>')), Some((b'8', b'^')),]),  | ||||||
|  |     (b'6', [Some((b'3', b'v')), Some((b'5', b'<')), Some((b'9', b'^')), None,]),  | ||||||
|  |     (b'7', [Some((b'4', b'v')), Some((b'8', b'>')), None, None]),  | ||||||
|  |     (b'8', [Some((b'5', b'v')), Some((b'7', b'<')), Some((b'9', b'>')), None,]),  | ||||||
|  |     (b'9', [Some((b'6', b'v')), Some((b'8', b'<')), None, None]), | ||||||
|  |     (b'A', [Some((b'0', b'<')), Some((b'3', b'^')), None, None]), | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | #[rustfmt::skip] | ||||||
|  | #[allow(clippy::type_complexity)] | ||||||
|  | const KEYPAD: [(u8, [Option<(u8, u8)>; 3]); 5] = [ | ||||||
|  |     (b'^', [Some((b'A', b'>')), Some((b'v', b'v')), None]), | ||||||
|  |     (b'<', [Some((b'v', b'>')), None, None]), | ||||||
|  |     (b'v', [Some((b'<', b'<')), Some((b'^', b'^')), Some((b'>', b'>'))]), | ||||||
|  |     (b'>', [Some((b'v', b'<')), Some((b'A', b'^')), None]), | ||||||
|  |     (b'A', [Some((b'^', b'<')), Some((b'>', b'v')), None]), | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | #[cached( | ||||||
|  |     ty = "SizedCache<String, Vec<VecDeque<u8>>>", | ||||||
|  |     create = "{ SizedCache::with_size(150) }", | ||||||
|  |     convert = r#"{ format!("{}{s}{e}", graph.len()) }"# | ||||||
|  | )] | ||||||
|  | fn bfs(graph: &HashMap<u8, Vec<(u8, u8)>>, s: u8, e: u8) -> Vec<VecDeque<u8>> { | ||||||
|  |     let mut res = Vec::new(); | ||||||
|  |  | ||||||
|  |     let mut queue = VecDeque::new(); | ||||||
|  |     let mut shortest = usize::MAX; | ||||||
|  |  | ||||||
|  |     queue.push_back((s, VecDeque::new())); | ||||||
|  |  | ||||||
|  |     while let Some((n, mut p)) = queue.pop_front() { | ||||||
|  |         if n == e { | ||||||
|  |             if shortest == usize::MAX { | ||||||
|  |                 shortest = p.len(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if p.len() == shortest { | ||||||
|  |                 p.push_back(b'A'); | ||||||
|  |                 res.push(p); | ||||||
|  |             } | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if p.len() >= shortest { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (nn, c) in graph[&n].iter().copied() { | ||||||
|  |             let mut np = p.clone(); | ||||||
|  |             np.push_back(c); | ||||||
|  |  | ||||||
|  |             queue.push_back((nn, np)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     res | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cached( | ||||||
|  |     ty = "SizedCache<String, usize>", | ||||||
|  |     create = "{ SizedCache::with_size(100000) }", | ||||||
|  |     convert = r#"{ format!("{sequence:?}{level}{graph}") }"# | ||||||
|  | )] | ||||||
|  | fn dfs( | ||||||
|  |     graphs: &[HashMap<u8, Vec<(u8, u8)>>], | ||||||
|  |     graph: usize, | ||||||
|  |     mut sequence: VecDeque<u8>, | ||||||
|  |     level: usize, | ||||||
|  | ) -> usize { | ||||||
|  |     let graph = &graphs[graph]; | ||||||
|  |     sequence.push_front(b'A'); | ||||||
|  |     let mut res = 0; | ||||||
|  |  | ||||||
|  |     for (n1, n2) in sequence.into_iter().tuple_windows() { | ||||||
|  |         let paths = bfs(graph, n1, n2); | ||||||
|  |         if level == 0 { | ||||||
|  |             res += paths.into_iter().map(|p| p.len()).min().unwrap(); | ||||||
|  |         } else { | ||||||
|  |             res += paths | ||||||
|  |                 .into_iter() | ||||||
|  |                 .map(|p| dfs(graphs, 1, p, level - 1)) | ||||||
|  |                 .min() | ||||||
|  |                 .unwrap(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     res | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn build_graphs() -> [HashMap<u8, Vec<(u8, u8)>>; 2] { | ||||||
|  |     let mut numpad = HashMap::new(); | ||||||
|  |     for (k, v) in NUMPAD.iter() { | ||||||
|  |         numpad.insert(*k, v.iter().filter_map(|&x| x).collect_vec()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let mut keypad = HashMap::new(); | ||||||
|  |     for (k, v) in KEYPAD.iter() { | ||||||
|  |         keypad.insert(*k, v.iter().filter_map(|&x| x).collect_vec()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [numpad, keypad] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn solve_chain(input: &str, level: usize) -> usize { | ||||||
|  |     let graphs = build_graphs(); | ||||||
|  |  | ||||||
|  |     let mut res = 0; | ||||||
|  |     for line in input.lines() { | ||||||
|  |         let n: usize = line.strip_suffix("A").unwrap().parse().unwrap(); | ||||||
|  |         let sequence = VecDeque::from_iter(line.as_bytes().iter().copied()); | ||||||
|  |         let min_len = dfs(&graphs, 0, sequence, level); | ||||||
|  |         res += min_len * n; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     res | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     Some(solve_chain(input, 2)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<usize> { | ||||||
|  |     Some(solve_chain(input, 25)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(21); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_one(&aoc::template::read_file("examples", 21)), | ||||||
|  |             Some(126384) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_two() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 21)), | ||||||
|  |             Some(154115708116294) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										91
									
								
								src/bin/22.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/bin/22.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | use aoc::parsers::to_vec_map; | ||||||
|  | use hashbrown::{HashMap, HashSet}; | ||||||
|  |  | ||||||
|  | fn pseudo_next(mut n: usize) -> usize { | ||||||
|  |     n = ((n << 6) ^ n) % 16777216; | ||||||
|  |     n = ((n >> 5) ^ n) % 16777216; | ||||||
|  |     n = ((n << 11) ^ n) % 16777216; | ||||||
|  |     n | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct MonkeyTrader { | ||||||
|  |     numbers: [usize; 2001], | ||||||
|  |     sequences: HashMap<[isize; 4], usize>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl MonkeyTrader { | ||||||
|  |     fn new(seed: usize) -> Self { | ||||||
|  |         let mut numbers = [0; 2001]; | ||||||
|  |         numbers[0] = seed; | ||||||
|  |  | ||||||
|  |         let mut n = seed; | ||||||
|  |         for num in numbers.iter_mut().skip(1) { | ||||||
|  |             n = pseudo_next(n); | ||||||
|  |             *num = n; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let mut sequences = HashMap::new(); | ||||||
|  |         for i in 4..2001 { | ||||||
|  |             let mut key = [0; 4]; | ||||||
|  |             for j in 1..=4 { | ||||||
|  |                 let d1 = numbers[i - 4 + j - 1] % 10; | ||||||
|  |                 let d2 = numbers[i - 4 + j] % 10; | ||||||
|  |                 let diff = d2 as isize - d1 as isize; | ||||||
|  |                 key[j - 1] = diff; | ||||||
|  |             } | ||||||
|  |             if sequences.contains_key(&key) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             *sequences.entry(key).or_default() = numbers[i] % 10; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         MonkeyTrader { numbers, sequences } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     to_vec_map(input, '\n', MonkeyTrader::new) | ||||||
|  |         .into_iter() | ||||||
|  |         .map(|x| x.numbers[2000]) | ||||||
|  |         .sum::<usize>() | ||||||
|  |         .into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<usize> { | ||||||
|  |     let traders = to_vec_map(input, '\n', MonkeyTrader::new); | ||||||
|  |     let key_union: HashSet<[isize; 4]> = traders | ||||||
|  |         .iter() | ||||||
|  |         .flat_map(|x| x.sequences.keys().cloned()) | ||||||
|  |         .collect(); | ||||||
|  |  | ||||||
|  |     key_union | ||||||
|  |         .into_iter() | ||||||
|  |         .map(|k| { | ||||||
|  |             traders | ||||||
|  |                 .iter() | ||||||
|  |                 .filter_map(|t| t.sequences.get(&k)) | ||||||
|  |                 .sum::<usize>() | ||||||
|  |         }) | ||||||
|  |         .max() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(22); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_one(&aoc::template::read_file("examples", 22)), | ||||||
|  |             Some(37990510) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_two() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 22)), | ||||||
|  |             Some(23) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								src/bin/23.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/bin/23.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | use std::collections::BTreeSet; | ||||||
|  |  | ||||||
|  | use hashbrown::{HashMap, HashSet}; | ||||||
|  | use itertools::Itertools; | ||||||
|  |  | ||||||
|  | fn parse_graph(input: &str) -> HashMap<&str, BTreeSet<&str>> { | ||||||
|  |     let nodes: HashSet<_> = input.lines().filter_map(|x| x.split_once('-')).collect(); | ||||||
|  |     let mut graph: HashMap<_, BTreeSet<_>> = HashMap::new(); | ||||||
|  |     for (n1, n2) in nodes.iter().copied() { | ||||||
|  |         graph.entry(n1).or_default().insert(n2); | ||||||
|  |         graph.entry(n2).or_default().insert(n1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     graph | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     let graph = parse_graph(input); | ||||||
|  |  | ||||||
|  |     let mut triples = HashSet::new(); | ||||||
|  |     for (n1, neigh) in graph.iter() { | ||||||
|  |         for n2 in neigh.iter().copied() { | ||||||
|  |             for n3 in graph[n2].iter() { | ||||||
|  |                 if graph[n3].contains(n1) && n1.starts_with('t') { | ||||||
|  |                     let mut triple = [n1, n2, n3]; | ||||||
|  |                     triple.sort(); | ||||||
|  |                     triples.insert(triple); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     triples.len().into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<String> { | ||||||
|  |     let graph = parse_graph(input); | ||||||
|  |  | ||||||
|  |     let p: BTreeSet<_> = graph.keys().copied().collect(); | ||||||
|  |     let r = HashSet::new(); | ||||||
|  |     let x = BTreeSet::new(); | ||||||
|  |  | ||||||
|  |     let mut maximals = HashSet::new(); | ||||||
|  |  | ||||||
|  |     let mut stack = Vec::new(); | ||||||
|  |     stack.push((r, p, x)); | ||||||
|  |  | ||||||
|  |     while let Some((r, mut p, mut x)) = stack.pop() { | ||||||
|  |         if p.is_empty() && x.is_empty() { | ||||||
|  |             let mut password = r.iter().copied().collect_vec(); | ||||||
|  |             password.sort(); | ||||||
|  |  | ||||||
|  |             maximals.insert(password.join(",")); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         while let Some(pp) = p.pop_last() { | ||||||
|  |             let mut nr = r.clone(); | ||||||
|  |             nr.insert(pp); | ||||||
|  |  | ||||||
|  |             let np = &p & &graph[pp]; | ||||||
|  |             let nx = &x & &graph[pp]; | ||||||
|  |  | ||||||
|  |             stack.push((nr, np, nx)); | ||||||
|  |  | ||||||
|  |             x.insert(pp); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     maximals.into_iter().max_by_key(|x| x.len()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(23); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!(part_one(&aoc::template::read_file("examples", 23)), Some(7)); | ||||||
|  |     } | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_two() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 23)), | ||||||
|  |             Some("co,de,ka,ta".to_string()) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										132
									
								
								src/bin/24.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/bin/24.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | |||||||
|  | use std::collections::VecDeque; | ||||||
|  |  | ||||||
|  | use hashbrown::HashMap; | ||||||
|  | use itertools::Itertools; | ||||||
|  | use regex::Regex; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, Copy)] | ||||||
|  | enum Gate { | ||||||
|  |     And, | ||||||
|  |     Or, | ||||||
|  |     XOr, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct LogicGate<'a> { | ||||||
|  |     input_one: &'a str, | ||||||
|  |     input_two: &'a str, | ||||||
|  |     output: &'a str, | ||||||
|  |     gate: Gate, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn parse_input(input: &str) -> (HashMap<&str, bool>, Vec<LogicGate>) { | ||||||
|  |     let (uvals, uevals) = input.split_once("\n\n").unwrap(); | ||||||
|  |     let vals: HashMap<_, _> = uvals | ||||||
|  |         .lines() | ||||||
|  |         .map(|x| x.split_once(": ").unwrap()) | ||||||
|  |         .map(|(k, v)| (k, v == "1")) | ||||||
|  |         .collect(); | ||||||
|  |  | ||||||
|  |     let mut logic_gates = Vec::new(); | ||||||
|  |     let re = Regex::new(r#"((?:\w|\d){3}) (AND|XOR|OR) ((?:\w|\d){3}) -> ((?:\w|\d){3})"#).unwrap(); | ||||||
|  |     for capt in re.captures_iter(uevals) { | ||||||
|  |         let input_one = capt.get(1).unwrap().as_str(); | ||||||
|  |         let gate = match capt.get(2).unwrap().as_str() { | ||||||
|  |             "AND" => Gate::And, | ||||||
|  |             "OR" => Gate::Or, | ||||||
|  |             "XOR" => Gate::XOr, | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         }; | ||||||
|  |         let input_two = capt.get(3).unwrap().as_str(); | ||||||
|  |         let output = capt.get(4).unwrap().as_str(); | ||||||
|  |         logic_gates.push(LogicGate { | ||||||
|  |             input_one, | ||||||
|  |             input_two, | ||||||
|  |             output, | ||||||
|  |             gate, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     (vals, logic_gates) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     let (mut vals, logic_gates) = parse_input(input); | ||||||
|  |     let mut queue = VecDeque::from(logic_gates); | ||||||
|  |  | ||||||
|  |     while let Some(s) = queue.pop_front() { | ||||||
|  |         if !vals.contains_key(s.input_one) || !vals.contains_key(s.input_two) { | ||||||
|  |             queue.push_back(s); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let v1 = vals[s.input_one]; | ||||||
|  |         let v2 = vals[s.input_two]; | ||||||
|  |  | ||||||
|  |         let o = match s.gate { | ||||||
|  |             Gate::And => v1 & v2, | ||||||
|  |             Gate::Or => v1 | v2, | ||||||
|  |             Gate::XOr => v1 ^ v2, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         vals.insert(s.output, o); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let mut zs = vals | ||||||
|  |         .into_iter() | ||||||
|  |         .filter(|x| x.0.starts_with('z')) | ||||||
|  |         .collect_vec(); | ||||||
|  |     zs.sort(); | ||||||
|  |     zs.into_iter() | ||||||
|  |         .enumerate() | ||||||
|  |         .filter(|x| x.1 .1) | ||||||
|  |         .map(|(i, _)| 1 << i) | ||||||
|  |         .sum::<usize>() | ||||||
|  |         .into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(_input: &str) -> Option<String> { | ||||||
|  |     // Used graphviz for this part | ||||||
|  |     // ```rs | ||||||
|  |     // let (_, logic_gates) = parse_input(input); | ||||||
|  |     // println!("digraph A {{"); | ||||||
|  |     // for (idx, lg) in logic_gates.iter().enumerate() { | ||||||
|  |     //     let LogicGate { | ||||||
|  |     //         input_one: i1, | ||||||
|  |     //         input_two: i2, | ||||||
|  |     //         output: o1, | ||||||
|  |     //         gate: g, | ||||||
|  |     //     } = lg; | ||||||
|  |     //     println!("{i1} -> {g:?}_{idx}"); | ||||||
|  |     //     println!("{i2} -> {g:?}_{idx}"); | ||||||
|  |     //     println!("{g:?}_{idx} -> {o1}"); | ||||||
|  |     // } | ||||||
|  |     // println!("}}"); | ||||||
|  |     // ``` | ||||||
|  |     // | ||||||
|  |     // and then pipe to dot | ||||||
|  |     // ```bash | ||||||
|  |     // ... | dot -Tsvg -Kneato > grpah.svg | ||||||
|  |     // ``` | ||||||
|  |     // | ||||||
|  |     // i looked for errors in the pattern and found below | ||||||
|  |     // solution for my input | ||||||
|  |  | ||||||
|  |     let mut res = ["fkp", "z06", "z11", "ngr", "z31", "mfm", "bpt", "krj"]; | ||||||
|  |     res.sort(); | ||||||
|  |     res.join(",").to_string().into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(24); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_one(&aoc::template::read_file("examples", 24)), | ||||||
|  |             Some(2024) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								src/bin/25.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/bin/25.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | pub fn part_one(input: &str) -> Option<usize> { | ||||||
|  |     let mut keys = Vec::new(); | ||||||
|  |     let mut locks = Vec::new(); | ||||||
|  |  | ||||||
|  |     for key_or_lock in input.split("\n\n") { | ||||||
|  |         let lock = key_or_lock | ||||||
|  |             .lines() | ||||||
|  |             .next() | ||||||
|  |             .unwrap() | ||||||
|  |             .chars() | ||||||
|  |             .all(|x| x == '#'); | ||||||
|  |  | ||||||
|  |         let mut columns = [0; 5]; | ||||||
|  |         for (idx, c) in key_or_lock.lines().flat_map(|x| x.chars().enumerate()) { | ||||||
|  |             if c == '#' { | ||||||
|  |                 columns[idx] += 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // remove top or bottom row from count | ||||||
|  |         for c in columns.iter_mut() { | ||||||
|  |             *c -= 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if lock { | ||||||
|  |             locks.push(columns); | ||||||
|  |         } else { | ||||||
|  |             keys.push(columns); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let mut count = 0; | ||||||
|  |     for k in keys.iter() { | ||||||
|  |         for l in locks.iter() { | ||||||
|  |             if k.iter().zip(l.iter()).all(|(k, l)| k + l <= 5) { | ||||||
|  |                 count += 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     count.into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(_input: &str) -> Option<String> { | ||||||
|  |     "Happy christmas!".to_string().into() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(25); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!(part_one(&aoc::template::read_file("examples", 25)), Some(3)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -43,7 +43,7 @@ impl Display for Grid { | |||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         for (idx, cell) in self.grid.iter().enumerate() { |         for (idx, cell) in self.grid.iter().enumerate() { | ||||||
|             write!(f, "{}", *cell as char)?; |             write!(f, "{}", *cell as char)?; | ||||||
|             if idx > 0 && idx % self.width == 0 { |             if idx > 0 && (idx + 1) % self.width == 0 { | ||||||
|                 writeln!(f)?; |                 writeln!(f)?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -77,10 +77,20 @@ impl Grid { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn get(&self, p: &Point) -> Option<&u8> { |     pub fn get(&self, p: &Point) -> Option<&u8> { | ||||||
|  |         if p.i >= self.grid.len() / self.width || p.j >= self.width { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|         self.grid.get(p.i * self.width + p.j) |         self.grid.get(p.i * self.width + p.j) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn get_mut(&mut self, p: &Point) -> Option<&mut u8> { |     pub fn get_mut(&mut self, p: &Point) -> Option<&mut u8> { | ||||||
|  |         if p.i >= self.grid.len() / self.width || p.j >= self.width { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|         self.grid.get_mut(p.i * self.width + p.j) |         self.grid.get_mut(p.i * self.width + p.j) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn size(&self) -> (usize, usize) { | ||||||
|  |         (self.grid.len() / self.width, self.width) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,9 +1,7 @@ | |||||||
| mod grid; |  | ||||||
| mod direction; | mod direction; | ||||||
|  | mod grid; | ||||||
| mod point; | mod point; | ||||||
|  |  | ||||||
| pub use grid::Grid; |  | ||||||
| pub use direction::Direction; | pub use direction::Direction; | ||||||
|  | pub use grid::Grid; | ||||||
| pub use point::Point; | pub use point::Point; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -89,7 +89,7 @@ impl Point { | |||||||
|  |  | ||||||
| #[macro_export] | #[macro_export] | ||||||
| macro_rules! pnt { | macro_rules! pnt { | ||||||
|     ($i:literal, $j:literal) => { |     ($i:expr, $j:expr) => { | ||||||
|         Point { i: $i, j: $j } |         Point { i: $i, j: $j } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user