day 11 done might not be clippy free

This commit is contained in:
Dylan Thies
2023-08-21 07:28:54 -04:00
parent 4fa617cfeb
commit d6cb3aa06a
4 changed files with 540 additions and 0 deletions

102
day11/Cargo.lock generated Normal file
View File

@@ -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"

13
day11/Cargo.toml Normal file
View File

@@ -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"

370
day11/src/main.rs Normal file
View File

@@ -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<ParseIntError> 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<Self, Self::Err> {
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<Self, Self::Err> {
let val = match s.split_whitespace().collect::<Vec<_>>()[..] {
["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<u64>,
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<u64> {
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<Ape> 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<String>;
fn from_str(_s: &str) -> Result<Self, Self::Err> {
todo!()
//Self::parse_monkey(s)?.finalize()
}
}
#[derive(Debug, Default, Getters, Clone)]
struct Monkeys {
monkeys: Vec<Ape>,
}
impl FromStr for Monkeys {
type Err = Error<String>;
fn from_str(_s: &str) -> Result<Self, Self::Err> {
todo!()
}
}
impl AsRef<Vec<Ape>> for Monkeys {
fn as_ref(&self) -> &Vec<Ape> {
self.monkeys.as_ref()
}
}
struct MonkeyReader {
buffer: String,
}
impl MonkeyReader {
pub fn new(file: &str) -> Result<Self, std::io::Error> {
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<Self::Item> {
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::<Vec<_>>();
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::<u64>();
println!("Part 1: {val}");
let magic = monkeys_game2.iter().map(|x| x.test().divisor()).product::<u64>();
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::<u64>();
println!("part 2: {val2}");
}

55
day11/test.txt Normal file
View File

@@ -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