From a91b120155e70d5b09ac8befe67ca3899375d112 Mon Sep 17 00:00:00 2001 From: sepia Date: Fri, 13 Dec 2024 14:50:19 -0600 Subject: [PATCH] Day 13 --- Cargo.lock | 144 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/day13.rs | 95 ++++++++++++++++++++++++++ src/grammars/day13.pest | 11 +++ src/main.rs | 4 +- 5 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 src/day13.rs create mode 100644 src/grammars/day13.pest diff --git a/Cargo.lock b/Cargo.lock index 220a40a..e46adab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,8 @@ version = "0.1.0" dependencies = [ "dotenvy", "itertools", + "pest", + "pest_derive", "rayon", "regex", "reqwest", @@ -76,6 +78,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -119,6 +130,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -144,6 +164,26 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -278,6 +318,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -750,6 +800,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -1034,6 +1129,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1148,6 +1254,26 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -1238,6 +1364,18 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.14" @@ -1279,6 +1417,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 68bccab..d94af49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] dotenvy = "0.15.7" itertools = "0.13.0" +pest = "2.7.15" +pest_derive = "2.7.15" rayon = "1.10.0" regex = "1.11.1" reqwest = { version = "0.12.9", features = ["blocking"] } diff --git a/src/day13.rs b/src/day13.rs new file mode 100644 index 0000000..9fdaefb --- /dev/null +++ b/src/day13.rs @@ -0,0 +1,95 @@ +use itertools::Itertools; +use pest::{ + iterators::{Pair, Pairs}, + Parser, +}; + +const OFFSETS: (u64, u64) = (10000000000000, 10000000000000); + +pub fn day13() { + let cost: f64 = parse_machines(&crate::input(13)) + .iter() + .filter_map(|machine| { + let (c, d) = machine.prize; + let (a, b) = &machine.buttons; + + let bn = (d - c * a.y / a.x) / (b.y - b.x * a.y / a.x); + let an = (c - bn * b.x) / a.x; + + // Both solutions must be whole numbers + let winnable = [an, bn] + .iter() + .all(|&n| n >= -0.01 && (n.round() - n).abs() <= 0.01); + if winnable { + Some(an.round() * a.cost + bn.round() * b.cost) + } else { + None + } + }) + .sum(); + println!("Minimum Cost: {:?}", cost); +} + +struct Machine { + buttons: (Button, Button), + prize: (f64, f64), +} + +struct Button { + cost: f64, + x: f64, + y: f64, +} + +#[derive(pest_derive::Parser)] +#[grammar = "grammars/day13.pest"] +struct MachinesParser {} + +fn parse_machines(input: &str) -> Vec { + MachinesParser::parse(Rule::machines, input) + .unwrap() + .nth(0) + .unwrap() + .into_inner() + .map(Pair::<'_, Rule>::into_inner) + .map(Machine::parse) + .collect() +} + +impl Machine { + fn parse(input: Pairs<'_, Rule>) -> Self { + let (a, b, prize) = input.map(|p| p.into_inner()).collect_tuple().unwrap(); + + let buttons = [a, b] + .into_iter() + .map(Button::parse) + .collect_tuple() + .unwrap(); + + let prize = prize + .map(|n| n.as_str().parse::().unwrap()) + .collect_tuple() + .map(|(x, y)| ((x + OFFSETS.0) as f64, (y + OFFSETS.1) as f64)) + .unwrap(); + + Self { buttons, prize } + } +} + +impl Button { + fn parse(input: Pairs<'_, Rule>) -> Self { + let (t, x, y) = input.collect_tuple().unwrap(); + + let cost = match t.as_str() { + "A" => 3., + "B" => 1., + _ => unreachable!(), + }; + + Self { + x: x.as_str().parse::().unwrap(), + y: y.as_str().parse::().unwrap(), + cost, + } + } +} diff --git a/src/grammars/day13.pest b/src/grammars/day13.pest new file mode 100644 index 0000000..262b0ac --- /dev/null +++ b/src/grammars/day13.pest @@ -0,0 +1,11 @@ +_WHITESPACE = _{ " " } +newline = _{ "\n" } + +number = { ASCII_DIGIT+ } +button_type = { "A" | "B" } +button = { "Button " ~ button_type ~ ": X+" ~ number ~ ", Y+" ~ number ~ newline } +prize = { "Prize: X=" ~ number ~ ", Y=" ~ number ~ newline } +machine = { button ~ button ~ prize ~ newline? } + +eoi = _{ !ANY } +machines = { SOI ~ machine+ ~ eoi } diff --git a/src/main.rs b/src/main.rs index 05f718e..54691ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,10 +22,12 @@ mod day9; mod day10; #[allow(dead_code)] mod day11; +#[allow(dead_code)] mod day12; +mod day13; fn main() { - day12::day12(); + day13::day13(); } pub fn input(day: u8) -> String {