mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Compare commits
2 Commits
dfd8b2b985
...
ba1b7b693e
| Author | SHA1 | Date | |
|---|---|---|---|
| ba1b7b693e | |||
| 7d331f9131 |
@@ -7,7 +7,7 @@ use criterion::criterion_main;
|
|||||||
use criterion::BenchmarkId;
|
use criterion::BenchmarkId;
|
||||||
use criterion::Criterion;
|
use criterion::Criterion;
|
||||||
|
|
||||||
const DAYS_IMPLEMENTED: usize = 16;
|
const DAYS_IMPLEMENTED: usize = 18;
|
||||||
|
|
||||||
fn read_input(day: usize) -> Vec<u8> {
|
fn read_input(day: usize) -> Vec<u8> {
|
||||||
let input_path = format!("inputs/{:02}.txt", day);
|
let input_path = format!("inputs/{:02}.txt", day);
|
||||||
|
|||||||
100
2021/inputs/18.txt
Normal file
100
2021/inputs/18.txt
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
[[3,[[6,3],[9,6]]],[6,[[0,9],[9,7]]]]
|
||||||
|
[[[3,9],[[0,8],[7,6]]],[[[7,9],1],[1,3]]]
|
||||||
|
[8,[[[9,6],[8,4]],4]]
|
||||||
|
[5,[[1,2],[3,7]]]
|
||||||
|
[[[[7,7],5],[[3,5],8]],4]
|
||||||
|
[[[5,[0,7]],3],[[5,[5,3]],[1,[9,4]]]]
|
||||||
|
[[[[3,5],[7,1]],6],[[[3,6],[5,6]],[[3,2],5]]]
|
||||||
|
[[[[2,0],[3,0]],[5,7]],[[4,4],[[9,9],[9,3]]]]
|
||||||
|
[[[[8,0],7],[[7,1],9]],[[3,[8,6]],8]]
|
||||||
|
[[6,[7,5]],[[6,8],9]]
|
||||||
|
[[[9,[1,8]],2],[[[4,0],[9,3]],1]]
|
||||||
|
[[7,[1,[3,8]]],[[4,7],[8,1]]]
|
||||||
|
[[[5,5],[[4,5],[2,9]]],[[[7,7],0],8]]
|
||||||
|
[[[[4,7],3],5],[[[4,3],[3,8]],[[6,5],5]]]
|
||||||
|
[[[[3,8],2],[1,7]],[[[3,1],4],9]]
|
||||||
|
[[[[2,1],4],[[9,5],[1,4]]],[[3,5],[[9,1],9]]]
|
||||||
|
[[[6,[1,8]],[0,0]],[9,[0,3]]]
|
||||||
|
[[[[2,2],[3,3]],[[4,8],4]],[[[6,8],4],5]]
|
||||||
|
[4,[[[7,8],[3,4]],[[3,2],9]]]
|
||||||
|
[[[9,0],3],[[[7,1],4],7]]
|
||||||
|
[[[1,4],8],[[7,5],[[8,0],[0,7]]]]
|
||||||
|
[9,[[4,6],[[2,9],1]]]
|
||||||
|
[[[[1,8],8],6],[[[2,0],6],[0,5]]]
|
||||||
|
[[[5,5],[6,4]],[[3,8],[9,[7,6]]]]
|
||||||
|
[[0,[8,[1,4]]],2]
|
||||||
|
[[[[9,5],0],5],[9,[7,5]]]
|
||||||
|
[[9,[4,8]],[[8,1],[[8,6],[7,1]]]]
|
||||||
|
[4,[[[9,6],5],9]]
|
||||||
|
[[[[3,7],6],0],[[7,7],[[2,7],[9,3]]]]
|
||||||
|
[[[6,[3,7]],[[8,3],2]],[8,[6,[8,5]]]]
|
||||||
|
[[[5,[2,7]],[[6,7],3]],[5,[[4,4],1]]]
|
||||||
|
[[1,0],[[2,8],[[0,4],9]]]
|
||||||
|
[[[1,4],6],[[[9,8],[1,0]],1]]
|
||||||
|
[[3,4],[[1,[8,4]],8]]
|
||||||
|
[[[[9,4],[0,7]],[[5,4],[8,2]]],2]
|
||||||
|
[5,[[[8,7],[3,4]],[2,4]]]
|
||||||
|
[[[[1,3],[8,6]],[[3,4],6]],[[8,5],[[9,3],[5,7]]]]
|
||||||
|
[[0,[[0,9],[7,8]]],[3,9]]
|
||||||
|
[0,[[8,[2,3]],[[3,5],[4,9]]]]
|
||||||
|
[[[4,3],[[1,9],[1,5]]],[4,[[9,1],1]]]
|
||||||
|
[[[[3,6],[2,5]],3],[[8,[8,0]],[[6,9],[5,8]]]]
|
||||||
|
[7,[[3,[3,6]],[[6,9],[2,7]]]]
|
||||||
|
[[[[8,3],[6,5]],[[3,9],2]],[6,1]]
|
||||||
|
[[[2,0],[2,3]],8]
|
||||||
|
[[1,[[8,7],2]],[[[9,4],8],[4,[9,0]]]]
|
||||||
|
[[[6,7],[[5,2],3]],[[0,5],[[9,4],[2,6]]]]
|
||||||
|
[[[9,[5,8]],[[9,3],[6,9]]],5]
|
||||||
|
[[[5,[4,6]],[5,[3,2]]],[2,[9,[5,4]]]]
|
||||||
|
[8,6]
|
||||||
|
[[[4,8],[3,1]],[1,[[7,8],[7,5]]]]
|
||||||
|
[[4,[[8,8],4]],[5,[8,[3,9]]]]
|
||||||
|
[[[4,[9,0]],[[0,3],5]],[[5,[3,0]],[6,[2,3]]]]
|
||||||
|
[[[4,0],8],[[[4,0],7],[[9,6],3]]]
|
||||||
|
[[8,[[7,8],5]],[[[6,2],8],[1,[0,4]]]]
|
||||||
|
[[1,[[3,4],[0,8]]],[[6,5],3]]
|
||||||
|
[[5,2],[[8,6],[1,[9,7]]]]
|
||||||
|
[5,[6,[[1,3],[1,0]]]]
|
||||||
|
[[0,[[1,9],[5,6]]],[[[6,2],[5,1]],[[1,2],[1,0]]]]
|
||||||
|
[[[7,1],4],[[[0,3],3],[[4,8],1]]]
|
||||||
|
[[3,[9,[3,4]]],[1,[[0,0],[1,4]]]]
|
||||||
|
[1,[7,[1,[3,7]]]]
|
||||||
|
[[[0,[5,6]],[[7,4],[5,7]]],[[[6,8],[4,6]],9]]
|
||||||
|
[[[9,8],[7,[1,3]]],3]
|
||||||
|
[[[4,[0,3]],[[3,0],6]],[[2,[9,2]],1]]
|
||||||
|
[[[[1,9],[3,3]],[8,1]],5]
|
||||||
|
[[7,[5,2]],[[4,[0,1]],[3,3]]]
|
||||||
|
[[[6,6],[0,6]],[[3,[5,9]],[[4,2],[4,3]]]]
|
||||||
|
[[[7,[5,4]],[7,1]],9]
|
||||||
|
[[6,[5,2]],[[7,[0,5]],4]]
|
||||||
|
[[[8,1],[[7,6],[4,1]]],2]
|
||||||
|
[[[[4,3],[1,4]],[9,6]],[3,[[2,5],3]]]
|
||||||
|
[[[[9,3],[5,0]],1],[1,[[9,7],9]]]
|
||||||
|
[[[8,5],[5,9]],[2,[4,[0,0]]]]
|
||||||
|
[[[[7,9],2],[[8,8],[6,3]]],[7,[0,9]]]
|
||||||
|
[[[[6,6],[0,2]],[2,[9,0]]],[[0,9],[9,9]]]
|
||||||
|
[[[9,[1,3]],[6,5]],[[[1,1],8],[9,[7,2]]]]
|
||||||
|
[[8,[[8,4],6]],[[4,[5,9]],0]]
|
||||||
|
[[8,[5,[6,7]]],[[[1,9],9],[0,[0,9]]]]
|
||||||
|
[[9,[9,[7,3]]],[4,[4,7]]]
|
||||||
|
[[[[9,3],7],5],[[5,[8,5]],[0,[8,0]]]]
|
||||||
|
[[[5,[9,0]],[[7,4],[5,3]]],[3,[[1,1],[1,8]]]]
|
||||||
|
[[1,[[1,4],[5,9]]],[[[9,1],[6,5]],[9,[0,7]]]]
|
||||||
|
[[[[9,4],9],[5,3]],[[[4,2],[2,2]],[[1,0],0]]]
|
||||||
|
[[[6,[8,6]],9],[8,[[0,1],[9,7]]]]
|
||||||
|
[[2,0],[5,[[8,3],4]]]
|
||||||
|
[[[[0,2],0],8],[8,[[2,5],[8,2]]]]
|
||||||
|
[[[[7,4],8],[9,[7,5]]],[8,[7,[5,3]]]]
|
||||||
|
[[2,4],[3,[3,8]]]
|
||||||
|
[[5,4],[[0,[5,8]],[4,3]]]
|
||||||
|
[6,[[5,[4,7]],9]]
|
||||||
|
[[[2,[6,8]],[5,5]],[[[3,0],4],[[6,6],[0,1]]]]
|
||||||
|
[[[1,[4,2]],[[8,0],8]],[8,[[6,1],[0,0]]]]
|
||||||
|
[[9,[2,[3,3]]],[[2,6],[[5,2],[5,8]]]]
|
||||||
|
[[9,[4,4]],[[[8,6],1],2]]
|
||||||
|
[2,[[[0,7],7],[[7,8],5]]]
|
||||||
|
[[[4,0],[[1,1],[7,6]]],[[6,7],[[7,2],1]]]
|
||||||
|
[[[[2,5],0],[[9,5],9]],[6,[7,[6,1]]]]
|
||||||
|
[[[7,8],1],[[[6,2],0],[[9,7],[3,5]]]]
|
||||||
|
[[[9,1],0],[3,[[6,1],[6,9]]]]
|
||||||
|
[[[[9,0],0],[4,[7,0]]],[[6,[4,0]],[8,[4,2]]]]
|
||||||
@@ -4,6 +4,9 @@ use std::io::Read;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use nom::Finish;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
pub struct LineIter<'a> {
|
pub struct LineIter<'a> {
|
||||||
reader: BufReader<&'a mut dyn Read>,
|
reader: BufReader<&'a mut dyn Read>,
|
||||||
buffer: String,
|
buffer: String,
|
||||||
@@ -78,3 +81,15 @@ pub fn ordered<O: PartialOrd>(a: O, b: O) -> (O, O) {
|
|||||||
(b, a)
|
(b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_input<P, O>(input: &mut dyn Read, parser: P) -> O
|
||||||
|
where
|
||||||
|
P: for<'a> FnOnce(&'a [u8]) -> IResult<&'a [u8], O>,
|
||||||
|
{
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
input.read_to_end(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
let (_, output) = parser(&buffer).finish().unwrap();
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ use nom::multi::many1;
|
|||||||
use nom::multi::separated_list1;
|
use nom::multi::separated_list1;
|
||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::Finish;
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::read_input;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct BingoCard([(bool, u8); 25]);
|
struct BingoCard([(bool, u8); 25]);
|
||||||
|
|
||||||
@@ -80,16 +81,8 @@ fn parse_input(input: &[u8]) -> IResult<&[u8], (Vec<u8>, Vec<BingoCard>)> {
|
|||||||
tuple((parse_numbers, many1(parse_bingo)))(input)
|
tuple((parse_numbers, many1(parse_bingo)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_input(input: &mut dyn Read) -> (Vec<u8>, Vec<BingoCard>) {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
|
|
||||||
input.read_to_end(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
parse_input(&buffer).finish().unwrap().1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part1(input: &mut dyn Read) -> String {
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
let (numbers, mut bingo_cards) = read_input(input);
|
let (numbers, mut bingo_cards) = read_input(input, parse_input);
|
||||||
|
|
||||||
for number in numbers {
|
for number in numbers {
|
||||||
for card in &mut bingo_cards {
|
for card in &mut bingo_cards {
|
||||||
@@ -103,7 +96,7 @@ pub fn part1(input: &mut dyn Read) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: &mut dyn Read) -> String {
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
let (numbers, mut bingo_cards) = read_input(input);
|
let (numbers, mut bingo_cards) = read_input(input, parse_input);
|
||||||
let mut bingo_won = vec![false; bingo_cards.len()];
|
let mut bingo_won = vec![false; bingo_cards.len()];
|
||||||
let mut num_won = 0;
|
let mut num_won = 0;
|
||||||
let to_win = bingo_cards.len();
|
let to_win = bingo_cards.len();
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ use nom::multi::many0;
|
|||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::separated_pair;
|
use nom::sequence::separated_pair;
|
||||||
use nom::sequence::terminated;
|
use nom::sequence::terminated;
|
||||||
use nom::Finish;
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::read_input;
|
||||||
|
|
||||||
type Coords = (u16, u16);
|
type Coords = (u16, u16);
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@@ -47,13 +48,6 @@ fn parse_fold(input: &[u8]) -> IResult<&[u8], Fold> {
|
|||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_input(input: &mut dyn Read) -> (Vec<Coords>, Vec<Fold>) {
|
|
||||||
let mut input_buffer = Vec::new();
|
|
||||||
input.read_to_end(&mut input_buffer).unwrap();
|
|
||||||
|
|
||||||
parse_input(&input_buffer).finish().unwrap().1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_fold(dots: &mut Vec<Coords>, fold: Fold) {
|
fn apply_fold(dots: &mut Vec<Coords>, fold: Fold) {
|
||||||
match fold {
|
match fold {
|
||||||
Fold::X(coord) => dots.iter_mut().for_each(|(x, _)| {
|
Fold::X(coord) => dots.iter_mut().for_each(|(x, _)| {
|
||||||
@@ -88,7 +82,7 @@ fn print_dots(dots: &[Coords]) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &mut dyn Read) -> String {
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
let (mut dots, folds) = read_input(input);
|
let (mut dots, folds) = read_input(input, parse_input);
|
||||||
|
|
||||||
apply_fold(&mut dots, folds[0]);
|
apply_fold(&mut dots, folds[0]);
|
||||||
|
|
||||||
@@ -98,7 +92,7 @@ pub fn part1(input: &mut dyn Read) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: &mut dyn Read) -> String {
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
let (mut dots, folds) = read_input(input);
|
let (mut dots, folds) = read_input(input, parse_input);
|
||||||
|
|
||||||
folds
|
folds
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ use nom::bytes::complete::tag;
|
|||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::separated_pair;
|
use nom::sequence::separated_pair;
|
||||||
use nom::Finish;
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::read_input;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
|
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
|
||||||
let d = b * b - 4. * a * c;
|
let d = b * b - 4. * a * c;
|
||||||
@@ -108,10 +109,7 @@ fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclus
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &mut dyn Read) -> String {
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
let mut buffer = Vec::new();
|
let (x_range, y_range) = read_input(input, parse_input);
|
||||||
input.read_to_end(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
let (x_range, y_range) = parse_input(&buffer).finish().unwrap().1;
|
|
||||||
|
|
||||||
let check_value = |y_speed| {
|
let check_value = |y_speed| {
|
||||||
let mut time = find_hit(y_speed, &y_range)?;
|
let mut time = find_hit(y_speed, &y_range)?;
|
||||||
@@ -127,10 +125,7 @@ pub fn part1(input: &mut dyn Read) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: &mut dyn Read) -> String {
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
let mut buffer = Vec::new();
|
let (x_range, y_range) = read_input(input, parse_input);
|
||||||
input.read_to_end(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
let (x_range, y_range) = parse_input(&buffer).finish().unwrap().1;
|
|
||||||
|
|
||||||
let num_options = |y_speed| {
|
let num_options = |y_speed| {
|
||||||
let time = find_hit(y_speed, &y_range)?;
|
let time = find_hit(y_speed, &y_range)?;
|
||||||
|
|||||||
@@ -1,9 +1,245 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::mem::replace;
|
||||||
|
|
||||||
pub fn part1(_input: &mut dyn Read) -> String {
|
use nom::branch::alt;
|
||||||
todo!()
|
use nom::character::complete::newline;
|
||||||
|
use nom::combinator::map;
|
||||||
|
use nom::multi::many0;
|
||||||
|
use nom::sequence::delimited;
|
||||||
|
use nom::sequence::separated_pair;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::read_input;
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
enum TurtleNumber {
|
||||||
|
Literal(u8),
|
||||||
|
Pair(Box<(TurtleNumber, TurtleNumber)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &mut dyn Read) -> String {
|
impl TurtleNumber {
|
||||||
todo!()
|
pub fn add(self, other: Self) -> Self {
|
||||||
|
let mut new = TurtleNumber::Pair(Box::new((self, other)));
|
||||||
|
new.reduce();
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn magnitude(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
TurtleNumber::Literal(num) => *num as u32,
|
||||||
|
TurtleNumber::Pair(pair) => 3 * pair.0.magnitude() + 2 * pair.1.magnitude(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce(&mut self) {
|
||||||
|
loop {
|
||||||
|
while self.try_explode(0).is_some() {}
|
||||||
|
|
||||||
|
if self.split() {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leftmost_add(&mut self, value: u8) {
|
||||||
|
match self {
|
||||||
|
TurtleNumber::Literal(num) => *num += value,
|
||||||
|
TurtleNumber::Pair(pair) => pair.0.leftmost_add(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rightmost_add(&mut self, value: u8) {
|
||||||
|
match self {
|
||||||
|
TurtleNumber::Literal(num) => *num += value,
|
||||||
|
TurtleNumber::Pair(pair) => pair.1.rightmost_add(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_explode(&mut self, depth: usize) -> Option<(Option<u8>, Option<u8>)> {
|
||||||
|
let pair = match self {
|
||||||
|
TurtleNumber::Literal(_) => return None,
|
||||||
|
TurtleNumber::Pair(pair) => pair,
|
||||||
|
};
|
||||||
|
|
||||||
|
if depth == 4 {
|
||||||
|
let original = replace(self, TurtleNumber::Literal(0));
|
||||||
|
let pair = match original {
|
||||||
|
TurtleNumber::Pair(pair) => *pair,
|
||||||
|
_ => unreachable!("Already checked for pair above"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (TurtleNumber::Literal(first), TurtleNumber::Literal(second)) = pair {
|
||||||
|
Some((Some(first), Some(second)))
|
||||||
|
} else {
|
||||||
|
panic!("Too deeply nested turtle number: {:?}", pair);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match pair.0.try_explode(depth + 1) {
|
||||||
|
Some((left, Some(right))) => {
|
||||||
|
pair.1.leftmost_add(right);
|
||||||
|
Some((left, None))
|
||||||
|
}
|
||||||
|
Some((left, None)) => Some((left, None)),
|
||||||
|
None => match pair.1.try_explode(depth + 1) {
|
||||||
|
Some((Some(left), right)) => {
|
||||||
|
pair.0.rightmost_add(left);
|
||||||
|
Some((None, right))
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(&mut self) -> bool {
|
||||||
|
match self {
|
||||||
|
TurtleNumber::Literal(num) if *num >= 10 => {
|
||||||
|
let half = *num / 2;
|
||||||
|
let other = *num - half;
|
||||||
|
*self = TurtleNumber::from((half, other));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
TurtleNumber::Pair(pair) => pair.0.split() || pair.1.split(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TurtleNumber {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Literal(num) => write!(f, "{}", num),
|
||||||
|
Self::Pair(pair) => write!(f, "[{:?},{:?}]", pair.0, pair.1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper traits to easily convert tuples to turtle numbers
|
||||||
|
impl From<u8> for TurtleNumber {
|
||||||
|
fn from(num: u8) -> Self {
|
||||||
|
TurtleNumber::Literal(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> From<(T, U)> for TurtleNumber
|
||||||
|
where
|
||||||
|
T: Into<TurtleNumber>,
|
||||||
|
U: Into<TurtleNumber>,
|
||||||
|
{
|
||||||
|
fn from((left, right): (T, U)) -> Self {
|
||||||
|
TurtleNumber::Pair(Box::new((left.into(), right.into())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_turtle(input: &[u8]) -> IResult<&[u8], TurtleNumber> {
|
||||||
|
use nom::character::complete::char;
|
||||||
|
use nom::character::complete::u8;
|
||||||
|
|
||||||
|
alt((
|
||||||
|
map(u8, TurtleNumber::Literal),
|
||||||
|
map(
|
||||||
|
delimited(
|
||||||
|
char('['),
|
||||||
|
separated_pair(parse_turtle, char(','), parse_turtle),
|
||||||
|
char(']'),
|
||||||
|
),
|
||||||
|
|pair| TurtleNumber::Pair(Box::new(pair)),
|
||||||
|
),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<TurtleNumber>> {
|
||||||
|
many0(terminated(parse_turtle, newline))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
|
let turtles = read_input(input, parse_input);
|
||||||
|
turtles
|
||||||
|
.into_iter()
|
||||||
|
.reduce(|a, b| a.add(b))
|
||||||
|
.map(|num| num.magnitude())
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
|
let turtles = read_input(input, parse_input);
|
||||||
|
|
||||||
|
turtles
|
||||||
|
.iter()
|
||||||
|
.flat_map(|a| turtles.iter().map(|b| a.clone().add(b.clone()).magnitude()))
|
||||||
|
.max()
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::test_implementation;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("samples/18.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_magnitude() {
|
||||||
|
let num: TurtleNumber = (
|
||||||
|
(((8, 7), (7, 7)), ((8, 6), (7, 7))),
|
||||||
|
(((0, 7), (6, 6)), (8, 7)),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
assert_eq!(num.magnitude(), 3488);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add() {
|
||||||
|
let input = TurtleNumber::from(((((4, 3), 4), 4), (7, ((8, 4), 9))));
|
||||||
|
let result = input.add((1, 1).into());
|
||||||
|
|
||||||
|
let expected = TurtleNumber::from(((((0, 7), 4), ((7, 8), (6, 0))), (8, 1)));
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_explode() {
|
||||||
|
let mut input1 = TurtleNumber::from((((((9, 8), 1), 2), 3), 4));
|
||||||
|
let output1 = TurtleNumber::from(((((0, 9), 2), 3), 4));
|
||||||
|
|
||||||
|
input1.reduce();
|
||||||
|
assert_eq!(input1, output1);
|
||||||
|
|
||||||
|
let mut input2 = TurtleNumber::from((7, (6, (5, (4, (3, 2))))));
|
||||||
|
let output2 = TurtleNumber::from((7, (6, (5, (7, 0)))));
|
||||||
|
|
||||||
|
input2.reduce();
|
||||||
|
assert_eq!(input2, output2);
|
||||||
|
|
||||||
|
let mut input3: TurtleNumber = TurtleNumber::from(((6, (5, (4, (3, 2)))), 1));
|
||||||
|
let output3 = TurtleNumber::from(((6, (5, (7, 0))), 3));
|
||||||
|
|
||||||
|
input3.reduce();
|
||||||
|
assert_eq!(input3, output3);
|
||||||
|
|
||||||
|
let mut input4 = TurtleNumber::from(((3, (2, (1, (7, 3)))), (6, (5, (4, (3, 2))))));
|
||||||
|
let output4 = TurtleNumber::from(((3, (2, (8, 0))), (9, (5, (7, 0)))));
|
||||||
|
|
||||||
|
input4.reduce();
|
||||||
|
assert_eq!(input4, output4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
test_implementation(part1, SAMPLE, 4140);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part2() {
|
||||||
|
test_implementation(part2, SAMPLE, 3993);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
2021/src/samples/18.txt
Normal file
10
2021/src/samples/18.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
|
||||||
|
[[[5,[2,8]],4],[5,[[9,9],0]]]
|
||||||
|
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
|
||||||
|
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
|
||||||
|
[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]
|
||||||
|
[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]
|
||||||
|
[[[[5,4],[7,7]],8],[[8,3],8]]
|
||||||
|
[[9,3],[[9,9],[6,[4,9]]]]
|
||||||
|
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
|
||||||
|
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]
|
||||||
Reference in New Issue
Block a user