much better
This commit is contained in:
parent
b9bc497271
commit
bdab9180a2
2 changed files with 80 additions and 153 deletions
|
|
@ -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::<Vec<&str>>().join("").chars().map(Pipes::from).collect();
|
||||
let mut grid: Vec<Vec<char>> = 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<usize> = 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::<Vec<&str>>().join("").chars().map(Pipes::from).collect();
|
||||
let mut grid: Vec<Vec<char>> = 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<usize> = 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::<Vec<_>>();
|
||||
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::<i32>();
|
||||
println!("{:?}", line);
|
||||
}
|
||||
|
||||
Answer::from(enclosed)
|
||||
Answer::from(total)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Pipes {
|
||||
Ground,
|
||||
Vertical,
|
||||
Horizontal,
|
||||
WtoN,
|
||||
NtoE,
|
||||
EtoS,
|
||||
StoW,
|
||||
Animal
|
||||
}
|
||||
|
||||
impl From<char> 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<Pipes>, 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<Pipes>, 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<Vec<char>>, 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ pub mod day22;
|
|||
pub mod day23;
|
||||
pub mod day24;
|
||||
pub mod day25;
|
||||
pub mod day10;
|
||||
|
||||
#[test]
|
||||
fn examples() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue