From bdab9180a2518a42341eeddc83573bdc32d62945 Mon Sep 17 00:00:00 2001 From: spectre Date: Sun, 10 Dec 2023 21:03:30 +0100 Subject: [PATCH] much better --- aoc2023/src/day10.rs | 232 +++++++++++++++---------------------------- aoc2023/src/lib.rs | 1 + 2 files changed, 80 insertions(+), 153 deletions(-) diff --git a/aoc2023/src/day10.rs b/aoc2023/src/day10.rs index 517959e..2453d5b 100644 --- a/aoc2023/src/day10.rs +++ b/aoc2023/src/day10.rs @@ -1,193 +1,119 @@ use std::collections::HashSet; -use std::process::abort; +use std::ffi::c_ushort; use shared::{Solution, Answer}; pub struct Day10; impl Solution for Day10 { fn part_1(&self, input: &str) -> Answer { - let width: i64 = input.lines().next().unwrap().len() as i64; - let grid: Vec<_> = input.lines().collect::>().join("").chars().map(Pipes::from).collect(); + let mut grid: Vec> = input.lines().map(|x| x.chars().collect()).collect(); + let full_animal = grid.iter().flatten().position(|&x| x == 'S').unwrap(); + let animal = (full_animal / grid.len(), full_animal % grid.len()); - let animal = grid.iter().position(|x| x == &Pipes::Animal).unwrap(); + replace_animal(&mut grid, &animal); - let mut seen: HashSet = HashSet::new(); + let mut pos = animal; + let mut last: Option<(usize, usize)> = None; - let mut len = 2; - let mut current ; - - if grid[animal + 1] == Pipes::Horizontal || grid[animal + 1] == Pipes::EtoS || grid[animal + 1] == Pipes::NtoE { - current = animal + 1; - } else if grid[animal - 1] == Pipes::Horizontal || grid[animal - 1] == Pipes::WtoN || grid[animal - 1] == Pipes::StoW { - current = animal - 1; - } else { current = animal + width as usize } - - seen.insert(animal); - seen.insert(current); + let mut len_of_loop = 0; loop { - let next = traverse(&grid, current as i64, width); - if next.is_none() { panic!() } - let (next1, next2) = next.unwrap(); - if seen.contains(&next1) && seen.contains(&next2) { - break; - } else if !seen.contains(&next1) { - current = next1; - seen.insert(next1); - len += 1; - } else if !seen.contains(&next2) { - current = next2; - seen.insert(next2); - len += 1; - } else { panic!() } + len_of_loop += 1; + let tmp = pos; + pos = traverse(&grid[pos.0][pos.1], &pos, &last); + last = Some(tmp); + + if pos == animal {break} } - Answer::from(len) + Answer::from(len_of_loop / 2) } fn part_2(&self, input: &str) -> Answer { - let width: usize = input.lines().next().unwrap().len(); - let mut grid: Vec<_> = input.lines().collect::>().join("").chars().map(Pipes::from).collect(); + let mut grid: Vec> = input.lines().map(|x| x.chars().collect()).collect(); + let full_animal = grid.iter().flatten().position(|&x| x == 'S').unwrap(); + let animal = (full_animal / grid.len(), full_animal % grid.len()); - let animal = grid.iter().position(|x| x == &Pipes::Animal).unwrap(); - replace_animal(&mut grid, animal, width); - println!("{:?}", grid[animal]); + replace_animal(&mut grid, &animal); - let mut seen: HashSet = HashSet::new(); + let mut pos = animal; + let mut last: Option<(usize, usize)> = None; - let mut len = 2; - let mut current ; - - if grid[animal + 1] == Pipes::Horizontal || grid[animal + 1] == Pipes::EtoS || grid[animal + 1] == Pipes::NtoE { - current = animal + 1; - } else if grid[animal - 1] == Pipes::Horizontal || grid[animal - 1] == Pipes::WtoN || grid[animal - 1] == Pipes::StoW { - current = animal - 1; - } else { current = animal + width as usize } - - seen.insert(animal); - seen.insert(current); + let mut in_loop: HashSet<(usize, usize)> = HashSet::new(); loop { - let next = traverse(&grid, current as i64, width as i64); - if next.is_none() { panic!() } - let (next1, next2) = next.unwrap(); - if seen.contains(&next1) && seen.contains(&next2) { - break; - } else if !seen.contains(&next1) { - current = next1; - seen.insert(next1); - len += 1; - } else if !seen.contains(&next2) { - current = next2; - seen.insert(next2); - } else { panic!() } + in_loop.insert(pos); + let tmp = pos; + pos = traverse(&grid[pos.0][pos.1], &pos, &last); + last = Some(tmp); + + if pos == animal {break} } - let mut parity = grid.chunks(width).map(|_| [0].repeat(width)).collect::>(); + let mut total = 0; - for (i, line) in grid.chunks(width).enumerate() { + for (i, line) in grid.iter().enumerate() { + let mut parity = 0; for (j, letter) in line.iter().enumerate() { - if seen.contains(&(width * i + j)) { - for k in j..width { - parity[i][k] += match letter { - Pipes::Vertical => 2, // using 2 and 1 instead of 1 and .5 for half parity, because integers - Pipes::StoW => 1, - Pipes::NtoE => 1, - Pipes::EtoS => -1, - Pipes::WtoN => -1, - _ => 0 - } - } + if in_loop.contains(&(i, j)) { + parity += modify_parity(letter) + } + else if parity % 4 != 0 { + total += 1 } } } - for i in seen { - parity[i / width][i % width] = 0; - } - let mut enclosed = 0; - - for line in parity { - enclosed += line.iter().map(|x| (x % 4 / 2)).map(i32::abs).sum::(); - println!("{:?}", line); - } - - Answer::from(enclosed) + Answer::from(total) } } -#[derive(Debug, PartialEq, Eq)] -enum Pipes { - Ground, - Vertical, - Horizontal, - WtoN, - NtoE, - EtoS, - StoW, - Animal -} - -impl From for Pipes { - fn from(value: char) -> Self { - match value { - '|' => Pipes::Vertical, - '-' => Pipes::Horizontal, - 'J' => Pipes::WtoN, - 'L' => Pipes::NtoE, - 'F' => Pipes::EtoS, - '7' => Pipes::StoW, - '.' => Pipes::Ground, - 'S' => Pipes::Animal, - _ => unreachable!() - } - } -} - -fn traverse(grid: &Vec, current: i64, width: i64) -> Option<(usize, usize)> { - let next1 = current + match grid[current as usize] { - Pipes::Vertical => -width, - Pipes::Horizontal => -1, - Pipes::WtoN => -1, - Pipes::NtoE => -width, - Pipes::EtoS => 1, - Pipes::StoW => width, - Pipes::Animal => 0, - Pipes::Ground => unreachable!() - }; - let next2 = current + match grid[current as usize] { - Pipes::Vertical => width, - Pipes::Horizontal => 1, - Pipes::WtoN => -width, - Pipes::NtoE => 1, - Pipes::EtoS => width, - Pipes::StoW => -1, - Pipes::Animal => 0, - Pipes::Ground => unreachable!() +fn traverse(pipe: &char, pos: &(usize, usize), last: &Option<(usize, usize)>) -> (usize, usize) { + let (offset1, offset2) = match *pipe { + '|' => ((-1, 0), (1, 0)), + '-' => ((0, -1), (0, 1)), + 'J' => ((-1, 0), (0, -1)), + 'L' => ((-1, 0), (0, 1)), + 'F' => ((1, 0), (0, 1)), + '7' => ((1, 0), (0, -1)), + l => panic!("Invalid letter {l}") }; - // println!("{next1}, {next2}: Current={current}, Width={width}"); + let new1 = ((offset1.0 + pos.0 as i32) as usize, (offset1.1 + pos.1 as i32) as usize); + let new2 = ((offset2.0 + pos.0 as i32) as usize, (offset2.1 + pos.1 as i32) as usize); - // if next1 - current == -1 || next1 - current == width || next1 == -1 || next1 == (grid.len() as i64) { return None }; - // if next2 - current == -1 || next2 - current == width || next2 == -1 || next2 == (grid.len() as i64) { return None }; - - Some((next1 as usize, next2 as usize)) -} - -fn replace_animal(grid: &mut Vec, animal: usize, width: usize) { - let east = grid[animal + 1] == Pipes::Horizontal || grid[animal + 1] == Pipes::WtoN || grid[animal + 1] == Pipes::StoW; - let north = grid[animal - width] == Pipes::Vertical || grid[animal - width] == Pipes::WtoN || grid[animal - width] == Pipes::NtoE; - let west = grid[animal - 1] == Pipes::Horizontal || grid[animal - 1] == Pipes::WtoN || grid[animal - 1] == Pipes::StoW; - let south = grid[animal + width] == Pipes::Vertical || grid[animal + width] == Pipes::StoW || grid[animal + width] == Pipes::EtoS; - - match (east, north, south, west) { - (false, false, true, true) => grid[animal] = Pipes::StoW, - (false, true, true, false) => grid[animal] = Pipes::Vertical, - (true, true, false, false) => grid[animal] = Pipes::NtoE, - (false, true, false, true) => grid[animal] = Pipes::WtoN, - (true, false, true, false) => grid[animal] = Pipes::EtoS, - (true, false, false, true) => grid[animal] = Pipes::Horizontal, + match last { + None => new1, + Some(p) if p == &new1 => new2, + Some(p) if p == &new2 => new1, _ => unreachable!() } } +fn replace_animal(grid: &mut Vec>, pos: &(usize, usize)) { + let left = match grid.get(pos.0) { Some(x) => x.get((pos.1 as i32 - 1) as usize), _ => None}; + let right = match grid.get(pos.0) { Some(x) => x.get(pos.1 + 1), _ => None}; + let top = match grid.get((pos.0 as i32 - 1) as usize) { Some(x) => x.get(pos.1), _ => None}; + let bottom = match grid.get(pos.0 + 1) { Some(x) => x.get(pos.1), _ => None}; + + grid[pos.0][pos.1] = match (left, right, top, bottom) { + (Some(x), Some(y), _, _) if ['-', 'L', 'F'].contains(x) && ['-', 'J', '7'].contains(y) => '-', + (Some(x), _, Some(y), _) if ['-', 'L', 'F'].contains(x) && ['|', '7', 'F'].contains(y) => 'J', + (Some(x), _, _, Some(y)) if ['-', 'L', 'F'].contains(x) && ['|', 'J', 'L'].contains(y) => '7', + (_, Some(x), Some(y), _) if ['-', 'J', '7'].contains(x) && ['|', '7', 'F'].contains(y) => 'L', + (_, Some(x), _, Some(y)) if ['-', 'J', '7'].contains(x) && ['|', 'J', 'L'].contains(y) => 'F', + (_, _, Some(x), Some(y)) if ['|', '7', 'F'].contains(x) && ['|', 'J', 'L'].contains(y) => '|', + _ => unreachable!() + } +} + +fn modify_parity(l: &char) -> i32 { + match l { + '|' => 2, + 'L' => 1, + 'J' => -1, + 'F' => -1, + '7' => 1, + _ => 0 + } +} diff --git a/aoc2023/src/lib.rs b/aoc2023/src/lib.rs index ba1cbad..7347a91 100644 --- a/aoc2023/src/lib.rs +++ b/aoc2023/src/lib.rs @@ -53,6 +53,7 @@ pub mod day22; pub mod day23; pub mod day24; pub mod day25; +pub mod day10; #[test] fn examples() {