From d6cb3aa06a525d320623b20cdb7a1533bd76a7fc Mon Sep 17 00:00:00 2001 From: Dylan Thies Date: Mon, 21 Aug 2023 07:28:54 -0400 Subject: [PATCH] day 11 done might not be clippy free --- day11/Cargo.lock | 102 +++++++++++++ day11/Cargo.toml | 13 ++ day11/src/main.rs | 370 ++++++++++++++++++++++++++++++++++++++++++++++ day11/test.txt | 55 +++++++ 4 files changed, 540 insertions(+) create mode 100644 day11/Cargo.lock create mode 100644 day11/Cargo.toml create mode 100644 day11/src/main.rs create mode 100644 day11/test.txt diff --git a/day11/Cargo.lock b/day11/Cargo.lock new file mode 100644 index 0000000..63bac3c --- /dev/null +++ b/day11/Cargo.lock @@ -0,0 +1,102 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day11" +version = "0.1.0" +dependencies = [ + "derive-getters", + "itertools", + "log", + "nom", +] + +[[package]] +name = "derive-getters" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[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 = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" diff --git a/day11/Cargo.toml b/day11/Cargo.toml new file mode 100644 index 0000000..092bd7a --- /dev/null +++ b/day11/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "day11" +version = "0.1.0" +edition = "2021" +description = "AOC 2022 Day 11" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +derive-getters = "0.3.0" +itertools = "0.11.0" +log = "0.4.20" +nom = "7.1.3" diff --git a/day11/src/main.rs b/day11/src/main.rs new file mode 100644 index 0000000..d189df9 --- /dev/null +++ b/day11/src/main.rs @@ -0,0 +1,370 @@ +#![warn(clippy::all, clippy::pedantic)] +use derive_getters::Getters; +use itertools::Itertools; +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::multispace1, + error::Error, + multi::separated_list1, + sequence::{delimited, preceded}, + IResult, Parser, +}; +use log::{debug, trace}; +use std::{ + collections::VecDeque, error, fmt::Display, fs::File, io::Read, num::ParseIntError, + str::FromStr, +}; + +pub type BoxError = std::boxed::Box< + dyn std::error::Error // must implement Error to satisfy ? + + std::marker::Send // needed for threads + + std::marker::Sync, // needed for threads +>; + +#[derive(Debug)] +enum MyParseError { + ParseIntError(ParseIntError), +} +impl error::Error for MyParseError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + // The cause is the underlying implementation error type. Is implicitly + // cast to the trait object `&error::Error`. This works because the + // underlying type already implements the `Error` trait. + Self::ParseIntError(ref e) => Some(e), + } + } +} +impl From for MyParseError { + fn from(value: ParseIntError) -> Self { + Self::ParseIntError(value) + } +} +impl Display for MyParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ParseIntError(err) => { + write!(f, "There was a problem parsing an integer: {err}") + } + } + } +} + +#[derive(Debug, Clone, Copy)] +enum Tok { + Num(u64), + Old, +} +impl Tok { + pub fn get_value_or(&self, current: u64) -> u64 { + match self { + Self::Num(i) => *i, + Self::Old => current, + } + } + pub fn parse_tok(input: &str) -> IResult<&str, Self> { + alt(( + tag("old").map(|_| Self::Old), + nom::character::complete::u64.map(Self::Num), + ))(input) + } +} +impl Default for Tok { + fn default() -> Self { + Self::Old + } +} +impl FromStr for Tok { + type Err = MyParseError; + fn from_str(s: &str) -> Result { + let val = match s { + "old" => Self::Old, + x => Self::Num(x.parse()?), + }; + Ok(val) + } +} + +#[derive(Debug, Default, Clone, Copy)] +enum Op { + Add(Tok, Tok), + Mul(Tok, Tok), + #[default] + Noop, +} +impl Op { + pub fn do_op(&self, current: u64) -> u64 { + match self { + Self::Add(a, b) => a.get_value_or(current) + b.get_value_or(current), + Self::Mul(a, b) => a.get_value_or(current) * b.get_value_or(current), + Self::Noop => panic!("No operation implemented"), + } + } + pub fn parse_op(input: &str) -> IResult<&str, Self> { + let (input, _) = tag("Operation: new = ")(input)?; + let (input, value_1) = Tok::parse_tok(input)?; + let (input, operator) = + delimited(multispace1, alt((tag("*"), tag("+"))), multispace1)(input)?; + let (input, value_2) = Tok::parse_tok(input)?; + let op = match operator { + "+" => Self::Add(value_1, value_2), + "*" => Self::Mul(value_1, value_2), + _ => Self::Noop, + }; + Ok((input, op)) + } +} + +impl FromStr for Op { + type Err = MyParseError; + fn from_str(s: &str) -> Result { + let val = match s.split_whitespace().collect::>()[..] { + ["new", "=", a, "+", b] => Self::Add(a.parse()?, b.parse()?), + ["new", "=", a, "*", b] => Self::Mul(a.parse()?, b.parse()?), + _ => Self::Noop, + }; + Ok(val) + } +} +#[derive(Debug, Default, Getters, Clone, Copy)] +struct Test { + divisor: u64, + true_to: usize, + false_to: usize, +} +impl Test { + pub fn get_to(&self, item: u64) -> usize { + match item % self.divisor { + 0 => self.true_to, + _ => self.false_to, + } + } + pub fn parse_test(input: &str) -> IResult<&str, Self> { + trace!("parse test 1"); + let (input, divisor) = + preceded(tag("Test: divisible by "), nom::character::complete::u64)(input)?; + trace!("parse test 2"); + let (input, _) = multispace1(input)?; + trace!("parse test 3"); + let (input, true_to) = match preceded( + tag("If true: throw to monkey "), + nom::character::complete::u64.map(|x| usize::try_from(x).unwrap()), + )(input){ + Err(e) => {println!("{e:?}"); Err(e)}, + x => x, + }?; + trace!("parse test 4"); + let (input, _) = multispace1(input)?; + trace!("parse test 5"); + let (input, false_to) = preceded( + tag("If false: throw to monkey "), + nom::character::complete::u64.map(|x| usize::try_from(x).unwrap()), + )(input)?; + trace!("parse test 6"); + Ok(( + input, + Self { + divisor, + true_to, + false_to, + }, + )) + } +} + +#[derive(Debug, Default, Getters, Clone)] +struct Ape { + items: VecDeque, + operation: Op, + test: Test, + inspected: u64, +} +impl Ape { + pub fn catch(&mut self, item: u64) { + self.items.push_back(item); + } + + pub fn inspect(&mut self, relief: bool) -> Option { + let relief: u64 = if relief {3} else {1}; + let item = self.items.pop_front()?; + self.inspected += 1; + Some(self.operation.do_op(item) / relief) + } + pub fn throw(&self, item: u64) -> usize { + self.test.get_to(item) + } + //impl nom::ParseTo for String{ + // todo!() + + // } + + pub fn parse_monkey(input: &str) -> IResult<&str, Self> { + trace!("parse monkey 1"); + let (input, _id) = + delimited(tag("Monkey "), nom::character::complete::u64, tag(":"))(input)?; + trace!("parse monkey 2"); + let (input, _) = multispace1(input)?; + trace!("parse monkey 3"); + let (input, items) = match preceded( + tag("Starting items: "), + separated_list1(tag(", "), nom::character::complete::u64), + )(input) + { + Err(x) => { + println!("{x:?}"); + Err(x) + } + x => x, + }?; + trace!("parse monkey 4"); + let items = VecDeque::from(items); + let (input, _) = multispace1(input)?; + trace!("parse monkey 5"); + let (input, operation) = Op::parse_op(input)?; + trace!("parse monkey 6"); + let (input, _) = multispace1(input)?; + trace!("parse monkey 7"); + let (input, test) = match Test::parse_test(input) { + Err(e) => { + println!("{e:?}"); + Err(e) + } + x => x, + }?; + trace!("parse monkey 8"); + Ok(( + input, + Self { + items, + operation, + test, + inspected: 0, + }, + )) + } +} +impl FromStr for Ape { + type Err = Error; + + fn from_str(_s: &str) -> Result { + todo!() + //Self::parse_monkey(s)?.finalize() + } +} + +#[derive(Debug, Default, Getters, Clone)] +struct Monkeys { + monkeys: Vec, +} + +impl FromStr for Monkeys { + type Err = Error; + + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl AsRef> for Monkeys { + fn as_ref(&self) -> &Vec { + self.monkeys.as_ref() + } +} +struct MonkeyReader { + buffer: String, +} +impl MonkeyReader { + pub fn new(file: &str) -> Result { + let mut f = File::open(file)?; + let mut buffer = String::new(); + f.read_to_string(&mut buffer)?; + Ok(Self { buffer }) + } +} +impl IntoIterator for MonkeyReader { + type Item = Ape; + type IntoIter = MonkeyReaderIter; + + fn into_iter(self) -> Self::IntoIter { + MonkeyReaderIter { + content: self.buffer, + } + } +} + +struct MonkeyReaderIter { + content: String, +} + +impl Iterator for MonkeyReaderIter { + type Item = Ape; + fn next(&mut self) -> Option { + match self.content.as_str() { + "" => { + trace!("done"); + None + } + x => { + trace!("Starting ape parse"); + let (input, _) = nom::combinator::opt(tag::<_, _, Error<&str>>("\n\n"))(x).ok()?; + trace!("pass the optional"); + let (input, monkey) = Ape::parse_monkey(input).ok()?; + trace!("Saving off ape"); + self.content = String::from(input); + debug!("{monkey:?}"); + Some(monkey) + } + } + } +} + +fn main() { + let mut monkeys = MonkeyReader::new("./test.txt") + .unwrap() + .into_iter() + .collect::>(); + println!("{monkeys:?}"); + //parse + + let mut monkeys_game2 = monkeys.clone(); + //game 1 + for _ in 0..20 { + for i in 0..monkeys.len() { + while let Some( item) = monkeys[i].inspect(true){ + let throw_to = monkeys[i].throw(item); + monkeys[throw_to].catch(item); + } + } + } + println!("{monkeys:?}"); + + let val = monkeys + .iter() + .map(Ape::inspected) + .sorted() + .rev() + .take(2) + .product::(); + println!("Part 1: {val}"); + + let magic = monkeys_game2.iter().map(|x| x.test().divisor()).product::(); + + for _ in 0..10_000 { + for i in 0..monkeys_game2.len() { + while let Some(item) = monkeys_game2[i].inspect(false) { + let item = item % magic; + let throw_to = monkeys_game2[i].throw(item); + monkeys_game2[throw_to].catch(item); + } + } + } + let val2 = monkeys_game2 + .iter() + .map(Ape::inspected) + .sorted() + .rev() + .take(2) + .product::(); + println!("part 2: {val2}"); +} diff --git a/day11/test.txt b/day11/test.txt new file mode 100644 index 0000000..4a9fa35 --- /dev/null +++ b/day11/test.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 65, 78 + Operation: new = old * 3 + Test: divisible by 5 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 54, 78, 86, 79, 73, 64, 85, 88 + Operation: new = old + 8 + Test: divisible by 11 + If true: throw to monkey 4 + If false: throw to monkey 7 + +Monkey 2: + Starting items: 69, 97, 77, 88, 87 + Operation: new = old + 2 + Test: divisible by 2 + If true: throw to monkey 5 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 99 + Operation: new = old + 4 + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 5 + +Monkey 4: + Starting items: 60, 57, 52 + Operation: new = old * 19 + Test: divisible by 7 + If true: throw to monkey 7 + If false: throw to monkey 6 + +Monkey 5: + Starting items: 91, 82, 85, 73, 84, 53 + Operation: new = old + 5 + Test: divisible by 3 + If true: throw to monkey 4 + If false: throw to monkey 1 + +Monkey 6: + Starting items: 88, 74, 68, 56 + Operation: new = old * old + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 54, 82, 72, 71, 53, 99, 67 + Operation: new = old + 1 + Test: divisible by 19 + If true: throw to monkey 6 + If false: throw to monkey 0 \ No newline at end of file