mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-27 22:00:31 +01:00
Compare commits
4 Commits
bfa7b26c69
...
0af116920b
| Author | SHA1 | Date | |
|---|---|---|---|
| 0af116920b | |||
| 898f8dce25 | |||
| 0cce8a2045 | |||
| c80354b4af |
@@ -5,7 +5,9 @@ use nom::IResult;
|
|||||||
|
|
||||||
use crate::common::parse_input;
|
use crate::common::parse_input;
|
||||||
|
|
||||||
fn parse_reports(mut i: &[u8]) -> IResult<&[u8], (Vec<Range<usize>>, Vec<i32>)> {
|
type Input = (Vec<Range<usize>>, Vec<i32>);
|
||||||
|
|
||||||
|
fn parse_reports(mut i: &[u8]) -> IResult<&[u8], Input> {
|
||||||
let mut begin = 0;
|
let mut begin = 0;
|
||||||
let mut numbers = Vec::new();
|
let mut numbers = Vec::new();
|
||||||
let mut ranges = Vec::new();
|
let mut ranges = Vec::new();
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ fn number_ways(line: &[u8], groups: &[u8]) -> u64 {
|
|||||||
+ cur[(groups.len() - 1) * group_stride + groups[groups.len() - 1] as usize]
|
+ cur[(groups.len() - 1) * group_stride + groups[groups.len() - 1] as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lines(i: &[u8]) -> IResult<&[u8], Vec<(&[u8], Vec<u8>)>> {
|
type LineAndGroups<'a> = Vec<(&'a [u8], Vec<u8>)>;
|
||||||
|
|
||||||
|
fn parse_lines(i: &[u8]) -> IResult<&[u8], LineAndGroups> {
|
||||||
many1(terminated(
|
many1(terminated(
|
||||||
separated_pair(
|
separated_pair(
|
||||||
take_until(" "),
|
take_until(" "),
|
||||||
|
|||||||
@@ -159,7 +159,9 @@ fn parse_rule(i: &[u8]) -> IResult<&[u8], (u16, Rule)> {
|
|||||||
Ok((&i[2..], (name, Rule { checks, end })))
|
Ok((&i[2..], (name, Rule { checks, end })))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_text(i: &[u8]) -> IResult<&[u8], (Box<[Rule]>, Vec<Item>)> {
|
type RulesAndItems = (Box<[Rule]>, Vec<Item>);
|
||||||
|
|
||||||
|
fn parse_text(i: &[u8]) -> IResult<&[u8], RulesAndItems> {
|
||||||
separated_pair(
|
separated_pair(
|
||||||
fold_many1(
|
fold_many1(
|
||||||
parse_rule,
|
parse_rule,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use crate::common::Grid;
|
use crate::common::Grid;
|
||||||
use crate::common::IndexSet;
|
use crate::common::IndexSet;
|
||||||
@@ -77,7 +76,6 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(Slope, usize, u32)>>>
|
|||||||
while let Some((dist, slope, x, y)) = todo_positions.pop() {
|
while let Some((dist, slope, x, y)) = todo_positions.pop() {
|
||||||
let mut enqueue = |x: usize, y: usize, up, down| {
|
let mut enqueue = |x: usize, y: usize, up, down| {
|
||||||
if map[(y, x)] == b'#' {
|
if map[(y, x)] == b'#' {
|
||||||
return;
|
|
||||||
} else if let Some(&other) = nodes.get(&(x, y)) {
|
} else if let Some(&other) = nodes.get(&(x, y)) {
|
||||||
if other == id {
|
if other == id {
|
||||||
return;
|
return;
|
||||||
@@ -122,7 +120,7 @@ fn longest_path(
|
|||||||
pos: usize,
|
pos: usize,
|
||||||
travelled: u32,
|
travelled: u32,
|
||||||
graph: &[Vec<(Slope, usize, u32)>],
|
graph: &[Vec<(Slope, usize, u32)>],
|
||||||
visited: &mut HashSet<usize>,
|
visited: u64,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
if pos == 1 {
|
if pos == 1 {
|
||||||
return travelled;
|
return travelled;
|
||||||
@@ -131,9 +129,12 @@ fn longest_path(
|
|||||||
let mut best = 0;
|
let mut best = 0;
|
||||||
|
|
||||||
for &(slope, other, dist) in &graph[pos] {
|
for &(slope, other, dist) in &graph[pos] {
|
||||||
if !matches!(slope, Slope::Up) && visited.insert(other) {
|
let index = 1u64 << other;
|
||||||
best = Ord::max(best, longest_path(other, travelled + dist, graph, visited));
|
if !matches!(slope, Slope::Up) && (visited & index) == 0 {
|
||||||
visited.remove(&other);
|
best = Ord::max(
|
||||||
|
best,
|
||||||
|
longest_path(other, travelled + dist, graph, visited | index),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,14 +144,14 @@ fn longest_path(
|
|||||||
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
||||||
let graph = simplify_graph(input)?;
|
let graph = simplify_graph(input)?;
|
||||||
|
|
||||||
Ok(longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
|
Ok(longest_path(0, 0, &graph, 0).to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn longer_longest_path(
|
fn longer_longest_path(
|
||||||
pos: usize,
|
pos: usize,
|
||||||
travelled: u32,
|
travelled: u32,
|
||||||
graph: &[Vec<(Slope, usize, u32)>],
|
graph: &[Vec<(Slope, usize, u32)>],
|
||||||
visited: &mut HashSet<usize>,
|
visited: u64,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
if pos == 1 {
|
if pos == 1 {
|
||||||
return travelled;
|
return travelled;
|
||||||
@@ -159,12 +160,12 @@ fn longer_longest_path(
|
|||||||
let mut best = 0;
|
let mut best = 0;
|
||||||
|
|
||||||
for &(_, other, dist) in &graph[pos] {
|
for &(_, other, dist) in &graph[pos] {
|
||||||
if visited.insert(other) {
|
let index = 1u64 << other;
|
||||||
|
if (visited & index) == 0 {
|
||||||
best = Ord::max(
|
best = Ord::max(
|
||||||
best,
|
best,
|
||||||
longer_longest_path(other, travelled + dist, graph, visited),
|
longer_longest_path(other, travelled + dist, graph, visited | index),
|
||||||
);
|
);
|
||||||
visited.remove(&other);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +175,7 @@ fn longer_longest_path(
|
|||||||
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
|
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
|
||||||
let graph = simplify_graph(input)?;
|
let graph = simplify_graph(input)?;
|
||||||
|
|
||||||
Ok(longer_longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
|
Ok(longer_longest_path(0, 0, &graph, 0).to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,42 +1,69 @@
|
|||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::space1;
|
||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
use nom::multi::many1;
|
use nom::multi::many1;
|
||||||
use nom::sequence::terminated;
|
use nom::sequence::terminated;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use num_integer::Integer;
|
|
||||||
|
|
||||||
use crate::common::parse_input;
|
use crate::common::parse_input;
|
||||||
|
|
||||||
|
const EPSILON: f64 = 1e-6;
|
||||||
|
|
||||||
struct Hail {
|
struct Hail {
|
||||||
position: [i64; 3],
|
position: [i64; 3],
|
||||||
speed: [i64; 3],
|
speed: [i64; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hail {
|
impl Hail {
|
||||||
fn intersect(&self, other: &Self) -> bool {
|
// Convert to y = ax + b form
|
||||||
// Assumption: speed in no coordinate is 0. This happens to be true.
|
fn to_yab(&self) -> (f64, f64) {
|
||||||
let multiplier = self.speed[0].lcm(&self.speed[1]);
|
debug_assert_ne!(0, self.speed[0]);
|
||||||
|
|
||||||
let mult_x = multiplier / self.speed[0];
|
let slope = self.speed[1] as f64 / self.speed[0] as f64;
|
||||||
let mult_y = multiplier / self.speed[1];
|
let offset = self.position[1] as f64 - self.position[0] as f64 * slope;
|
||||||
|
|
||||||
|
(slope, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect(&self, other: &Self, min: f64, max: f64) -> bool {
|
||||||
|
let (a1, b1) = self.to_yab();
|
||||||
|
let (a2, b2) = other.to_yab();
|
||||||
|
|
||||||
|
if (a1 - a2).abs() < EPSILON {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = a1 - a2;
|
||||||
|
let b = b2 - b1;
|
||||||
|
|
||||||
|
let x = b / a;
|
||||||
|
let y = a1 * x + b1;
|
||||||
|
|
||||||
|
let t1 = (x - self.position[0] as f64) / self.speed[0] as f64;
|
||||||
|
let t2 = (x - other.position[0] as f64) / other.speed[0] as f64;
|
||||||
|
|
||||||
|
if t1 < 0.0 || t2 < 0.0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// use the formula for X
|
// use the formula for X
|
||||||
false
|
x >= min && x <= max && y >= min && y <= max
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(i: &[u8]) -> IResult<&[u8], Self> {
|
fn parse(i: &[u8]) -> IResult<&[u8], Self> {
|
||||||
use nom::character::complete::i64;
|
use nom::character::complete::i64;
|
||||||
let parse_coordinates = |i| {
|
let sep = |i| tuple((tag(","), space1))(i);
|
||||||
|
let parse_coordinates = move |i| {
|
||||||
map(
|
map(
|
||||||
tuple((terminated(i64, tag(", ")), terminated(i64, tag(", ")), i64)),
|
tuple((terminated(i64, sep), terminated(i64, sep), i64)),
|
||||||
|(x, y, z)| [x, y, z],
|
|(x, y, z)| [x, y, z],
|
||||||
)(i)
|
)(i)
|
||||||
};
|
};
|
||||||
|
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
terminated(parse_coordinates, tag(" @ ")),
|
terminated(parse_coordinates, tuple((tag(" @"), space1))),
|
||||||
terminated(parse_coordinates, tag("\n")),
|
terminated(parse_coordinates, tag("\n")),
|
||||||
)),
|
)),
|
||||||
|(position, speed)| Self { position, speed },
|
|(position, speed)| Self { position, speed },
|
||||||
@@ -47,7 +74,7 @@ fn parse_hail(i: &[u8]) -> IResult<&[u8], Vec<Hail>> {
|
|||||||
many1(Hail::parse)(i)
|
many1(Hail::parse)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
fn part1_parametrized(input: &[u8], min: f64, max: f64) -> anyhow::Result<String> {
|
||||||
let hail = parse_input(input, parse_hail)?;
|
let hail = parse_input(input, parse_hail)?;
|
||||||
|
|
||||||
let intersections = hail
|
let intersections = hail
|
||||||
@@ -57,13 +84,17 @@ pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
|||||||
hail[i + 1..]
|
hail[i + 1..]
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |b| (a, b))
|
.map(move |b| (a, b))
|
||||||
.filter(|(a, b)| a.intersect(b))
|
.filter(|(a, b)| a.intersect(b, min, max))
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
Ok(intersections.to_string())
|
Ok(intersections.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
part1_parametrized(input, 200000000000000.0, 400000000000000.0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
anyhow::bail!("Not implemented")
|
anyhow::bail!("Not implemented")
|
||||||
}
|
}
|
||||||
@@ -75,8 +106,7 @@ mod tests {
|
|||||||
const SAMPLE: &[u8] = include_bytes!("samples/24.txt");
|
const SAMPLE: &[u8] = include_bytes!("samples/24.txt");
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "not completely implemented"]
|
|
||||||
fn sample_part1() {
|
fn sample_part1() {
|
||||||
assert_eq!("2", part1(SAMPLE).unwrap());
|
assert_eq!("2", part1_parametrized(SAMPLE, 7.0, 27.0).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user