generated from janezicmatej/aoc-template
	Compare commits
	
		
			3 Commits
		
	
	
		
			0000043002
			...
			day20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 000003902f | |||
| 00000380c1 | |||
| 0000037022 | 
							
								
								
									
										197
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										197
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -17,21 +17,9 @@ version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | ||||
|  | ||||
| [[package]] | ||||
| name = "aho-corasick" | ||||
| version = "1.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" | ||||
| dependencies = [ | ||||
|  "memchr", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "aoc" | ||||
| version = "46.0.0" | ||||
| dependencies = [ | ||||
|  "z3", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "autocfg" | ||||
| @@ -60,38 +48,12 @@ version = "0.21.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" | ||||
|  | ||||
| [[package]] | ||||
| name = "bindgen" | ||||
| version = "0.66.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" | ||||
| dependencies = [ | ||||
|  "bitflags 2.4.1", | ||||
|  "cexpr", | ||||
|  "clang-sys", | ||||
|  "lazy_static", | ||||
|  "lazycell", | ||||
|  "peeking_take_while", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "regex", | ||||
|  "rustc-hash", | ||||
|  "shlex", | ||||
|  "syn 2.0.42", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "1.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||||
|  | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "2.4.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" | ||||
|  | ||||
| [[package]] | ||||
| name = "bumpalo" | ||||
| version = "3.11.1" | ||||
| @@ -110,41 +72,12 @@ version = "1.0.78" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" | ||||
|  | ||||
| [[package]] | ||||
| name = "cexpr" | ||||
| version = "0.6.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" | ||||
| dependencies = [ | ||||
|  "nom", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "cfg-if" | ||||
| version = "1.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
|  | ||||
| [[package]] | ||||
| name = "clang-sys" | ||||
| version = "1.6.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" | ||||
| dependencies = [ | ||||
|  "glob", | ||||
|  "libc", | ||||
|  "libloading", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "cmake" | ||||
| version = "0.1.50" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "core-foundation" | ||||
| version = "0.9.3" | ||||
| @@ -278,12 +211,6 @@ version = "0.28.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" | ||||
|  | ||||
| [[package]] | ||||
| name = "glob" | ||||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" | ||||
|  | ||||
| [[package]] | ||||
| name = "h2" | ||||
| version = "0.3.15" | ||||
| @@ -445,28 +372,12 @@ version = "1.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||||
|  | ||||
| [[package]] | ||||
| name = "lazycell" | ||||
| version = "1.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" | ||||
|  | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.150" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" | ||||
|  | ||||
| [[package]] | ||||
| name = "libloading" | ||||
| version = "0.7.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "winapi", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "log" | ||||
| version = "0.4.17" | ||||
| @@ -488,12 +399,6 @@ version = "0.3.16" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" | ||||
|  | ||||
| [[package]] | ||||
| name = "minimal-lexical" | ||||
| version = "0.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" | ||||
|  | ||||
| [[package]] | ||||
| name = "miniz_oxide" | ||||
| version = "0.7.1" | ||||
| @@ -532,16 +437,6 @@ dependencies = [ | ||||
|  "tempfile", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "nom" | ||||
| version = "7.1.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" | ||||
| dependencies = [ | ||||
|  "memchr", | ||||
|  "minimal-lexical", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "num_cpus" | ||||
| version = "1.15.0" | ||||
| @@ -573,7 +468,7 @@ version = "0.10.45" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" | ||||
| dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
|  "bitflags", | ||||
|  "cfg-if", | ||||
|  "foreign-types", | ||||
|  "libc", | ||||
| @@ -590,7 +485,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 1.0.107", | ||||
|  "syn", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @@ -612,12 +507,6 @@ dependencies = [ | ||||
|  "vcpkg", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "peeking_take_while" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" | ||||
|  | ||||
| [[package]] | ||||
| name = "percent-encoding" | ||||
| version = "2.2.0" | ||||
| @@ -672,38 +561,9 @@ version = "0.2.16" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" | ||||
| dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
|  "bitflags", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "1.10.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
|  "regex-automata", | ||||
|  "regex-syntax", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "regex-automata" | ||||
| version = "0.4.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
|  "regex-syntax", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "regex-syntax" | ||||
| version = "0.8.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" | ||||
|  | ||||
| [[package]] | ||||
| name = "remove_dir_all" | ||||
| version = "0.5.3" | ||||
| @@ -757,12 +617,6 @@ version = "0.1.23" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" | ||||
|  | ||||
| [[package]] | ||||
| name = "rustc-hash" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | ||||
|  | ||||
| [[package]] | ||||
| name = "ryu" | ||||
| version = "1.0.12" | ||||
| @@ -794,7 +648,7 @@ version = "2.7.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" | ||||
| dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
|  "bitflags", | ||||
|  "core-foundation", | ||||
|  "core-foundation-sys", | ||||
|  "libc", | ||||
| @@ -840,12 +694,6 @@ dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "shlex" | ||||
| version = "1.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" | ||||
|  | ||||
| [[package]] | ||||
| name = "slab" | ||||
| version = "0.4.7" | ||||
| @@ -886,24 +734,13 @@ dependencies = [ | ||||
|  "unicode-ident", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "2.0.42" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "unicode-ident", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "system-configuration" | ||||
| version = "0.5.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" | ||||
| dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
|  "bitflags", | ||||
|  "core-foundation", | ||||
|  "system-configuration-sys", | ||||
| ] | ||||
| @@ -1094,7 +931,7 @@ dependencies = [ | ||||
|  "once_cell", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 1.0.107", | ||||
|  "syn", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
|  | ||||
| @@ -1128,7 +965,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 1.0.107", | ||||
|  "syn", | ||||
|  "wasm-bindgen-backend", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
| @@ -1289,23 +1126,3 @@ dependencies = [ | ||||
|  "cfg-if", | ||||
|  "windows-sys 0.48.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "z3" | ||||
| version = "0.12.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4a7ff5718c079e7b813378d67a5bed32ccc2086f151d6185074a7e24f4a565e8" | ||||
| dependencies = [ | ||||
|  "log", | ||||
|  "z3-sys", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "z3-sys" | ||||
| version = "0.8.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d7cf70fdbc0de3f42b404f49b0d4686a82562254ea29ff0a155eef2f5430f4b0" | ||||
| dependencies = [ | ||||
|  "bindgen", | ||||
|  "cmake", | ||||
| ] | ||||
|   | ||||
| @@ -21,6 +21,4 @@ authors.workspace = true | ||||
| repository.workspace = true | ||||
|  | ||||
| [dependencies] | ||||
| # so much for no dependencies this year, but I really cba so here it is | ||||
| z3 = { version = "0.12.1", features = [ "static-link-z3" ] } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| broadcaster -> a | ||||
| %a -> inv, con | ||||
| &inv -> b | ||||
| %b -> con | ||||
| &con -> output | ||||
| @@ -1,11 +0,0 @@ | ||||
| ........... | ||||
| .....###.#. | ||||
| .###.##..#. | ||||
| ..#.#...#.. | ||||
| ....#.#.... | ||||
| .##..S####. | ||||
| .##..#...#. | ||||
| .......##.. | ||||
| .##.#.####. | ||||
| .##..##.##. | ||||
| ........... | ||||
| @@ -1,7 +0,0 @@ | ||||
| 1,0,1~1,2,1 | ||||
| 0,0,2~2,0,2 | ||||
| 0,2,3~2,2,3 | ||||
| 0,0,4~0,2,4 | ||||
| 2,0,5~2,2,5 | ||||
| 0,1,6~2,1,6 | ||||
| 1,1,9~1,1,8 | ||||
| @@ -1,23 +0,0 @@ | ||||
| #.##################### | ||||
| #.......#########...### | ||||
| #######.#########.#.### | ||||
| ###.....#.>.>.###.#.### | ||||
| ###v#####.#v#.###.#.### | ||||
| ###.>...#.#.#.....#...# | ||||
| ###v###.#.#.#########.# | ||||
| ###...#.#.#.......#...# | ||||
| #####.#.#.#######.#.### | ||||
| #.....#.#.#.......#...# | ||||
| #.#####.#.#.#########v# | ||||
| #.#...#...#...###...>.# | ||||
| #.#.#v#######v###.###v# | ||||
| #...#.>.#...>.>.#.###.# | ||||
| #####v#.#.###v#.#.###.# | ||||
| #.....#...#...#.#.#...# | ||||
| #.#########.###.#.#.### | ||||
| #...###...#...#...#.### | ||||
| ###.###.#.###v#####v### | ||||
| #...#...#.#.>.>.#.>.### | ||||
| #.###.###.#.###.#.#v### | ||||
| #.....###...###...#...# | ||||
| #####################.# | ||||
| @@ -1,5 +0,0 @@ | ||||
| 19, 13, 30 @ -2, 1, -2 | ||||
| 18, 19, 22 @ -1, -1, -2 | ||||
| 20, 25, 34 @ -2, -2, -4 | ||||
| 12, 31, 28 @ -1, -2, -1 | ||||
| 20, 19, 15 @ 1, -5, -3 | ||||
| @@ -1,13 +0,0 @@ | ||||
| jqt: rhn xhk nvd | ||||
| rsh: frs pzl lsr | ||||
| xhk: hfx | ||||
| cmg: qnr nvd lhk bvb | ||||
| rhn: xhk bvb hfx | ||||
| bvb: xhk hfx | ||||
| pzl: lsr hfx nvd | ||||
| qnr: nvd | ||||
| ntq: jqt hfx bvb xhk | ||||
| nvd: lhk | ||||
| lsr: lhk | ||||
| rzs: qnr cmg lsr rsh | ||||
| frs: qnr lhk lsr | ||||
							
								
								
									
										179
									
								
								src/bin/20.rs
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/bin/20.rs
									
									
									
									
									
								
							| @@ -1,16 +1,14 @@ | ||||
| use std::{ | ||||
|     collections::{HashMap, VecDeque}, | ||||
|     mem::swap, | ||||
|     str::FromStr, | ||||
| }; | ||||
|  | ||||
| use aoc::lcm; | ||||
|  | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| enum Module { | ||||
|     Broadcaster, | ||||
|     FlipFlop(bool), | ||||
|     Conjuction, | ||||
|     Output, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| @@ -22,8 +20,7 @@ impl FromStr for Module { | ||||
|         Ok(match s { | ||||
|             "%" => Module::FlipFlop(false), | ||||
|             "&" => Module::Conjuction, | ||||
|             "b" => Module::Broadcaster, | ||||
|             _ => return Err(ParseModuleError), | ||||
|             _ => Module::Broadcaster, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| @@ -40,18 +37,13 @@ fn parse_input(input: &str) -> Vec<Node> { | ||||
|     let mut nodes = Vec::new(); | ||||
|     let mut mapper: HashMap<String, usize> = HashMap::new(); | ||||
|  | ||||
|     let output = Node { | ||||
|         index: 0, | ||||
|         module: Module::Output, | ||||
|         inputs: Vec::new(), | ||||
|         outputs: Vec::new(), | ||||
|     }; | ||||
|     nodes.push(output); | ||||
|  | ||||
|     for line in input.lines() { | ||||
|         let (from, _) = line.split_once(" -> ").unwrap(); | ||||
|         let (module, name) = from.split_at(1); | ||||
|         let (module, mut name) = from.split_at(1); | ||||
|         let module: Module = module.parse().unwrap(); | ||||
|         if module == Module::Broadcaster { | ||||
|             name = from; | ||||
|         } | ||||
|  | ||||
|         *mapper.entry(name.to_string()).or_default() = nodes.len(); | ||||
|  | ||||
| @@ -67,11 +59,15 @@ fn parse_input(input: &str) -> Vec<Node> { | ||||
|  | ||||
|     for line in input.lines() { | ||||
|         let (from, to) = line.split_once(" -> ").unwrap(); | ||||
|         let (_, name) = from.split_at(1); | ||||
|         let (module, mut name) = from.split_at(1); | ||||
|         let module: Module = module.parse().unwrap(); | ||||
|         if module == Module::Broadcaster { | ||||
|             name = from; | ||||
|         } | ||||
|  | ||||
|         let index = mapper[name]; | ||||
|         for destination in to.split(", ") { | ||||
|             let to_index = *mapper.get(destination).unwrap_or(&0); | ||||
|             let to_index = mapper[destination]; | ||||
|             nodes[index].outputs.push(to_index); | ||||
|             nodes[to_index].inputs.push(index); | ||||
|         } | ||||
| @@ -80,101 +76,99 @@ fn parse_input(input: &str) -> Vec<Node> { | ||||
|     nodes | ||||
| } | ||||
|  | ||||
| pub fn cycle(input: &str, button_presses: Option<usize>) -> usize { | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     let mut nodes = parse_input(input); | ||||
|  | ||||
|     let mut graph = vec![vec![false; nodes.len()]; nodes.len()]; | ||||
|     let mut graph = vec![vec![None; nodes.len()]; nodes.len()]; | ||||
|  | ||||
|     let mut highs = 0; | ||||
|     let mut lows = 0; | ||||
|  | ||||
|     let broadcaster = nodes | ||||
|         .iter() | ||||
|         .find(|x| x.module == Module::Broadcaster) | ||||
|         .unwrap() | ||||
|         .find(|x| x.module == Module::Broadcaster)? | ||||
|         .index; | ||||
|  | ||||
|     let mut hm = HashMap::new(); | ||||
|     let critical_node = nodes[0].inputs.first().copied(); | ||||
|     let critical_inputs = critical_node.map(|x| nodes[x].inputs.len()); | ||||
|     for _ in 0..1000 { | ||||
|         let mut stack = VecDeque::from([broadcaster]); | ||||
|         while !stack.is_empty() { | ||||
|             let mut new_stack = VecDeque::new(); | ||||
|             let mut new_graph = graph.clone(); | ||||
|  | ||||
|     for i in 1..=button_presses.unwrap_or(usize::MAX) { | ||||
|         if let Some(c) = critical_inputs { | ||||
|             if button_presses.is_none() && hm.values().len() == c { | ||||
|                 return hm.values().copied().reduce(lcm).unwrap_or(0); | ||||
|             } | ||||
|         } | ||||
|             while let Some(index) = stack.pop_front() { | ||||
|                 let node = &nodes[index]; | ||||
|                 let mut new_module = None; | ||||
|  | ||||
|         let mut stack = VecDeque::from([(broadcaster, false)]); | ||||
|  | ||||
|         while let Some((index, signal)) = stack.pop_front() { | ||||
|             if signal { | ||||
|                 highs += 1; | ||||
|             } else { | ||||
|                 lows += 1; | ||||
|             } | ||||
|  | ||||
|             let node = &nodes[index]; | ||||
|             let mut new_module = None; | ||||
|  | ||||
|             match node.module { | ||||
|                 Module::Output => (), | ||||
|                 Module::Broadcaster => { | ||||
|                     for dest_index in node.outputs.iter().copied() { | ||||
|                         stack.push_back((dest_index, false)); | ||||
|                 match node.module { | ||||
|                     Module::Broadcaster => { | ||||
|                         for dest_index in node.outputs.iter() { | ||||
|                             new_graph[index][*dest_index] = Some(false); | ||||
|                             new_stack.push_back(*dest_index); | ||||
|                             lows += 1; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Module::FlipFlop(high) => { | ||||
|                     if !signal { | ||||
|                         let signal = !high; | ||||
|  | ||||
|                         for dest_index in nodes[index].outputs.iter().copied() { | ||||
|                             graph[index][dest_index] = signal; | ||||
|                             stack.push_back((dest_index, signal)); | ||||
|                     Module::FlipFlop(high) => { | ||||
|                         let mut swapper = None; | ||||
|                         for in_index in nodes[index].inputs.iter() { | ||||
|                             let value = &mut graph[*in_index][index]; | ||||
|                             if value.is_some() { | ||||
|                                 debug_assert!(swapper.is_none()); | ||||
|                                 swap(&mut swapper, value); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         new_module = Some(Module::FlipFlop(signal)); | ||||
|                     } | ||||
|                 } | ||||
|                 Module::Conjuction => { | ||||
|                     let mut all = true; | ||||
|                         if !swapper.unwrap() { | ||||
|                             let signal = !high; | ||||
|  | ||||
|                     for in_index in nodes[index].inputs.iter().copied() { | ||||
|                         all &= graph[in_index][index]; | ||||
|                     } | ||||
|  | ||||
|                     for dest_index in nodes[index].outputs.iter().copied() { | ||||
|                         graph[index][dest_index] = !all; | ||||
|                         stack.push_back((dest_index, !all)); | ||||
|                     } | ||||
|  | ||||
|                     if let Some(c) = critical_node { | ||||
|                         if index == c { | ||||
|                             for in_index in nodes[index].inputs.iter().copied() { | ||||
|                                 if graph[in_index][index] { | ||||
|                                     hm.entry(in_index).or_insert(i); | ||||
|                             for dest_index in nodes[index].outputs.iter() { | ||||
|                                 new_graph[index][*dest_index] = Some(signal); | ||||
|                                 new_stack.push_back(*dest_index); | ||||
|                                 if signal { | ||||
|                                     highs += 1; | ||||
|                                 } else { | ||||
|                                     lows += 1; | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
|                             new_module = Some(Module::FlipFlop(signal)); | ||||
|                         } | ||||
|                     } | ||||
|                     Module::Conjuction => { | ||||
|                         let mut all = true; | ||||
|  | ||||
|                         for in_index in nodes[index].inputs.iter() { | ||||
|                             let value = graph[*in_index][index]; | ||||
|                             all &= value.unwrap_or(false); | ||||
|                         } | ||||
|  | ||||
|                         for dest_index in nodes[index].outputs.iter() { | ||||
|                             new_graph[index][*dest_index] = Some(!all); | ||||
|                             new_stack.push_back(*dest_index); | ||||
|                             if !all { | ||||
|                                 highs += 1; | ||||
|                             } else { | ||||
|                                 lows += 1; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 let node = &mut nodes[index]; | ||||
|                 if let Some(module) = new_module { | ||||
|                     node.module = module; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             let node = &mut nodes[index]; | ||||
|             if let Some(module) = new_module { | ||||
|                 node.module = module; | ||||
|             } | ||||
|             stack = new_stack; | ||||
|             graph = new_graph; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     highs * lows | ||||
| } | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     Some(cycle(input, Some(1000))) | ||||
|     Some(highs * lows) | ||||
| } | ||||
|  | ||||
| pub fn part_two(input: &str) -> Option<usize> { | ||||
|     Some(cycle(input, None)) | ||||
| pub fn part_two(input: &str) -> Option<u32> { | ||||
|     None | ||||
| } | ||||
|  | ||||
| aoc::solution!(20); | ||||
| @@ -183,24 +177,11 @@ aoc::solution!(20); | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     #[test] | ||||
|     fn test_part_one_first() { | ||||
|         assert_eq!( | ||||
|             part_one(&aoc::template::read_file_part("examples", 20, 1)), | ||||
|             Some(32000000) | ||||
|         ); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_part_one_second() { | ||||
|         assert_eq!( | ||||
|             part_one(&aoc::template::read_file_part("examples", 20, 2)), | ||||
|             Some(11687500) | ||||
|         ); | ||||
|     fn test_part_one() { | ||||
|         assert_eq!(part_one(&aoc::template::read_file("examples", 20)), None); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_part_two() { | ||||
|         assert_eq!( | ||||
|             part_two(&aoc::template::read_file_part("examples", 20, 2)), | ||||
|             Some(1) | ||||
|         ); | ||||
|         assert_eq!(part_two(&aoc::template::read_file("examples", 20)), None); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										106
									
								
								src/bin/21.rs
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								src/bin/21.rs
									
									
									
									
									
								
							| @@ -1,106 +0,0 @@ | ||||
| use std::{collections::HashSet, usize}; | ||||
|  | ||||
| fn parse_input(input: &str) -> (Vec<Vec<u8>>, (isize, isize)) { | ||||
|     let mut grid: Vec<_> = input.lines().map(|x| x.as_bytes().to_vec()).collect(); | ||||
|  | ||||
|     let start = grid | ||||
|         .iter() | ||||
|         .enumerate() | ||||
|         .flat_map(|(y, item)| item.iter().enumerate().map(move |(x, item)| (x, y, *item))) | ||||
|         .find_map(|(x, y, s)| if s == b'S' { Some((y, x)) } else { None }) | ||||
|         .unwrap(); | ||||
|  | ||||
|     grid[start.0][start.1] = b'.'; | ||||
|  | ||||
|     (grid, (start.0 as isize, start.1 as isize)) | ||||
| } | ||||
|  | ||||
| fn walk_return_at( | ||||
|     grid: &[Vec<u8>], | ||||
|     start: (isize, isize), | ||||
|     mut returns: Vec<usize>, | ||||
|     can_cycle: bool, | ||||
| ) -> Vec<usize> { | ||||
|     returns.sort_by(|a, b| b.cmp(a)); | ||||
|  | ||||
|     let h = grid.len() as isize; | ||||
|     let w = grid[0].len() as isize; | ||||
|  | ||||
|     let invalid_indexing = |y, x| y < 0 || y >= h || x < 0 || x >= w; | ||||
|  | ||||
|     let mut results = Vec::new(); | ||||
|     let length = returns[0]; | ||||
|     let mut next = returns.pop().unwrap(); | ||||
|  | ||||
|     let mut visited = HashSet::new(); | ||||
|     visited.insert(start); | ||||
|  | ||||
|     for i in 1..=length { | ||||
|         let mut new_visited = HashSet::new(); | ||||
|  | ||||
|         for (y, x) in visited.iter() { | ||||
|             for (dy, dx) in [(1, 0), (0, 1), (-1, 0), (0, -1)] { | ||||
|                 let (ny, nx) = (y + dy, x + dx); | ||||
|  | ||||
|                 if !can_cycle && invalid_indexing(ny, nx) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 let (cy, cx) = (ny.rem_euclid(h) as usize, nx.rem_euclid(w) as usize); | ||||
|  | ||||
|                 if grid[cy][cx] == b'.' { | ||||
|                     new_visited.insert((ny, nx)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         visited = new_visited; | ||||
|  | ||||
|         if i == next { | ||||
|             results.push(visited.len()); | ||||
|             if !returns.is_empty() { | ||||
|                 next = returns.pop().unwrap(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     results | ||||
| } | ||||
|  | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     let (grid, start) = parse_input(input); | ||||
|     let result = walk_return_at(&grid, start, vec![64], false); | ||||
|  | ||||
|     Some(result[0]) | ||||
| } | ||||
|  | ||||
| pub fn part_two(input: &str) -> Option<usize> { | ||||
|     let (grid, start) = parse_input(input); | ||||
|  | ||||
|     let h = grid.len(); | ||||
|     let s = start.0 as usize; | ||||
|  | ||||
|     let result = walk_return_at(&grid, start, vec![s, s + h, s + 2 * h], true); | ||||
|  | ||||
|     let a = (result[2] - 2 * result[1] + result[0]) / 2; | ||||
|     let b = (result[1] - result[0]) - a; | ||||
|     let c = result[0]; | ||||
|  | ||||
|     let x = 26501365 / h; | ||||
|  | ||||
|     Some(a * x * x + b * x + c) | ||||
| } | ||||
|  | ||||
| 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(42) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										143
									
								
								src/bin/22.rs
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								src/bin/22.rs
									
									
									
									
									
								
							| @@ -1,143 +0,0 @@ | ||||
| use std::{collections::HashMap, str::FromStr}; | ||||
|  | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||||
| struct Brick { | ||||
|     from: (usize, usize, usize), | ||||
|     to: (usize, usize, usize), | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| struct ParseBrickError; | ||||
|  | ||||
| impl FromStr for Brick { | ||||
|     type Err = ParseBrickError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let (first, second) = s.split_once('~').ok_or(ParseBrickError)?; | ||||
|  | ||||
|         let sorted: Vec<_> = first | ||||
|             .split(',') | ||||
|             .filter_map(|y| y.parse().ok()) | ||||
|             .zip(second.split(',').filter_map(|y| y.parse().ok())) | ||||
|             .map(|(x, y)| if x < y { (x, y) } else { (y, x) }) | ||||
|             .collect(); | ||||
|         let from = (sorted[0].0, sorted[1].0, sorted[2].0); | ||||
|         let to = (sorted[0].1, sorted[1].1, sorted[2].1); | ||||
|  | ||||
|         Ok(Self { from, to }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Brick { | ||||
|     fn height(&self) -> usize { | ||||
|         self.to.2 - self.from.2 + 1 | ||||
|     } | ||||
|  | ||||
|     fn points(&self) -> impl Iterator<Item = (usize, usize, usize)> + '_ { | ||||
|         (self.from.0..=self.to.0).flat_map(move |x| { | ||||
|             (self.from.1..=self.to.1) | ||||
|                 .flat_map(move |y| (self.from.2..=self.to.2).map(move |z| (x, y, z))) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialOrd for Brick { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ord for Brick { | ||||
|     fn cmp(&self, other: &Self) -> std::cmp::Ordering { | ||||
|         self.from | ||||
|             .2 | ||||
|             .cmp(&other.from.2) | ||||
|             .then((self.from.0, self.from.1).cmp(&(other.from.0, other.from.1))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| struct Tower { | ||||
|     bricks: Vec<Brick>, | ||||
| } | ||||
|  | ||||
| impl Tower { | ||||
|     fn new(mut bricks: Vec<Brick>) -> Self { | ||||
|         bricks.sort(); | ||||
|         let mut ret = Self { bricks }; | ||||
|         ret.compress(None); | ||||
|         ret | ||||
|     } | ||||
|  | ||||
|     fn compress(&mut self, skip: Option<usize>) -> usize { | ||||
|         let mut heights: HashMap<(usize, usize), usize> = HashMap::new(); | ||||
|         let mut moved = 0; | ||||
|  | ||||
|         for brick in self | ||||
|             .bricks | ||||
|             .iter_mut() | ||||
|             .enumerate() | ||||
|             .filter(|(i, _)| *i != skip.unwrap_or(usize::MAX)) | ||||
|             .map(|(_, x)| x) | ||||
|         { | ||||
|             let height = brick.height(); | ||||
|             let new_height = brick | ||||
|                 .points() | ||||
|                 .map(|(x, y, _)| *heights.entry((x, y)).or_default()) | ||||
|                 .max() | ||||
|                 .unwrap(); | ||||
|  | ||||
|             for (x, y, _) in brick.points() { | ||||
|                 *heights.get_mut(&(x, y)).unwrap() = new_height + height; | ||||
|             } | ||||
|  | ||||
|             if new_height + 1 == brick.from.2 { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if skip.is_none() { | ||||
|                 brick.from.2 = new_height + 1; | ||||
|                 brick.to.2 = new_height + height; | ||||
|             } | ||||
|  | ||||
|             moved += 1; | ||||
|         } | ||||
|  | ||||
|         moved | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     let mut tower = Tower::new(input.lines().filter_map(|x| x.parse().ok()).collect()); | ||||
|  | ||||
|     Some( | ||||
|         (0..tower.bricks.len()) | ||||
|             .map(|i| tower.compress(Some(i))) | ||||
|             .filter(|m| *m == 0) | ||||
|             .count(), | ||||
|     ) | ||||
| } | ||||
|  | ||||
| pub fn part_two(input: &str) -> Option<usize> { | ||||
|     let mut tower = Tower::new(input.lines().filter_map(|x| x.parse().ok()).collect()); | ||||
|  | ||||
|     Some( | ||||
|         (0..tower.bricks.len()) | ||||
|             .map(|i| tower.compress(Some(i))) | ||||
|             .sum(), | ||||
|     ) | ||||
| } | ||||
|  | ||||
| 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(5)); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_part_two() { | ||||
|         assert_eq!(part_two(&aoc::template::read_file("examples", 22)), Some(7)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										161
									
								
								src/bin/23.rs
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								src/bin/23.rs
									
									
									
									
									
								
							| @@ -1,161 +0,0 @@ | ||||
| use std::{ | ||||
|     collections::{HashMap, HashSet}, | ||||
|     iter::once, | ||||
| }; | ||||
|  | ||||
| const DIRS: [(isize, isize); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)]; | ||||
|  | ||||
| #[derive(Debug, Default)] | ||||
| struct Node { | ||||
|     neighbours: Vec<(usize, usize)>, | ||||
| } | ||||
|  | ||||
| fn build_graph(input: &str, two_way: bool) -> (Vec<Node>, usize) { | ||||
|     let mut grid: Vec<Vec<_>> = input.lines().map(|x| x.as_bytes().to_vec()).collect(); | ||||
|  | ||||
|     let l = grid[0].len(); | ||||
|  | ||||
|     let border: Vec<_> = once(b'#').cycle().take(l).collect(); | ||||
|     grid.insert(0, border.clone()); | ||||
|     grid.push(border); | ||||
|  | ||||
|     let start = (1, 1); | ||||
|     let end = (grid.len() - 2, grid[0].len() - 2); | ||||
|  | ||||
|     let mut nodes = Vec::new(); | ||||
|  | ||||
|     let mut mapper = HashMap::new(); | ||||
|     mapper.insert(start, 0); | ||||
|  | ||||
|     let mut visited: HashSet<(usize, usize)> = HashSet::new(); | ||||
|  | ||||
|     let mut stack = Vec::new(); | ||||
|     // (from_node, at, len) | ||||
|     stack.push((start, start, 0)); | ||||
|  | ||||
|     let forced = |x| match x { | ||||
|         b'>' => (0, 1), | ||||
|         b'v' => (1, 0), | ||||
|         _ => (0, 0), | ||||
|     }; | ||||
|  | ||||
|     while let Some((from, (y, x), len)) = stack.pop() { | ||||
|         let is_node = DIRS | ||||
|             .iter() | ||||
|             .filter(|(dy, dx)| { | ||||
|                 grid[((y as isize) + dy) as usize][((x as isize) + dx) as usize] != b'#' | ||||
|             }) | ||||
|             .count() | ||||
|             > 2 | ||||
|             || (y, x) == start | ||||
|             || (y, x) == end; | ||||
|  | ||||
|         if is_node { | ||||
|             if !visited.contains(&(y, x)) { | ||||
|                 mapper.insert((y, x), nodes.len()); | ||||
|                 nodes.push(Node::default()); | ||||
|             } | ||||
|  | ||||
|             if from != (y, x) { | ||||
|                 nodes[mapper[&from]].neighbours.push((mapper[&(y, x)], len)); | ||||
|                 if two_way { | ||||
|                     nodes[mapper[&(y, x)]].neighbours.push((mapper[&from], len)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if !visited.insert((y, x)) { | ||||
|             continue; | ||||
|         } | ||||
|         for (ny, nx, _, _) in DIRS | ||||
|             .iter() | ||||
|             .map(|(dy, dx)| { | ||||
|                 ( | ||||
|                     ((y as isize) + dy) as usize, | ||||
|                     ((x as isize) + dx) as usize, | ||||
|                     dy, | ||||
|                     dx, | ||||
|                 ) | ||||
|             }) | ||||
|             .filter(|(ny, nx, _, _)| grid[*ny][*nx] != b'#') | ||||
|             .filter(|(ny, nx, dy, dx)| { | ||||
|                 let (fy, fx) = forced(grid[*ny][*nx]); | ||||
|                 (fy + **dy, fx + **dx) != (0, 0) | ||||
|             }) | ||||
|         { | ||||
|             let new_len = if is_node { 1 } else { len + 1 }; | ||||
|             let new_from = if is_node { (y, x) } else { from }; | ||||
|             stack.push((new_from, (ny, nx), new_len)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     (nodes, mapper[&end]) | ||||
| } | ||||
|  | ||||
| fn longest_path( | ||||
|     nodes: &[Node], | ||||
|     mut visited: usize, | ||||
|     location: usize, | ||||
|     target: usize, | ||||
|     length: usize, | ||||
| ) -> Option<usize> { | ||||
|     if location == target { | ||||
|         return Some(length); | ||||
|     } | ||||
|  | ||||
|     // binary mask for visited since < 64 nodes in input | ||||
|     // nth bit tells if location n was visited already | ||||
|     visited |= 1 << location; | ||||
|  | ||||
|     let mut max_len = 0; | ||||
|  | ||||
|     for (n, l) in nodes[location] | ||||
|         .neighbours | ||||
|         .iter() | ||||
|         .copied() | ||||
|         .filter(|(n, _)| (visited & 1 << n) == 0) | ||||
|     { | ||||
|         if let Some(new_len) = longest_path(nodes, visited, n, target, length + l) { | ||||
|             if max_len < new_len { | ||||
|                 max_len = new_len; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if max_len > 0 { | ||||
|         Some(max_len) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     let (nodes, target) = build_graph(input, false); | ||||
|     longest_path(&nodes, 0, 0, target, 0) | ||||
| } | ||||
|  | ||||
| pub fn part_two(input: &str) -> Option<usize> { | ||||
|     let (nodes, target) = build_graph(input, true); | ||||
|     longest_path(&nodes, 0, 0, target, 0) | ||||
| } | ||||
|  | ||||
| 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(94) | ||||
|         ); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_part_two() { | ||||
|         assert_eq!( | ||||
|             part_two(&aoc::template::read_file("examples", 23)), | ||||
|             Some(154) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| use z3::ast::{Ast, Int}; | ||||
|  | ||||
| type Vector3 = (f64, f64, f64); | ||||
|  | ||||
| fn parse_input(input: &str) -> Vec<(Vector3, Vector3)> { | ||||
|     input | ||||
|         .lines() | ||||
|         .filter_map(|x| x.split_once(" @ ")) | ||||
|         .map(|(a, b)| { | ||||
|             let av: Vec<_> = a.splitn(3, ", ").filter_map(|x| x.parse().ok()).collect(); | ||||
|             let bv: Vec<_> = b.splitn(3, ", ").filter_map(|x| x.parse().ok()).collect(); | ||||
|             ((av[0], av[1], av[2]), (bv[0], bv[1], bv[2])) | ||||
|         }) | ||||
|         .collect() | ||||
| } | ||||
|  | ||||
| fn part_one_with_area(input: &str, min: f64, max: f64) -> u32 { | ||||
|     let points = parse_input(input); | ||||
|  | ||||
|     let mut c = 0; | ||||
|  | ||||
|     let test_area = |x: f64, y: f64| x <= max && x >= min && y <= max && y >= min; | ||||
|  | ||||
|     for (i, ((x1, y1, _), (dx1, dy1, _))) in points.iter().copied().enumerate() { | ||||
|         for ((x2, y2, _), (dx2, dy2, _)) in points.iter().skip(i + 1).copied() { | ||||
|             let n2 = (x2 - x1 + (y1 - y2) * dx1 / dy1) / (dy2 * dx1 / dy1 - dx2); | ||||
|             let n1 = (x1 - x2 + (y2 - y1) * dx2 / dy2) / (dy1 * dx2 / dy2 - dx1); | ||||
|  | ||||
|             if n1 <= 0.0 || n2 <= 0.0 { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             let x = x1 + n1 * dx1; | ||||
|             let y = y1 + n1 * dy1; | ||||
|  | ||||
|             if test_area(x, y) { | ||||
|                 c += 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     c | ||||
| } | ||||
| pub fn part_one(input: &str) -> Option<u32> { | ||||
|     let min = 200000000000000.0; | ||||
|     let max = 400000000000000.0; | ||||
|     Some(part_one_with_area(input, min, max)) | ||||
| } | ||||
|  | ||||
| pub fn part_two(input: &str) -> Option<u64> { | ||||
|     let points = parse_input(input); | ||||
|  | ||||
|     let ctx = z3::Context::new(&z3::Config::new()); | ||||
|     let solver = z3::Solver::new(&ctx); | ||||
|  | ||||
|     let zero = Int::from_u64(&ctx, 0); | ||||
|     let [a, b, c, da, db, dc] = ["a", "b", "c", "da", "db", "dc"].map(|x| Int::new_const(&ctx, x)); | ||||
|  | ||||
|     for (i, ((x, y, z), (dx, dy, dz))) in points.iter().enumerate().take(3) { | ||||
|         let [x, y, z, dx, dy, dz] = [x, y, z, dx, dy, dz].map(|w| Int::from_i64(&ctx, *w as i64)); | ||||
|         let t = Int::new_const(&ctx, format!("t_{i}").as_str()); | ||||
|         solver.assert(&t.ge(&zero)); | ||||
|         solver.assert(&((&x + &dx * &t)._eq(&(&a + &da * &t)))); | ||||
|         solver.assert(&((&y + &dy * &t)._eq(&(&b + &db * &t)))); | ||||
|         solver.assert(&((&z + &dz * &t)._eq(&(&c + &dc * &t)))); | ||||
|     } | ||||
|  | ||||
|     solver.check(); | ||||
|     let model = solver.get_model().unwrap(); | ||||
|     let res = model.eval(&(&a + &b + &c), true).unwrap(); | ||||
|  | ||||
|     res.as_u64() | ||||
| } | ||||
|  | ||||
| aoc::solution!(24); | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     #[test] | ||||
|     fn test_part_one() { | ||||
|         let input = aoc::template::read_file("examples", 24); | ||||
|         let min = 7.0; | ||||
|         let max = 27.0; | ||||
|         assert_eq!(part_one_with_area(&input, min, max), 2); | ||||
|     } | ||||
|     #[test] | ||||
|     fn test_part_two() { | ||||
|         assert_eq!( | ||||
|             part_two(&aoc::template::read_file("examples", 24)), | ||||
|             Some(47) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,80 +0,0 @@ | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| fn build_graph(input: &str, skips: &[(&str, &str)]) -> Vec<Vec<usize>> { | ||||
|     let mut nodes = Vec::new(); | ||||
|     let mut mapper = HashMap::new(); | ||||
|  | ||||
|     for (node, neighs) in input.lines().filter_map(|x| x.split_once(": ")) { | ||||
|         if !mapper.contains_key(node) { | ||||
|             mapper.insert(node, nodes.len()); | ||||
|             nodes.push(Vec::new()); | ||||
|         } | ||||
|  | ||||
|         let index_a = mapper[node]; | ||||
|  | ||||
|         for n in neighs.split(' ') { | ||||
|             if !mapper.contains_key(n) { | ||||
|                 mapper.insert(n, nodes.len()); | ||||
|                 nodes.push(Vec::new()); | ||||
|             } | ||||
|  | ||||
|             if skips.contains(&(node, n)) || skips.contains(&(n, node)) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             let index_b = mapper[n]; | ||||
|             nodes[index_a].push(index_b); | ||||
|             nodes[index_b].push(index_a); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     nodes | ||||
| } | ||||
|  | ||||
| pub fn part_one_wrapped(input: &str, skips: &[(&str, &str)]) -> Option<usize> { | ||||
|     let nodes = build_graph(input, skips); | ||||
|  | ||||
|     let mut visited = vec![false; nodes.len()]; | ||||
|     let mut stack = vec![0]; | ||||
|  | ||||
|     while let Some(node) = stack.pop() { | ||||
|         if visited[node] { | ||||
|             continue; | ||||
|         } | ||||
|         visited[node] = true; | ||||
|         for n in nodes[node].iter().copied() { | ||||
|             if !visited[n] { | ||||
|                 stack.push(n); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     let counter = visited.iter().copied().filter(|&x| x).count(); | ||||
|     Some((nodes.len() - counter) * counter) | ||||
| } | ||||
|  | ||||
| pub fn part_one(input: &str) -> Option<usize> { | ||||
|     // to figure out which nodes to skip | ||||
|     // echo "graph A {\n$(cat data/inputs/25.txt)\n}" | \ | ||||
|     // sed 's/\(.*\): \(.*\)$/\1 -- {\2}/' | \ | ||||
|     // dot -Tsvg -Kneato > graph.svg | ||||
|     let skips = [("sfm", "vmt"), ("vph", "mfc"), ("fql", "rmg")]; | ||||
|     part_one_wrapped(input, &skips) | ||||
| } | ||||
|  | ||||
| pub fn part_two(_input: &str) -> Option<String> { | ||||
|     Some("Happy chrismas!".into()) | ||||
| } | ||||
|  | ||||
| aoc::solution!(25); | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     #[test] | ||||
|     fn test_part_one() { | ||||
|         let skips = [("pzl", "hfx"), ("bvb", "cmg"), ("nvd", "jqt")]; | ||||
|         let input = aoc::template::read_file("examples", 25); | ||||
|         assert_eq!(part_one_wrapped(&input, &skips), Some(54)); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user