mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-28 06:10:32 +01:00
Compare commits
3 Commits
353e551f66
...
24430cf1da
| Author | SHA1 | Date | |
|---|---|---|---|
| 24430cf1da | |||
| 8faabf1220 | |||
| f15c8fbec3 |
@@ -33,7 +33,7 @@ fn number_ways(line: &[u8], groups: &[u8]) -> u64 {
|
|||||||
|
|
||||||
// Either defective or maybe defective
|
// Either defective or maybe defective
|
||||||
if c != b'.' && cur_group < usize::from(group) {
|
if c != b'.' && cur_group < usize::from(group) {
|
||||||
next[group_pos * group_stride + cur_group as usize + 1] += ways;
|
next[group_pos * group_stride + cur_group + 1] += ways;
|
||||||
}
|
}
|
||||||
|
|
||||||
if c != b'#' {
|
if c != b'#' {
|
||||||
|
|||||||
@@ -1,7 +1,147 @@
|
|||||||
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
use anyhow::Context;
|
||||||
anyhow::bail!("Not implemented")
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::bytes::complete::take;
|
||||||
|
use nom::bytes::complete::take_until;
|
||||||
|
use nom::combinator::map;
|
||||||
|
use nom::combinator::map_res;
|
||||||
|
use nom::multi::many1;
|
||||||
|
use nom::sequence::delimited;
|
||||||
|
use nom::sequence::pair;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::parse_input;
|
||||||
|
use crate::common::Direction;
|
||||||
|
|
||||||
|
struct Dig {
|
||||||
|
dir: Direction,
|
||||||
|
amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
fn parse_instructions(i: &[u8]) -> IResult<&[u8], Vec<Dig>> {
|
||||||
anyhow::bail!("Not implemented")
|
many1(terminated(
|
||||||
|
map(
|
||||||
|
pair(
|
||||||
|
terminated(
|
||||||
|
map_res(take(1usize), |c: &[u8]| {
|
||||||
|
Ok(match c[0] {
|
||||||
|
b'L' => Direction::Left,
|
||||||
|
b'U' => Direction::Up,
|
||||||
|
b'R' => Direction::Right,
|
||||||
|
b'D' => Direction::Down,
|
||||||
|
e => return Err(format!("Invalid digging direction {e}")),
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
tag(" "),
|
||||||
|
),
|
||||||
|
terminated(nom::character::complete::u64, tag(" ")),
|
||||||
|
),
|
||||||
|
|(dir, amount)| Dig { dir, amount },
|
||||||
|
),
|
||||||
|
take(10usize),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_points(instructions: &[Dig]) -> Vec<(i64, i64)> {
|
||||||
|
let mut result = Vec::with_capacity(instructions.len() + 1);
|
||||||
|
result.push((0, 0));
|
||||||
|
|
||||||
|
let mut x = 0;
|
||||||
|
let mut y = 0;
|
||||||
|
|
||||||
|
for &Dig { dir, amount } in instructions {
|
||||||
|
match dir {
|
||||||
|
Direction::Up => y -= amount as i64,
|
||||||
|
Direction::Left => x -= amount as i64,
|
||||||
|
Direction::Down => y += amount as i64,
|
||||||
|
Direction::Right => x += amount as i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push((x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(result.first(), result.last());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shoelace(points: &[(i64, i64)]) -> i64 {
|
||||||
|
points
|
||||||
|
.windows(2)
|
||||||
|
.map(|w| w[0].0 * w[1].1 - w[0].1 * w[1].0)
|
||||||
|
.sum::<i64>()
|
||||||
|
/ 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(digs: &[Dig]) -> anyhow::Result<String> {
|
||||||
|
let points = compute_points(digs);
|
||||||
|
|
||||||
|
let area = shoelace(&points);
|
||||||
|
// Assumption: we don't cross over ourselves
|
||||||
|
let perimeter = digs.iter().map(|dig| dig.amount as i64).sum::<i64>();
|
||||||
|
|
||||||
|
let total = area + perimeter / 2 + 1;
|
||||||
|
|
||||||
|
Ok(total.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
let digs = parse_input(input, parse_instructions)?;
|
||||||
|
|
||||||
|
solve(&digs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_colors(i: &[u8]) -> IResult<&[u8], Vec<Dig>> {
|
||||||
|
fn parse_color(i: &[u8]) -> anyhow::Result<u64> {
|
||||||
|
// stdlib offers hex parsing but requires going through string, incurring utf-8 validation.
|
||||||
|
// better do it ourselves.
|
||||||
|
let mut num = 0;
|
||||||
|
|
||||||
|
for &c in &i[1..] {
|
||||||
|
num *= 16;
|
||||||
|
num += (c as char).to_digit(16).context("Invalid hex")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(num.into())
|
||||||
|
}
|
||||||
|
many1(delimited(
|
||||||
|
take_until("#"),
|
||||||
|
map_res(take(7usize), |color: &[u8]| -> anyhow::Result<Dig> {
|
||||||
|
let num = parse_color(color)?;
|
||||||
|
let amount = num >> 4;
|
||||||
|
|
||||||
|
let dir = match num & 0xF {
|
||||||
|
0 => Direction::Right,
|
||||||
|
1 => Direction::Down,
|
||||||
|
2 => Direction::Left,
|
||||||
|
3 => Direction::Up,
|
||||||
|
other => anyhow::bail!("Unknown direction: {other}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Dig { dir, amount })
|
||||||
|
}),
|
||||||
|
tag(")\n"),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
let digs = parse_input(input, parse_colors)?;
|
||||||
|
solve(&digs)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("samples/18.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
assert_eq!("62", part1(SAMPLE).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part2() {
|
||||||
|
assert_eq!("952408144115", part2(SAMPLE).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
2023/src/samples/18.txt
Normal file
14
2023/src/samples/18.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
R 6 (#70c710)
|
||||||
|
D 5 (#0dc571)
|
||||||
|
L 2 (#5713f0)
|
||||||
|
D 2 (#d2c081)
|
||||||
|
R 2 (#59c680)
|
||||||
|
D 2 (#411b91)
|
||||||
|
L 5 (#8ceee2)
|
||||||
|
U 2 (#caa173)
|
||||||
|
L 1 (#1b58a2)
|
||||||
|
U 2 (#caa171)
|
||||||
|
R 2 (#7807d2)
|
||||||
|
U 3 (#a77fa3)
|
||||||
|
L 2 (#015232)
|
||||||
|
U 2 (#7a21e3)
|
||||||
Reference in New Issue
Block a user