Day 10&11
This commit is contained in:
parent
3eaea9577a
commit
afc1255c76
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/target
|
/target
|
||||||
result
|
result*
|
||||||
flamegraph.svg
|
flamegraph.svg
|
||||||
.direnv
|
.direnv
|
||||||
|
perf.data*
|
||||||
|
|
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -8,6 +8,12 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dbdbb2877d26e0647c6b8125802b2ecf2dc2a28d864dde41e6f9b9a54da08fe"
|
checksum = "2dbdbb2877d26e0647c6b8125802b2ecf2dc2a28d864dde41e6f9b9a54da08fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "beef"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -143,6 +149,9 @@ version = "0.1.0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "day11"
|
name = "day11"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"logos",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "day12"
|
name = "day12"
|
||||||
|
@ -217,6 +226,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -312,6 +327,29 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1"
|
||||||
|
dependencies = [
|
||||||
|
"logos-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos-derive"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c"
|
||||||
|
dependencies = [
|
||||||
|
"beef",
|
||||||
|
"fnv",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex-syntax",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -426,6 +464,12 @@ dependencies = [
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.36.4"
|
version = "0.36.4"
|
||||||
|
|
|
@ -4,16 +4,8 @@ use std::{
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn either_calories_or_blank<S: AsRef<str>>(inp: S) -> Option<usize> {
|
|
||||||
inp.as_ref().parse().ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TopThree {
|
struct TopThree([usize; 3]);
|
||||||
first: usize,
|
|
||||||
second: usize,
|
|
||||||
third: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TopCal {
|
struct TopCal {
|
||||||
|
@ -38,24 +30,36 @@ impl TopCal {
|
||||||
|
|
||||||
impl TopThree {
|
impl TopThree {
|
||||||
const fn push_sum(self, sum: usize) -> Self {
|
const fn push_sum(self, sum: usize) -> Self {
|
||||||
let (first, second, third) = if sum > self.first {
|
let new_order = if sum > self.first() {
|
||||||
(sum, self.first, self.second)
|
[sum, self.first(), self.second()]
|
||||||
} else if sum > self.second {
|
} else if sum > self.second() {
|
||||||
(self.first, sum, self.second)
|
[self.first(), sum, self.second()]
|
||||||
} else if sum > self.third {
|
} else if sum > self.third() {
|
||||||
(self.first, self.second, sum)
|
[self.first(), self.second(), sum]
|
||||||
} else {
|
} else {
|
||||||
(self.first, self.second, self.third)
|
[self.first(), self.second(), self.third()]
|
||||||
};
|
};
|
||||||
Self {
|
Self(new_order)
|
||||||
first,
|
|
||||||
second,
|
|
||||||
third,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const fn total_sum(&self) -> usize {
|
const fn total_sum(&self) -> usize {
|
||||||
self.first + self.second + self.third
|
self.first() + self.second() + self.third()
|
||||||
}
|
}
|
||||||
|
const fn nth<const N: usize>(&self) -> usize {
|
||||||
|
self.0[N]
|
||||||
|
}
|
||||||
|
const fn first(&self) -> usize {
|
||||||
|
self.nth::<0>()
|
||||||
|
}
|
||||||
|
const fn second(&self) -> usize {
|
||||||
|
self.nth::<1>()
|
||||||
|
}
|
||||||
|
const fn third(&self) -> usize {
|
||||||
|
self.nth::<2>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn either_calories_or_blank<S: AsRef<str>>(inp: S) -> Option<usize> {
|
||||||
|
inp.as_ref().parse().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
137
day10/input
Normal file
137
day10/input
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
noop
|
||||||
|
addx 7
|
||||||
|
addx -1
|
||||||
|
addx -1
|
||||||
|
addx 5
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx 3
|
||||||
|
addx 2
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
addx 10
|
||||||
|
addx -9
|
||||||
|
addx 4
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 3
|
||||||
|
addx 5
|
||||||
|
addx -40
|
||||||
|
addx 26
|
||||||
|
addx -23
|
||||||
|
addx 2
|
||||||
|
addx 5
|
||||||
|
addx 26
|
||||||
|
addx -35
|
||||||
|
addx 12
|
||||||
|
addx 2
|
||||||
|
addx 17
|
||||||
|
addx -10
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 2
|
||||||
|
addx -39
|
||||||
|
noop
|
||||||
|
addx 15
|
||||||
|
addx -12
|
||||||
|
addx 2
|
||||||
|
addx 10
|
||||||
|
noop
|
||||||
|
addx -1
|
||||||
|
addx -2
|
||||||
|
noop
|
||||||
|
addx 5
|
||||||
|
noop
|
||||||
|
addx 5
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx 4
|
||||||
|
addx -25
|
||||||
|
addx 26
|
||||||
|
addx 2
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
noop
|
||||||
|
addx -3
|
||||||
|
addx -32
|
||||||
|
addx 1
|
||||||
|
addx 4
|
||||||
|
addx -2
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx 6
|
||||||
|
addx -17
|
||||||
|
addx 27
|
||||||
|
addx -7
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
addx 3
|
||||||
|
addx -2
|
||||||
|
addx 4
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
addx -39
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 5
|
||||||
|
addx 3
|
||||||
|
addx -2
|
||||||
|
addx 2
|
||||||
|
addx 11
|
||||||
|
addx -4
|
||||||
|
addx -5
|
||||||
|
noop
|
||||||
|
addx 10
|
||||||
|
addx -18
|
||||||
|
addx 19
|
||||||
|
addx 2
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
addx 2
|
||||||
|
addx 3
|
||||||
|
addx -2
|
||||||
|
addx 2
|
||||||
|
addx -37
|
||||||
|
noop
|
||||||
|
addx 5
|
||||||
|
addx 4
|
||||||
|
addx -1
|
||||||
|
noop
|
||||||
|
addx 4
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx 4
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx 2
|
||||||
|
noop
|
||||||
|
addx 3
|
||||||
|
addx 5
|
||||||
|
noop
|
||||||
|
addx -3
|
||||||
|
addx 5
|
||||||
|
addx 5
|
||||||
|
addx 2
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx -32
|
||||||
|
noop
|
146
day10/input.test
Normal file
146
day10/input.test
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
addx 15
|
||||||
|
addx -11
|
||||||
|
addx 6
|
||||||
|
addx -3
|
||||||
|
addx 5
|
||||||
|
addx -1
|
||||||
|
addx -8
|
||||||
|
addx 13
|
||||||
|
addx 4
|
||||||
|
noop
|
||||||
|
addx -1
|
||||||
|
addx 5
|
||||||
|
addx -1
|
||||||
|
addx 5
|
||||||
|
addx -1
|
||||||
|
addx 5
|
||||||
|
addx -1
|
||||||
|
addx 5
|
||||||
|
addx -1
|
||||||
|
addx -35
|
||||||
|
addx 1
|
||||||
|
addx 24
|
||||||
|
addx -19
|
||||||
|
addx 1
|
||||||
|
addx 16
|
||||||
|
addx -11
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 21
|
||||||
|
addx -15
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx -3
|
||||||
|
addx 9
|
||||||
|
addx 1
|
||||||
|
addx -3
|
||||||
|
addx 8
|
||||||
|
addx 1
|
||||||
|
addx 5
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx -36
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx 7
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 6
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 7
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
addx -13
|
||||||
|
addx 13
|
||||||
|
addx 7
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
addx -33
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 8
|
||||||
|
noop
|
||||||
|
addx -1
|
||||||
|
addx 2
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
addx 17
|
||||||
|
addx -9
|
||||||
|
addx 1
|
||||||
|
addx 1
|
||||||
|
addx -3
|
||||||
|
addx 11
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx -13
|
||||||
|
addx -19
|
||||||
|
addx 1
|
||||||
|
addx 3
|
||||||
|
addx 26
|
||||||
|
addx -30
|
||||||
|
addx 12
|
||||||
|
addx -1
|
||||||
|
addx 3
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx -9
|
||||||
|
addx 18
|
||||||
|
addx 1
|
||||||
|
addx 2
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 9
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx -1
|
||||||
|
addx 2
|
||||||
|
addx -37
|
||||||
|
addx 1
|
||||||
|
addx 3
|
||||||
|
noop
|
||||||
|
addx 15
|
||||||
|
addx -21
|
||||||
|
addx 22
|
||||||
|
addx -6
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
addx 2
|
||||||
|
addx 1
|
||||||
|
noop
|
||||||
|
addx -10
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
addx 20
|
||||||
|
addx 1
|
||||||
|
addx 2
|
||||||
|
addx 2
|
||||||
|
addx -6
|
||||||
|
addx -11
|
||||||
|
noop
|
||||||
|
noop
|
||||||
|
noop
|
|
@ -1,3 +1,134 @@
|
||||||
fn main() {
|
use std::{
|
||||||
println!("Hello, world!");
|
fs::File,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
|
const INITIAL_REG_VALUE: i32 = 1;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
enum SolvePuzzle {
|
||||||
|
First,
|
||||||
|
#[default]
|
||||||
|
Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Instruction {
|
||||||
|
AddX(i8),
|
||||||
|
Noop,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CRT {
|
||||||
|
curr_drawing: usize,
|
||||||
|
screen: [bool; 240],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CRT {
|
||||||
|
pub fn draw(&mut self, reg: i32) {
|
||||||
|
let horizontal_position = self.curr_drawing % 40;
|
||||||
|
if (reg - 1..=reg + 1).contains(&(horizontal_position as i32)) {
|
||||||
|
self.screen[self.curr_drawing] = true;
|
||||||
|
}
|
||||||
|
self.curr_drawing += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instruction {
|
||||||
|
pub fn parse<S: AsRef<str>>(line: S) -> Self {
|
||||||
|
let line = line.as_ref();
|
||||||
|
if let Some(value) = line.strip_prefix("addx ") {
|
||||||
|
Self::AddX(value.parse().unwrap_or_default())
|
||||||
|
} else {
|
||||||
|
Self::Noop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_instruction_to_register(
|
||||||
|
reg: &mut i32,
|
||||||
|
inst: Instruction,
|
||||||
|
) -> Option<impl Iterator<Item = i32>> {
|
||||||
|
match inst {
|
||||||
|
Instruction::AddX(value) => {
|
||||||
|
let old = *reg;
|
||||||
|
*reg += value as i32;
|
||||||
|
Some(::std::iter::repeat(old).take(2))
|
||||||
|
}
|
||||||
|
Instruction::Noop => Some(::std::iter::repeat(*reg).take(1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_puzzle<R: BufRead>(reader: R) -> i32 {
|
||||||
|
let mut register_history = reader
|
||||||
|
.lines()
|
||||||
|
.map(Result::unwrap)
|
||||||
|
.map(Instruction::parse)
|
||||||
|
.scan(INITIAL_REG_VALUE, apply_instruction_to_register)
|
||||||
|
.flatten();
|
||||||
|
[19_usize, 39, 39, 39, 39, 39]
|
||||||
|
.into_iter()
|
||||||
|
.fold((0_i32, 0_usize), |(mut sum, mut idx_sum), idx| {
|
||||||
|
idx_sum += idx as usize + 1;
|
||||||
|
sum += register_history.nth(idx).unwrap() * idx_sum as i32;
|
||||||
|
(sum, idx_sum)
|
||||||
|
})
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_second_puzzle<R: BufRead>(reader: R) {
|
||||||
|
let crt: CRT = reader
|
||||||
|
.lines()
|
||||||
|
.map(Result::unwrap)
|
||||||
|
.map(Instruction::parse)
|
||||||
|
.scan(INITIAL_REG_VALUE, apply_instruction_to_register)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
for y_pos in 0..6 {
|
||||||
|
let start = 40 * y_pos;
|
||||||
|
let end = 40 * (y_pos + 1);
|
||||||
|
let output: String = crt.screen[start..end]
|
||||||
|
.iter()
|
||||||
|
.map(|is_on| match is_on {
|
||||||
|
true => "X",
|
||||||
|
false => ".",
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
println!("{output}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = ::std::env::args().skip(1);
|
||||||
|
let file = args.next().unwrap_or_else(|| String::from("./input"));
|
||||||
|
let solve = args
|
||||||
|
.next()
|
||||||
|
.map(|arg| match arg.as_str() {
|
||||||
|
"first" => SolvePuzzle::First,
|
||||||
|
"second" => SolvePuzzle::Second,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let reader = BufReader::new(File::open(file).expect("Opening file"));
|
||||||
|
match solve {
|
||||||
|
SolvePuzzle::First => {
|
||||||
|
let solution = solve_puzzle(reader);
|
||||||
|
println!("{}", solution);
|
||||||
|
}
|
||||||
|
SolvePuzzle::Second => solve_second_puzzle(reader),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromIterator<i32> for CRT {
|
||||||
|
fn from_iter<T: IntoIterator<Item = i32>>(iter: T) -> Self {
|
||||||
|
iter.into_iter().fold(
|
||||||
|
CRT {
|
||||||
|
curr_drawing: 0,
|
||||||
|
screen: [false; 240],
|
||||||
|
},
|
||||||
|
|mut crt, reg| {
|
||||||
|
crt.draw(reg);
|
||||||
|
crt
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,4 @@ build = true
|
||||||
app = true
|
app = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
logos = "0.12.1"
|
||||||
|
|
55
day11/input
Normal file
55
day11/input
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
Monkey 0:
|
||||||
|
Starting items: 74, 73, 57, 77, 74
|
||||||
|
Operation: new = old * 11
|
||||||
|
Test: divisible by 19
|
||||||
|
If true: throw to monkey 6
|
||||||
|
If false: throw to monkey 7
|
||||||
|
|
||||||
|
Monkey 1:
|
||||||
|
Starting items: 99, 77, 79
|
||||||
|
Operation: new = old + 8
|
||||||
|
Test: divisible by 2
|
||||||
|
If true: throw to monkey 6
|
||||||
|
If false: throw to monkey 0
|
||||||
|
|
||||||
|
Monkey 2:
|
||||||
|
Starting items: 64, 67, 50, 96, 89, 82, 82
|
||||||
|
Operation: new = old + 1
|
||||||
|
Test: divisible by 3
|
||||||
|
If true: throw to monkey 5
|
||||||
|
If false: throw to monkey 3
|
||||||
|
|
||||||
|
Monkey 3:
|
||||||
|
Starting items: 88
|
||||||
|
Operation: new = old * 7
|
||||||
|
Test: divisible by 17
|
||||||
|
If true: throw to monkey 5
|
||||||
|
If false: throw to monkey 4
|
||||||
|
|
||||||
|
Monkey 4:
|
||||||
|
Starting items: 80, 66, 98, 83, 70, 63, 57, 66
|
||||||
|
Operation: new = old + 4
|
||||||
|
Test: divisible by 13
|
||||||
|
If true: throw to monkey 0
|
||||||
|
If false: throw to monkey 1
|
||||||
|
|
||||||
|
Monkey 5:
|
||||||
|
Starting items: 81, 93, 90, 61, 62, 64
|
||||||
|
Operation: new = old + 7
|
||||||
|
Test: divisible by 7
|
||||||
|
If true: throw to monkey 1
|
||||||
|
If false: throw to monkey 4
|
||||||
|
|
||||||
|
Monkey 6:
|
||||||
|
Starting items: 69, 97, 88, 93
|
||||||
|
Operation: new = old * old
|
||||||
|
Test: divisible by 5
|
||||||
|
If true: throw to monkey 7
|
||||||
|
If false: throw to monkey 2
|
||||||
|
|
||||||
|
Monkey 7:
|
||||||
|
Starting items: 59, 80
|
||||||
|
Operation: new = old + 6
|
||||||
|
Test: divisible by 11
|
||||||
|
If true: throw to monkey 2
|
||||||
|
If false: throw to monkey 3
|
27
day11/input.test
Normal file
27
day11/input.test
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Monkey 0:
|
||||||
|
Starting items: 79, 98
|
||||||
|
Operation: new = old * 19
|
||||||
|
Test: divisible by 23
|
||||||
|
If true: throw to monkey 2
|
||||||
|
If false: throw to monkey 3
|
||||||
|
|
||||||
|
Monkey 1:
|
||||||
|
Starting items: 54, 65, 75, 74
|
||||||
|
Operation: new = old + 6
|
||||||
|
Test: divisible by 19
|
||||||
|
If true: throw to monkey 2
|
||||||
|
If false: throw to monkey 0
|
||||||
|
|
||||||
|
Monkey 2:
|
||||||
|
Starting items: 79, 60, 97
|
||||||
|
Operation: new = old * old
|
||||||
|
Test: divisible by 13
|
||||||
|
If true: throw to monkey 1
|
||||||
|
If false: throw to monkey 3
|
||||||
|
|
||||||
|
Monkey 3:
|
||||||
|
Starting items: 74
|
||||||
|
Operation: new = old + 3
|
||||||
|
Test: divisible by 17
|
||||||
|
If true: throw to monkey 0
|
||||||
|
If false: throw to monkey 1
|
|
@ -1,3 +1,60 @@
|
||||||
fn main() {
|
use monkey_business::MonkeyBusiness;
|
||||||
println!("Hello, world!");
|
|
||||||
|
mod monkey_business;
|
||||||
|
|
||||||
|
type WorryLevel = u64;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
enum SolvePuzzle {
|
||||||
|
First,
|
||||||
|
#[default]
|
||||||
|
Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_puzzle<const ROUNDS: usize, const DIVIDE_WORRY_LEVEL: bool>(file: &str) -> usize {
|
||||||
|
let mut monkey_business = MonkeyBusiness::parse(file).expect("Parsing file");
|
||||||
|
for _round in 0..ROUNDS {
|
||||||
|
monkey_business.play_round::<DIVIDE_WORRY_LEVEL>();
|
||||||
|
}
|
||||||
|
monkey_business.into_level_of_monkey_business()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = ::std::env::args().skip(1);
|
||||||
|
let file = args.next().unwrap_or_else(|| String::from("./input"));
|
||||||
|
let solve = args
|
||||||
|
.next()
|
||||||
|
.map(|arg| match arg.as_str() {
|
||||||
|
"first" => SolvePuzzle::First,
|
||||||
|
"second" => SolvePuzzle::Second,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let file = ::std::fs::read_to_string(file).expect("Reading file");
|
||||||
|
let solution = match solve {
|
||||||
|
SolvePuzzle::First => solve_puzzle::<20, true>(&file),
|
||||||
|
SolvePuzzle::Second => solve_puzzle::<10_000, false>(&file),
|
||||||
|
};
|
||||||
|
println!("{}", solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_on_first() {
|
||||||
|
assert_eq!(
|
||||||
|
solve_puzzle::<20, true>(include_str!("../input.test")),
|
||||||
|
10_605
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_on_second() {
|
||||||
|
assert_eq!(
|
||||||
|
solve_puzzle::<10_000, false>(include_str!("../input.test")),
|
||||||
|
2713310158
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
80
day11/src/monkey_business/mod.rs
Normal file
80
day11/src/monkey_business/mod.rs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
use std::cmp::Reverse;
|
||||||
|
|
||||||
|
use crate::WorryLevel;
|
||||||
|
|
||||||
|
mod parser;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Operation {
|
||||||
|
Add(WorryLevel),
|
||||||
|
Mul(WorryLevel),
|
||||||
|
Square,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operation {
|
||||||
|
fn apply_to(&self, item: &mut WorryLevel, lcm: &WorryLevel) {
|
||||||
|
match self {
|
||||||
|
Operation::Add(num) => *item = (*item + num) % lcm,
|
||||||
|
Operation::Mul(num) => *item = (*item * num) % lcm,
|
||||||
|
Operation::Square => *item = (*item * *item) % lcm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Monkey {
|
||||||
|
holding: Vec<WorryLevel>,
|
||||||
|
operation: Operation,
|
||||||
|
test_div_by: WorryLevel,
|
||||||
|
on_test_true_target: usize,
|
||||||
|
on_test_false_target: usize,
|
||||||
|
inspection_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MonkeyBusiness {
|
||||||
|
monkeys: Vec<Monkey>,
|
||||||
|
lcm: WorryLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MonkeyBusiness {
|
||||||
|
pub fn play_round<const DIVIDE_WORRY_LEVEL: bool>(&mut self) {
|
||||||
|
for monkey_idx in 0..self.monkeys.len() {
|
||||||
|
let new_monkey_idxs =
|
||||||
|
self.monkeys[monkey_idx].play_round::<DIVIDE_WORRY_LEVEL>(self.lcm);
|
||||||
|
let mut holding = Vec::with_capacity(self.monkeys[monkey_idx].holding.len());
|
||||||
|
::std::mem::swap(&mut holding, &mut self.monkeys[monkey_idx].holding);
|
||||||
|
for (monkey_idx, item) in new_monkey_idxs.into_iter().zip(holding) {
|
||||||
|
self.monkeys[monkey_idx].holding.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_level_of_monkey_business(mut self) -> usize {
|
||||||
|
self.monkeys
|
||||||
|
.sort_by_key(|monkey| Reverse(monkey.inspection_count));
|
||||||
|
self.monkeys
|
||||||
|
.into_iter()
|
||||||
|
.take(2)
|
||||||
|
.map(|monkey| monkey.inspection_count)
|
||||||
|
.product()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monkey {
|
||||||
|
pub fn play_round<const DIVIDE_WORRY_LEVEL: bool>(&mut self, lcm: WorryLevel) -> Vec<usize> {
|
||||||
|
let mut new_monkeys = Vec::with_capacity(self.holding.len());
|
||||||
|
for item in &mut self.holding {
|
||||||
|
self.inspection_count += 1;
|
||||||
|
self.operation.apply_to(item, &lcm);
|
||||||
|
if DIVIDE_WORRY_LEVEL {
|
||||||
|
*item = *item / 3 % lcm;
|
||||||
|
}
|
||||||
|
if *item % self.test_div_by == 0 {
|
||||||
|
new_monkeys.push(self.on_test_true_target);
|
||||||
|
} else {
|
||||||
|
new_monkeys.push(self.on_test_false_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_monkeys
|
||||||
|
}
|
||||||
|
}
|
205
day11/src/monkey_business/parser.rs
Normal file
205
day11/src/monkey_business/parser.rs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
use logos::{Lexer, Logos, Span};
|
||||||
|
|
||||||
|
use crate::WorryLevel;
|
||||||
|
|
||||||
|
use super::{Monkey, MonkeyBusiness, Operation};
|
||||||
|
|
||||||
|
#[derive(Debug, Logos, PartialEq, Eq)]
|
||||||
|
pub enum Token {
|
||||||
|
#[token("Monkey")]
|
||||||
|
Monkey,
|
||||||
|
#[regex("[0-9]+", |lex| lex.slice().parse())]
|
||||||
|
Number(WorryLevel),
|
||||||
|
#[token(":")]
|
||||||
|
Colon,
|
||||||
|
#[token("Starting items")]
|
||||||
|
StartingItems,
|
||||||
|
#[token(",")]
|
||||||
|
Comma,
|
||||||
|
#[token("Operation")]
|
||||||
|
Operation,
|
||||||
|
#[token("new")]
|
||||||
|
New,
|
||||||
|
#[token("=")]
|
||||||
|
EqualSign,
|
||||||
|
#[token("old")]
|
||||||
|
Old,
|
||||||
|
#[token("*")]
|
||||||
|
Multiplication,
|
||||||
|
#[token("+")]
|
||||||
|
Addition,
|
||||||
|
#[token("Test")]
|
||||||
|
Test,
|
||||||
|
#[token("divisible by")]
|
||||||
|
DivisibleBy,
|
||||||
|
#[token("If true")]
|
||||||
|
IfTrue,
|
||||||
|
#[token("If false")]
|
||||||
|
IfFalse,
|
||||||
|
#[token("throw to monkey")]
|
||||||
|
ThrowToMonkey,
|
||||||
|
#[regex(r"[\r\n]+")]
|
||||||
|
NewLine,
|
||||||
|
#[error]
|
||||||
|
#[regex(r"[ ]+", logos::skip)]
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
UnexpectedToken(Span, Token, Vec<Token>),
|
||||||
|
MissingToken(Vec<Token>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect(lex: &mut Lexer<Token>, expect: Token) -> Result<Token, Error> {
|
||||||
|
if let Some(next) = lex.next() {
|
||||||
|
if next == expect {
|
||||||
|
Ok(next)
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedToken(lex.span(), next, vec![expect]))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(Error::MissingToken(vec![expect]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MonkeyBusiness {
|
||||||
|
pub fn parse(source: &str) -> Result<Self, Error> {
|
||||||
|
let mut lex = Token::lexer(source);
|
||||||
|
let mut monkeys = vec![];
|
||||||
|
while !lex.remainder().is_empty() {
|
||||||
|
expect(&mut lex, Token::Monkey)?;
|
||||||
|
expect(&mut lex, Token::Number(monkeys.len() as WorryLevel))?;
|
||||||
|
expect(&mut lex, Token::Colon)?;
|
||||||
|
expect(&mut lex, Token::NewLine)?;
|
||||||
|
let monkey = Monkey::parse(&mut lex)?;
|
||||||
|
monkeys.push(monkey);
|
||||||
|
}
|
||||||
|
let lcm = monkeys.iter().map(|monkey| monkey.test_div_by).product();
|
||||||
|
// Presize the holding lists
|
||||||
|
let total_item_count: usize = monkeys.iter().map(|monkey| monkey.holding.len()).sum();
|
||||||
|
monkeys.iter_mut().for_each(|monkey| {
|
||||||
|
monkey
|
||||||
|
.holding
|
||||||
|
.reserve(total_item_count - monkey.holding.len())
|
||||||
|
});
|
||||||
|
Ok(Self { monkeys, lcm })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monkey {
|
||||||
|
fn parse(lex: &mut Lexer<Token>) -> Result<Self, Error> {
|
||||||
|
expect(lex, Token::StartingItems)?;
|
||||||
|
expect(lex, Token::Colon)?;
|
||||||
|
let holding = parse_item_list(lex)?;
|
||||||
|
expect(lex, Token::Operation)?;
|
||||||
|
expect(lex, Token::Colon)?;
|
||||||
|
let operation = Operation::parse(lex)?;
|
||||||
|
expect(lex, Token::Test)?;
|
||||||
|
expect(lex, Token::Colon)?;
|
||||||
|
let test_div_by = parse_test_div_by(lex)?;
|
||||||
|
expect(lex, Token::IfTrue)?;
|
||||||
|
expect(lex, Token::Colon)?;
|
||||||
|
expect(lex, Token::ThrowToMonkey)?;
|
||||||
|
let on_test_true_target = parse_number(lex)? as usize;
|
||||||
|
expect(lex, Token::NewLine)?;
|
||||||
|
expect(lex, Token::IfFalse)?;
|
||||||
|
expect(lex, Token::Colon)?;
|
||||||
|
expect(lex, Token::ThrowToMonkey)?;
|
||||||
|
let on_test_false_target = parse_number(lex)? as usize;
|
||||||
|
expect(lex, Token::NewLine)?;
|
||||||
|
Ok(Self {
|
||||||
|
holding,
|
||||||
|
operation,
|
||||||
|
test_div_by,
|
||||||
|
on_test_true_target,
|
||||||
|
on_test_false_target,
|
||||||
|
inspection_count: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_test_div_by(lex: &mut Lexer<Token>) -> Result<WorryLevel, Error> {
|
||||||
|
match lex.next() {
|
||||||
|
Some(Token::DivisibleBy) => {
|
||||||
|
let number = parse_number(lex)?;
|
||||||
|
expect(lex, Token::NewLine)?;
|
||||||
|
Ok(number)
|
||||||
|
}
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(
|
||||||
|
lex.span(),
|
||||||
|
token,
|
||||||
|
vec![Token::DivisibleBy],
|
||||||
|
)),
|
||||||
|
None => Err(Error::MissingToken(vec![Token::DivisibleBy])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operation {
|
||||||
|
fn parse(lex: &mut Lexer<Token>) -> Result<Self, Error> {
|
||||||
|
expect(lex, Token::New)?;
|
||||||
|
expect(lex, Token::EqualSign)?;
|
||||||
|
expect(lex, Token::Old)?;
|
||||||
|
match lex.next() {
|
||||||
|
Some(Token::Multiplication) => {
|
||||||
|
let op = match lex.next() {
|
||||||
|
Some(Token::Number(number)) => Ok(Self::Mul(number)),
|
||||||
|
Some(Token::Old) => Ok(Self::Square),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(
|
||||||
|
lex.span(),
|
||||||
|
token,
|
||||||
|
vec![Token::Number(0), Token::Old],
|
||||||
|
)),
|
||||||
|
None => Err(Error::MissingToken(vec![Token::Number(0), Token::Old])),
|
||||||
|
};
|
||||||
|
expect(lex, Token::NewLine)?;
|
||||||
|
op
|
||||||
|
}
|
||||||
|
Some(Token::Addition) => {
|
||||||
|
let number = parse_number(lex)?;
|
||||||
|
expect(lex, Token::NewLine)?;
|
||||||
|
Ok(Self::Add(number))
|
||||||
|
}
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(
|
||||||
|
lex.span(),
|
||||||
|
token,
|
||||||
|
vec![Token::Multiplication, Token::Addition],
|
||||||
|
)),
|
||||||
|
None => Err(Error::MissingToken(vec![
|
||||||
|
Token::Multiplication,
|
||||||
|
Token::Addition,
|
||||||
|
])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_item_list(lex: &mut Lexer<Token>) -> Result<Vec<WorryLevel>, Error> {
|
||||||
|
let mut ret = vec![];
|
||||||
|
loop {
|
||||||
|
ret.push(parse_number(lex)?);
|
||||||
|
match lex.next() {
|
||||||
|
Some(Token::Comma) | None => {}
|
||||||
|
Some(Token::NewLine) => break,
|
||||||
|
Some(token) => {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
lex.span(),
|
||||||
|
token,
|
||||||
|
vec![Token::NewLine, Token::Comma],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_number(lex: &mut Lexer<Token>) -> Result<WorryLevel, Error> {
|
||||||
|
match lex.next() {
|
||||||
|
Some(Token::Number(number)) => Ok(number),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(
|
||||||
|
lex.span(),
|
||||||
|
token,
|
||||||
|
vec![Token::Number(0)],
|
||||||
|
)),
|
||||||
|
None => Err(Error::MissingToken(vec![Token::Number(0)])),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue