mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-27 13:50:32 +01:00
Compare commits
3 Commits
9b60faf4fc
...
bfa7b26c69
| Author | SHA1 | Date | |
|---|---|---|---|
| bfa7b26c69 | |||
| 9cc64a7904 | |||
| f9c977ab33 |
@@ -327,8 +327,16 @@ impl<T: AsRef<[u8]>> Index<(usize, usize)> for Grid<T> {
|
|||||||
type Output = u8;
|
type Output = u8;
|
||||||
|
|
||||||
fn index(&self, (y, x): (usize, usize)) -> &Self::Output {
|
fn index(&self, (y, x): (usize, usize)) -> &Self::Output {
|
||||||
debug_assert!(y < self.height());
|
debug_assert!(
|
||||||
debug_assert!(x < self.width());
|
y < self.height(),
|
||||||
|
"Y {y} should be lower than {}",
|
||||||
|
self.height()
|
||||||
|
);
|
||||||
|
debug_assert!(
|
||||||
|
x < self.width(),
|
||||||
|
"X {x} should be lower than {}",
|
||||||
|
self.width()
|
||||||
|
);
|
||||||
|
|
||||||
let offset = self.width * y + x;
|
let offset = self.width * y + x;
|
||||||
&self.data.as_ref()[offset]
|
&self.data.as_ref()[offset]
|
||||||
|
|||||||
@@ -1,7 +1,195 @@
|
|||||||
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
use std::collections::HashMap;
|
||||||
anyhow::bail!("Not implemented")
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::common::Grid;
|
||||||
|
use crate::common::IndexSet;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum Slope {
|
||||||
|
Level,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
impl Slope {
|
||||||
anyhow::bail!("Not implemented")
|
fn invert(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Slope::Level => Self::Level,
|
||||||
|
Slope::Up => Self::Down,
|
||||||
|
Slope::Down => Self::Up,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn combine(self, other: Self) -> Self {
|
||||||
|
match (self, other) {
|
||||||
|
(Slope::Level, next) | (next, Slope::Level) => next,
|
||||||
|
(Slope::Up, Slope::Up) => Slope::Up,
|
||||||
|
(Slope::Up, Slope::Down) | (Slope::Down, Slope::Up) => {
|
||||||
|
debug_assert!(false, "Inverted slope somehow");
|
||||||
|
Slope::Level
|
||||||
|
}
|
||||||
|
(Slope::Down, Slope::Down) => Slope::Down,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(Slope, usize, u32)>>> {
|
||||||
|
let map = Grid::new(input)?;
|
||||||
|
let width = map.width();
|
||||||
|
let height = map.height();
|
||||||
|
|
||||||
|
let is_junction = |x, y| {
|
||||||
|
let mut entrance_count = 0;
|
||||||
|
|
||||||
|
if map[(y, x + 1)] != b'#' {
|
||||||
|
entrance_count += 1;
|
||||||
|
}
|
||||||
|
if map[(y, x - 1)] != b'#' {
|
||||||
|
entrance_count += 1;
|
||||||
|
}
|
||||||
|
if map[(y - 1, x)] != b'#' {
|
||||||
|
entrance_count += 1;
|
||||||
|
}
|
||||||
|
if map[(y + 1, x)] != b'#' {
|
||||||
|
entrance_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
entrance_count >= 3
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut visited = IndexSet::with_capacity(width * height);
|
||||||
|
let mut graph = vec![vec![]; 3];
|
||||||
|
visited.insert(1); // x = 1, y = 0;
|
||||||
|
visited.insert(1 + width); // x = 1, y = 1
|
||||||
|
visited.insert(width * height - 2);
|
||||||
|
|
||||||
|
let mut nodes = HashMap::new();
|
||||||
|
nodes.insert((1, 0), 0usize);
|
||||||
|
nodes.insert((width - 2, height - 1), 1);
|
||||||
|
nodes.insert((1, 1), 2);
|
||||||
|
|
||||||
|
let mut todo_junctions = vec![(2, 1, 1)];
|
||||||
|
|
||||||
|
let mut todo_positions = Vec::new();
|
||||||
|
|
||||||
|
while let Some((id, start_x, start_y)) = todo_junctions.pop() {
|
||||||
|
todo_positions.push((0, Slope::Level, start_x, start_y));
|
||||||
|
|
||||||
|
while let Some((dist, slope, x, y)) = todo_positions.pop() {
|
||||||
|
let mut enqueue = |x: usize, y: usize, up, down| {
|
||||||
|
if map[(y, x)] == b'#' {
|
||||||
|
return;
|
||||||
|
} else if let Some(&other) = nodes.get(&(x, y)) {
|
||||||
|
if other == id {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
graph[id].push((slope, other, dist + 1));
|
||||||
|
graph[other].push((slope.invert(), id, dist + 1));
|
||||||
|
} else if visited.insert(x + y * width) {
|
||||||
|
let tile_slope = if map[(y, x)] == up {
|
||||||
|
Slope::Up
|
||||||
|
} else if map[(y, x)] == down {
|
||||||
|
Slope::Down
|
||||||
|
} else {
|
||||||
|
Slope::Level
|
||||||
|
};
|
||||||
|
let resulting_slope = slope.combine(tile_slope);
|
||||||
|
|
||||||
|
if is_junction(x, y) {
|
||||||
|
let new_id = graph.len();
|
||||||
|
nodes.insert((x, y), new_id);
|
||||||
|
graph.push(Vec::new());
|
||||||
|
graph[id].push((slope, new_id, dist + 1));
|
||||||
|
graph[new_id].push((slope.invert(), id, dist + 1));
|
||||||
|
|
||||||
|
todo_junctions.push((new_id, x, y));
|
||||||
|
} else {
|
||||||
|
todo_positions.push((dist + 1, resulting_slope, x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
enqueue(x - 1, y, b'>', b'<');
|
||||||
|
enqueue(x + 1, y, b'<', b'>');
|
||||||
|
enqueue(x, y - 1, b'v', b'^');
|
||||||
|
enqueue(x, y + 1, b'^', b'v');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(graph)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn longest_path(
|
||||||
|
pos: usize,
|
||||||
|
travelled: u32,
|
||||||
|
graph: &[Vec<(Slope, usize, u32)>],
|
||||||
|
visited: &mut HashSet<usize>,
|
||||||
|
) -> u32 {
|
||||||
|
if pos == 1 {
|
||||||
|
return travelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut best = 0;
|
||||||
|
|
||||||
|
for &(slope, other, dist) in &graph[pos] {
|
||||||
|
if !matches!(slope, Slope::Up) && visited.insert(other) {
|
||||||
|
best = Ord::max(best, longest_path(other, travelled + dist, graph, visited));
|
||||||
|
visited.remove(&other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
let graph = simplify_graph(input)?;
|
||||||
|
|
||||||
|
Ok(longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn longer_longest_path(
|
||||||
|
pos: usize,
|
||||||
|
travelled: u32,
|
||||||
|
graph: &[Vec<(Slope, usize, u32)>],
|
||||||
|
visited: &mut HashSet<usize>,
|
||||||
|
) -> u32 {
|
||||||
|
if pos == 1 {
|
||||||
|
return travelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut best = 0;
|
||||||
|
|
||||||
|
for &(_, other, dist) in &graph[pos] {
|
||||||
|
if visited.insert(other) {
|
||||||
|
best = Ord::max(
|
||||||
|
best,
|
||||||
|
longer_longest_path(other, travelled + dist, graph, visited),
|
||||||
|
);
|
||||||
|
visited.remove(&other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
let graph = simplify_graph(input)?;
|
||||||
|
|
||||||
|
Ok(longer_longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("samples/23.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
assert_eq!("94", part1(SAMPLE).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part2() {
|
||||||
|
assert_eq!("154", part2(SAMPLE).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,82 @@
|
|||||||
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
use nom::bytes::complete::tag;
|
||||||
anyhow::bail!("Not implemented")
|
use nom::combinator::map;
|
||||||
|
use nom::multi::many1;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
use nom::IResult;
|
||||||
|
use num_integer::Integer;
|
||||||
|
|
||||||
|
use crate::common::parse_input;
|
||||||
|
|
||||||
|
struct Hail {
|
||||||
|
position: [i64; 3],
|
||||||
|
speed: [i64; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hail {
|
||||||
|
fn intersect(&self, other: &Self) -> bool {
|
||||||
|
// Assumption: speed in no coordinate is 0. This happens to be true.
|
||||||
|
let multiplier = self.speed[0].lcm(&self.speed[1]);
|
||||||
|
|
||||||
|
let mult_x = multiplier / self.speed[0];
|
||||||
|
let mult_y = multiplier / self.speed[1];
|
||||||
|
|
||||||
|
// use the formula for X
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(i: &[u8]) -> IResult<&[u8], Self> {
|
||||||
|
use nom::character::complete::i64;
|
||||||
|
let parse_coordinates = |i| {
|
||||||
|
map(
|
||||||
|
tuple((terminated(i64, tag(", ")), terminated(i64, tag(", ")), i64)),
|
||||||
|
|(x, y, z)| [x, y, z],
|
||||||
|
)(i)
|
||||||
|
};
|
||||||
|
|
||||||
|
map(
|
||||||
|
tuple((
|
||||||
|
terminated(parse_coordinates, tag(" @ ")),
|
||||||
|
terminated(parse_coordinates, tag("\n")),
|
||||||
|
)),
|
||||||
|
|(position, speed)| Self { position, speed },
|
||||||
|
)(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_hail(i: &[u8]) -> IResult<&[u8], Vec<Hail>> {
|
||||||
|
many1(Hail::parse)(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
let hail = parse_input(input, parse_hail)?;
|
||||||
|
|
||||||
|
let intersections = hail
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(i, a)| {
|
||||||
|
hail[i + 1..]
|
||||||
|
.iter()
|
||||||
|
.map(move |b| (a, b))
|
||||||
|
.filter(|(a, b)| a.intersect(b))
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
Ok(intersections.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
anyhow::bail!("Not implemented")
|
anyhow::bail!("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("samples/24.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore = "not completely implemented"]
|
||||||
|
fn sample_part1() {
|
||||||
|
assert_eq!("2", part1(SAMPLE).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
23
2023/src/samples/23.txt
Normal file
23
2023/src/samples/23.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#.#####################
|
||||||
|
#.......#########...###
|
||||||
|
#######.#########.#.###
|
||||||
|
###.....#.>.>.###.#.###
|
||||||
|
###v#####.#v#.###.#.###
|
||||||
|
###.>...#.#.#.....#...#
|
||||||
|
###v###.#.#.#########.#
|
||||||
|
###...#.#.#.......#...#
|
||||||
|
#####.#.#.#######.#.###
|
||||||
|
#.....#.#.#.......#...#
|
||||||
|
#.#####.#.#.#########v#
|
||||||
|
#.#...#...#...###...>.#
|
||||||
|
#.#.#v#######v###.###v#
|
||||||
|
#...#.>.#...>.>.#.###.#
|
||||||
|
#####v#.#.###v#.#.###.#
|
||||||
|
#.....#...#...#.#.#...#
|
||||||
|
#.#########.###.#.#.###
|
||||||
|
#...###...#...#...#.###
|
||||||
|
###.###.#.###v#####v###
|
||||||
|
#...#...#.#.>.>.#.>.###
|
||||||
|
#.###.###.#.###.#.#v###
|
||||||
|
#.....###...###...#...#
|
||||||
|
#####################.#
|
||||||
5
2023/src/samples/24.txt
Normal file
5
2023/src/samples/24.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
19, 13, 30 @ -2, 1, -2
|
||||||
|
18, 19, 22 @ -1, -1, -2
|
||||||
|
20, 25, 34 @ -2, -2, -4
|
||||||
|
12, 31, 28 @ -1, -2, -1
|
||||||
|
20, 19, 15 @ 1, -5, -3
|
||||||
Reference in New Issue
Block a user