mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Compare commits
4 Commits
ffe8d27469
...
b5866b2d8a
| Author | SHA1 | Date | |
|---|---|---|---|
| b5866b2d8a | |||
| 554683bc64 | |||
| 1031a8cdbb | |||
| 5c764f6627 |
@@ -7,7 +7,7 @@ use criterion::criterion_main;
|
|||||||
use criterion::BenchmarkId;
|
use criterion::BenchmarkId;
|
||||||
use criterion::Criterion;
|
use criterion::Criterion;
|
||||||
|
|
||||||
const DAYS_IMPLEMENTED: usize = 12;
|
const DAYS_IMPLEMENTED: usize = 13;
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -1,148 +1,108 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::error::Error;
|
use nom::combinator::map;
|
||||||
use nom::sequence::tuple;
|
use nom::multi::many0;
|
||||||
|
use nom::sequence::preceded;
|
||||||
|
use nom::sequence::separated_pair;
|
||||||
|
use nom::sequence::terminated;
|
||||||
use nom::Finish;
|
use nom::Finish;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
use crate::common::LineIter;
|
|
||||||
use crate::common::LineParser;
|
|
||||||
|
|
||||||
type Coords = (u16, u16);
|
type Coords = (u16, u16);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
enum Fold {
|
enum Fold {
|
||||||
X(u16),
|
X(u16),
|
||||||
Y(u16),
|
Y(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Fold {
|
fn parse_input(input: &[u8]) -> IResult<&[u8], (Vec<Coords>, Vec<Fold>)> {
|
||||||
type Err = Error<String>;
|
use nom::character::complete::char;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
let parse_coordinates = many0(terminated(parse_coordinate, char('\n')));
|
||||||
let (_, fold) = parse_fold(s)
|
let parse_folds = many0(terminated(parse_fold, char('\n')));
|
||||||
.finish()
|
|
||||||
.map_err(|Error { input, code }| Error {
|
|
||||||
input: input.to_string(),
|
|
||||||
code,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(fold)
|
separated_pair(parse_coordinates, char('\n'), parse_folds)(input)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_coordinates(input: &str) -> IResult<&str, Coords> {
|
fn parse_coordinate(input: &[u8]) -> IResult<&[u8], Coords> {
|
||||||
use nom::character::complete::char;
|
use nom::character::complete::char;
|
||||||
use nom::character::complete::u16;
|
use nom::character::complete::u16;
|
||||||
|
|
||||||
let (input, (x, _, y)) = tuple((u16, char(','), u16))(input)?;
|
separated_pair(u16, char(','), u16)(input)
|
||||||
|
|
||||||
Ok((input, (x, y)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fold(input: &str) -> IResult<&str, Fold> {
|
fn parse_fold(input: &[u8]) -> IResult<&[u8], Fold> {
|
||||||
use nom::character::complete::char;
|
|
||||||
use nom::character::complete::u16;
|
use nom::character::complete::u16;
|
||||||
|
|
||||||
let (input, (_, axis, _, coord)) = tuple((
|
preceded(
|
||||||
tag("fold along "),
|
tag("fold along "),
|
||||||
alt((char('x'), char('y'))),
|
alt((
|
||||||
char('='),
|
preceded(tag("x="), map(u16, Fold::X)),
|
||||||
u16,
|
preceded(tag("y="), map(u16, Fold::Y)),
|
||||||
))(input)?;
|
)),
|
||||||
|
)(input)
|
||||||
let fold = match axis {
|
|
||||||
'x' => Fold::X(coord),
|
|
||||||
'y' => Fold::Y(coord),
|
|
||||||
_ => unreachable!("Should be filtered by nom"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((input, fold))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_dots(reader: &mut LineIter<'_>) -> HashSet<Coords> {
|
fn read_input(input: &mut dyn Read) -> (Vec<Coords>, Vec<Fold>) {
|
||||||
let mut dots = HashSet::new();
|
let mut input_buffer = Vec::new();
|
||||||
|
input.read_to_end(&mut input_buffer).unwrap();
|
||||||
|
|
||||||
while let Some(line) = reader.next() {
|
parse_input(&input_buffer).finish().unwrap().1
|
||||||
if line.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_, coords) = parse_coordinates(line).unwrap();
|
|
||||||
|
|
||||||
dots.insert(coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
dots
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_fold(dots: &mut HashSet<Coords>, fold: Fold, to_fold: &mut Vec<Coords>) {
|
fn apply_fold(dots: &mut Vec<Coords>, fold: Fold) {
|
||||||
match fold {
|
match fold {
|
||||||
Fold::X(coord) => dots.retain(|&(x, y)| {
|
Fold::X(coord) => dots.iter_mut().for_each(|(x, _)| {
|
||||||
if x < coord {
|
if *x >= coord {
|
||||||
true
|
*x = 2 * coord - *x;
|
||||||
} else {
|
|
||||||
to_fold.push((2 * coord - x, y));
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Fold::Y(coord) => dots.retain(|&(x, y)| {
|
Fold::Y(coord) => dots.iter_mut().for_each(|(_, y)| {
|
||||||
if y < coord {
|
if *y >= coord {
|
||||||
true
|
*y = 2 * coord - *y;
|
||||||
} else {
|
|
||||||
to_fold.push((x, 2 * coord - y));
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
dots.extend(to_fold.drain(..));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_dots(dots: &HashSet<Coords>) -> String {
|
fn print_dots(dots: &[Coords]) -> String {
|
||||||
let (x, y) = dots
|
let (width, height) = dots.iter().fold((0, 0), |(xc, yc), &(xn, yn)| {
|
||||||
.iter()
|
(xc.max(xn as usize + 1), yc.max(yn as usize + 1))
|
||||||
.fold((0, 0), |(xc, yc), &(xn, yn)| (xc.max(xn), yc.max(yn)));
|
});
|
||||||
|
|
||||||
let mut buffer = String::with_capacity((x as usize + 1) * y as usize);
|
let mut buffer = vec![b' '; (width + 1) * height - 1];
|
||||||
|
|
||||||
for y in 0..=y {
|
for &(x, y) in dots {
|
||||||
for x in 0..=x {
|
buffer[x as usize + (width + 1) * y as usize] = b'#';
|
||||||
if dots.contains(&(x, y)) {
|
|
||||||
buffer.push('#');
|
|
||||||
} else {
|
|
||||||
buffer.push(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.push('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.pop();
|
for line in buffer.chunks_exact_mut(width + 1) {
|
||||||
|
line[width] = b'\n';
|
||||||
|
}
|
||||||
|
|
||||||
buffer
|
String::from_utf8(buffer).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &mut dyn Read) -> String {
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
let mut reader = LineIter::new(input);
|
let (mut dots, folds) = read_input(input);
|
||||||
|
|
||||||
let mut dots = read_dots(&mut reader);
|
apply_fold(&mut dots, folds[0]);
|
||||||
|
|
||||||
let fold = reader.next().unwrap().parse().unwrap();
|
dots.sort_unstable();
|
||||||
apply_fold(&mut dots, fold, &mut Vec::new());
|
|
||||||
|
|
||||||
dots.len().to_string()
|
dots.into_iter().unique().count().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: &mut dyn Read) -> String {
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
let mut reader = LineIter::new(input);
|
let (mut dots, folds) = read_input(input);
|
||||||
|
|
||||||
let mut dots = read_dots(&mut reader);
|
folds
|
||||||
let mut to_fold = Vec::new();
|
.into_iter()
|
||||||
|
.for_each(|fold| apply_fold(&mut dots, fold));
|
||||||
LineParser::from(reader).for_each(|fold| apply_fold(&mut dots, fold, &mut to_fold));
|
|
||||||
|
|
||||||
print_dots(&dots)
|
print_dots(&dots)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user