mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement day 22 part 2 (and 1 again)
This commit is contained in:
@@ -7,7 +7,7 @@ use criterion::criterion_main;
|
|||||||
use criterion::BenchmarkId;
|
use criterion::BenchmarkId;
|
||||||
use criterion::Criterion;
|
use criterion::Criterion;
|
||||||
|
|
||||||
const DAYS_IMPLEMENTED: usize = 21;
|
const DAYS_IMPLEMENTED: usize = 22;
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub fn part2(input: &mut dyn Read) -> String {
|
|||||||
let mut grid = read_grid(input, &mut buffer);
|
let mut grid = read_grid(input, &mut buffer);
|
||||||
let mut todo = Vec::new();
|
let mut todo = Vec::new();
|
||||||
|
|
||||||
let target = grid.iter().map(|line| line.len()).sum();
|
let target: usize = grid.iter().map(|line| line.len()).sum();
|
||||||
|
|
||||||
(1..)
|
(1..)
|
||||||
.find(|_| advance(&mut grid, &mut todo) == target)
|
.find(|_| advance(&mut grid, &mut todo) == target)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::ops::RangeInclusive;
|
|
||||||
|
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
@@ -13,78 +12,169 @@ use nom::IResult;
|
|||||||
|
|
||||||
use crate::common::read_input;
|
use crate::common::read_input;
|
||||||
|
|
||||||
type CRange = RangeInclusive<i32>;
|
type Point3 = [i32; 3];
|
||||||
|
|
||||||
fn parse_range(input: &[u8]) -> IResult<&[u8], CRange> {
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
use nom::character::complete::i32;
|
struct Cuboid {
|
||||||
|
lower: Point3,
|
||||||
map(separated_pair(i32, tag(".."), i32), |(first, last)| {
|
upper: Point3,
|
||||||
first..=last
|
|
||||||
})(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<(bool, [CRange; 3])>> {
|
impl Cuboid {
|
||||||
let parse_state = alt((map(tag("on x="), |_| true), map(tag("off x="), |_| false)));
|
pub fn new(lower: Point3, upper: Point3) -> Self {
|
||||||
let parse_line = map(
|
// The input uses an inclusive range for representation, but an exclusive one simplifies a
|
||||||
|
// lot of computations, so we convert here.
|
||||||
|
Self::new_internal(lower, upper.map(|c| c + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_internal(lower: Point3, upper: Point3) -> Self {
|
||||||
|
debug_assert!(lower.iter().zip(&upper).all(|(a, b)| a < b));
|
||||||
|
Self { lower, upper }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_small(&self) -> bool {
|
||||||
|
self.lower
|
||||||
|
.iter()
|
||||||
|
.chain(&self.upper.map(|c| c - 1)) // begrudgingly convert back
|
||||||
|
.all(|c| c.abs() <= 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn volume(&self) -> i64 {
|
||||||
|
self.lower
|
||||||
|
.iter()
|
||||||
|
.zip(&self.upper)
|
||||||
|
.map(|(&l, &h)| (h - l) as i64)
|
||||||
|
.product()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overlaps(&self, other: &Self) -> bool {
|
||||||
|
self.lower
|
||||||
|
.iter()
|
||||||
|
.zip(&self.upper)
|
||||||
|
.zip(other.lower.iter().zip(&other.upper))
|
||||||
|
.all(|((&al, &ah), (&bl, &bh))| al < bh && bl < ah)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retain_nonoverlapping(&self, other: &Self, new_cubes: &mut Vec<Self>) -> bool {
|
||||||
|
if !self.overlaps(other) {
|
||||||
|
// Cube can be kept as-is.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.lower[0] > self.lower[0] {
|
||||||
|
// We have a set of X-coordinates below the overlap, add a cube for that
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
self.lower,
|
||||||
|
[other.lower[0], self.upper[1], self.upper[2]],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.upper[0] < self.upper[0] {
|
||||||
|
// Similarly, we can remove an upper section.
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
[other.upper[0], self.lower[1], self.lower[2]],
|
||||||
|
self.upper,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can fix the X-coordinates of the overlap section
|
||||||
|
let overlap_xl = self.lower[0].max(other.lower[0]);
|
||||||
|
let overlap_xh = self.upper[0].min(other.upper[0]);
|
||||||
|
|
||||||
|
// Same strategy for the Y axis
|
||||||
|
if other.lower[1] > self.lower[1] {
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
[overlap_xl, self.lower[1], self.lower[2]],
|
||||||
|
[overlap_xh, other.lower[1], self.upper[2]],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if other.upper[1] < self.upper[1] {
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
[overlap_xl, other.upper[1], self.lower[2]],
|
||||||
|
[overlap_xh, self.upper[1], self.upper[2]],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
let overlap_yl = self.lower[1].max(other.lower[1]);
|
||||||
|
let overlap_yh = self.upper[1].min(other.upper[1]);
|
||||||
|
|
||||||
|
// Finally, handle the last axis
|
||||||
|
if other.lower[2] > self.lower[2] {
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
[overlap_xl, overlap_yl, self.lower[2]],
|
||||||
|
[overlap_xh, overlap_yh, other.lower[2]],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if other.upper[2] < self.upper[2] {
|
||||||
|
new_cubes.push(Self::new_internal(
|
||||||
|
[overlap_xl, overlap_yl, other.upper[2]],
|
||||||
|
[overlap_xh, overlap_yh, self.upper[2]],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_tuple(input: &[u8]) -> IResult<&[u8], (i32, i32)> {
|
||||||
|
use nom::character::complete::i32;
|
||||||
|
separated_pair(i32, tag(".."), i32)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_cuboid(input: &[u8]) -> IResult<&[u8], Cuboid> {
|
||||||
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
parse_state,
|
parse_tuple,
|
||||||
parse_range,
|
preceded(tag(",y="), parse_tuple),
|
||||||
preceded(tag(",y="), parse_range),
|
preceded(tag(",z="), parse_tuple),
|
||||||
preceded(tag(",z="), parse_range),
|
|
||||||
)),
|
)),
|
||||||
|(b, x, y, z)| (b, [x, y, z]),
|
|((xl, xh), (yl, yh), (zl, zh))| Cuboid::new([xl, yl, zl], [xh, yh, zh]),
|
||||||
);
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<(bool, Cuboid)>> {
|
||||||
|
let parse_state = alt((map(tag("on x="), |_| true), map(tag("off x="), |_| false)));
|
||||||
|
let parse_line = tuple((parse_state, parse_cuboid));
|
||||||
|
|
||||||
separated_list1(newline, parse_line)(input)
|
separated_list1(newline, parse_line)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &mut dyn Read) -> String {
|
pub fn part1(input: &mut dyn Read) -> String {
|
||||||
const MAX_ABS_VAL: i32 = 50;
|
let commands = read_input(input, parse_input);
|
||||||
const SIDE_LEN: usize = 2 * (MAX_ABS_VAL as usize) + 1;
|
let mut cubes = Vec::new();
|
||||||
|
let mut new_cubes = Vec::new();
|
||||||
|
|
||||||
let mut state = [[0u128; SIDE_LEN]; SIDE_LEN];
|
for (state, cube) in commands.into_iter().filter(|(_, c)| c.is_small()) {
|
||||||
|
cubes.retain(|existing: &Cuboid| existing.retain_nonoverlapping(&cube, &mut new_cubes));
|
||||||
|
|
||||||
let valid_range = -MAX_ABS_VAL..=MAX_ABS_VAL;
|
// Add new cubes to the end
|
||||||
|
cubes.append(&mut new_cubes);
|
||||||
|
|
||||||
let ranges = read_input(input, parse_input);
|
if state {
|
||||||
|
cubes.push(cube);
|
||||||
for (toggle, [xr, yr, zr]) in ranges {
|
|
||||||
for z in zr {
|
|
||||||
if !valid_range.contains(&z) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for y in yr.clone() {
|
|
||||||
if !valid_range.contains(&y) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let row = &mut state[(z + MAX_ABS_VAL) as usize][(y + MAX_ABS_VAL) as usize];
|
|
||||||
|
|
||||||
for x in xr.clone() {
|
|
||||||
if !valid_range.contains(&x) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let bit = 1 << (x + MAX_ABS_VAL);
|
|
||||||
|
|
||||||
if toggle {
|
|
||||||
*row |= bit;
|
|
||||||
} else {
|
|
||||||
*row &= !bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state
|
cubes.iter().map(Cuboid::volume).sum::<i64>().to_string()
|
||||||
.iter()
|
|
||||||
.flatten()
|
|
||||||
.map(|val| val.count_ones())
|
|
||||||
.sum::<u32>()
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &mut dyn Read) -> String {
|
pub fn part2(input: &mut dyn Read) -> String {
|
||||||
todo!()
|
let commands = read_input(input, parse_input);
|
||||||
|
let mut cubes = Vec::new();
|
||||||
|
let mut new_cubes = Vec::new();
|
||||||
|
|
||||||
|
for (state, cube) in commands {
|
||||||
|
cubes.retain(|existing: &Cuboid| existing.retain_nonoverlapping(&cube, &mut new_cubes));
|
||||||
|
|
||||||
|
// Add new cubes to the end
|
||||||
|
cubes.append(&mut new_cubes);
|
||||||
|
|
||||||
|
if state {
|
||||||
|
cubes.push(cube);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cubes.iter().map(Cuboid::volume).sum::<i64>().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -93,15 +183,39 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const SAMPLE: &[u8] = include_bytes!("samples/22.txt");
|
const SAMPLE1: &[u8] = include_bytes!("samples/22.1.txt");
|
||||||
|
const SAMPLE2: &[u8] = include_bytes!("samples/22.2.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_overlap() {
|
||||||
|
let cube_a = Cuboid {
|
||||||
|
lower: [1, 1, 1],
|
||||||
|
upper: [4, 4, 4],
|
||||||
|
};
|
||||||
|
|
||||||
|
let cube_b = Cuboid {
|
||||||
|
lower: [2, 2, 2],
|
||||||
|
upper: [3, 3, 3],
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new_cubes = Vec::new();
|
||||||
|
|
||||||
|
// B is fully inside A so it should overlap and the result should be empty
|
||||||
|
assert!(!cube_b.retain_nonoverlapping(&cube_a, &mut new_cubes));
|
||||||
|
assert_eq!(new_cubes, Vec::new());
|
||||||
|
|
||||||
|
// In the reverse case, we should have lots of new cubes
|
||||||
|
assert!(!cube_a.retain_nonoverlapping(&cube_b, &mut new_cubes));
|
||||||
|
assert_eq!(new_cubes.len(), 6);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sample_part1() {
|
fn sample_part1() {
|
||||||
test_implementation(part1, SAMPLE, 590784);
|
test_implementation(part1, SAMPLE1, 590784);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sample_part2() {
|
fn sample_part2() {
|
||||||
// test_implementation(part2, SAMPLE, 230)
|
test_implementation(part2, SAMPLE2, 2758514936282235u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ pub fn get_implementation(day: usize, part2: bool) -> Solution {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn test_implementation(solution: Solution, data: &[u8], answer: impl ToString) {
|
fn test_implementation(solution: Solution, data: &[u8], answer: impl ToString) {
|
||||||
let result = solution(&mut data.as_ref());
|
let result = solution(&mut &data[..]);
|
||||||
|
|
||||||
assert_eq!(answer.to_string(), result);
|
assert_eq!(answer.to_string(), result);
|
||||||
}
|
}
|
||||||
|
|||||||
60
2021/src/samples/22.2.txt
Normal file
60
2021/src/samples/22.2.txt
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
on x=-5..47,y=-31..22,z=-19..33
|
||||||
|
on x=-44..5,y=-27..21,z=-14..35
|
||||||
|
on x=-49..-1,y=-11..42,z=-10..38
|
||||||
|
on x=-20..34,y=-40..6,z=-44..1
|
||||||
|
off x=26..39,y=40..50,z=-2..11
|
||||||
|
on x=-41..5,y=-41..6,z=-36..8
|
||||||
|
off x=-43..-33,y=-45..-28,z=7..25
|
||||||
|
on x=-33..15,y=-32..19,z=-34..11
|
||||||
|
off x=35..47,y=-46..-34,z=-11..5
|
||||||
|
on x=-14..36,y=-6..44,z=-16..29
|
||||||
|
on x=-57795..-6158,y=29564..72030,z=20435..90618
|
||||||
|
on x=36731..105352,y=-21140..28532,z=16094..90401
|
||||||
|
on x=30999..107136,y=-53464..15513,z=8553..71215
|
||||||
|
on x=13528..83982,y=-99403..-27377,z=-24141..23996
|
||||||
|
on x=-72682..-12347,y=18159..111354,z=7391..80950
|
||||||
|
on x=-1060..80757,y=-65301..-20884,z=-103788..-16709
|
||||||
|
on x=-83015..-9461,y=-72160..-8347,z=-81239..-26856
|
||||||
|
on x=-52752..22273,y=-49450..9096,z=54442..119054
|
||||||
|
on x=-29982..40483,y=-108474..-28371,z=-24328..38471
|
||||||
|
on x=-4958..62750,y=40422..118853,z=-7672..65583
|
||||||
|
on x=55694..108686,y=-43367..46958,z=-26781..48729
|
||||||
|
on x=-98497..-18186,y=-63569..3412,z=1232..88485
|
||||||
|
on x=-726..56291,y=-62629..13224,z=18033..85226
|
||||||
|
on x=-110886..-34664,y=-81338..-8658,z=8914..63723
|
||||||
|
on x=-55829..24974,y=-16897..54165,z=-121762..-28058
|
||||||
|
on x=-65152..-11147,y=22489..91432,z=-58782..1780
|
||||||
|
on x=-120100..-32970,y=-46592..27473,z=-11695..61039
|
||||||
|
on x=-18631..37533,y=-124565..-50804,z=-35667..28308
|
||||||
|
on x=-57817..18248,y=49321..117703,z=5745..55881
|
||||||
|
on x=14781..98692,y=-1341..70827,z=15753..70151
|
||||||
|
on x=-34419..55919,y=-19626..40991,z=39015..114138
|
||||||
|
on x=-60785..11593,y=-56135..2999,z=-95368..-26915
|
||||||
|
on x=-32178..58085,y=17647..101866,z=-91405..-8878
|
||||||
|
on x=-53655..12091,y=50097..105568,z=-75335..-4862
|
||||||
|
on x=-111166..-40997,y=-71714..2688,z=5609..50954
|
||||||
|
on x=-16602..70118,y=-98693..-44401,z=5197..76897
|
||||||
|
on x=16383..101554,y=4615..83635,z=-44907..18747
|
||||||
|
off x=-95822..-15171,y=-19987..48940,z=10804..104439
|
||||||
|
on x=-89813..-14614,y=16069..88491,z=-3297..45228
|
||||||
|
on x=41075..99376,y=-20427..49978,z=-52012..13762
|
||||||
|
on x=-21330..50085,y=-17944..62733,z=-112280..-30197
|
||||||
|
on x=-16478..35915,y=36008..118594,z=-7885..47086
|
||||||
|
off x=-98156..-27851,y=-49952..43171,z=-99005..-8456
|
||||||
|
off x=2032..69770,y=-71013..4824,z=7471..94418
|
||||||
|
on x=43670..120875,y=-42068..12382,z=-24787..38892
|
||||||
|
off x=37514..111226,y=-45862..25743,z=-16714..54663
|
||||||
|
off x=25699..97951,y=-30668..59918,z=-15349..69697
|
||||||
|
off x=-44271..17935,y=-9516..60759,z=49131..112598
|
||||||
|
on x=-61695..-5813,y=40978..94975,z=8655..80240
|
||||||
|
off x=-101086..-9439,y=-7088..67543,z=33935..83858
|
||||||
|
off x=18020..114017,y=-48931..32606,z=21474..89843
|
||||||
|
off x=-77139..10506,y=-89994..-18797,z=-80..59318
|
||||||
|
off x=8476..79288,y=-75520..11602,z=-96624..-24783
|
||||||
|
on x=-47488..-1262,y=24338..100707,z=16292..72967
|
||||||
|
off x=-84341..13987,y=2429..92914,z=-90671..-1318
|
||||||
|
off x=-37810..49457,y=-71013..-7894,z=-105357..-13188
|
||||||
|
off x=-27365..46395,y=31009..98017,z=15428..76570
|
||||||
|
off x=-70369..-16548,y=22648..78696,z=-1892..86821
|
||||||
|
on x=-53470..21291,y=-120233..-33476,z=-44150..38147
|
||||||
|
off x=-93533..-4276,y=-16170..68771,z=-104985..-24507
|
||||||
Reference in New Issue
Block a user