Optimize day 4 slightly
parent
ff572f4a36
commit
81eebf8df8
|
|
@ -1,54 +1,119 @@
|
||||||
// use crate::utils;
|
// use crate::utils;
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub fn answer(text : String) -> ( u32, u32 ) {
|
pub fn answer(text : String) -> ( u32, u32 ) {
|
||||||
let mut paper_rolls : HashSet<( i32, i32 )> = text
|
let mut rolls = PaperRolls::from(&text);
|
||||||
|
let part_1 = rolls.remove();
|
||||||
|
|
||||||
|
while rolls.remove() > 0 {};
|
||||||
|
|
||||||
|
( part_1, rolls.rolls_moved )
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PaperRolls {
|
||||||
|
paper : HashMap<( u8, u8 ), u8>,
|
||||||
|
prev_move : Option<Vec<(u8, u8)>>,
|
||||||
|
rolls_moved : u32,
|
||||||
|
}
|
||||||
|
impl PaperRolls {
|
||||||
|
fn remove(&mut self) -> u32 {
|
||||||
|
let to_remove: Vec<(u8, u8)>;
|
||||||
|
|
||||||
|
if let Some(prev_move) = &self.prev_move {
|
||||||
|
// We have already moved before. If we couldn't remove a roll last
|
||||||
|
// time, we won't be able to move it now unless it was a neighbour
|
||||||
|
// of a roll that was moved last turn.
|
||||||
|
let mut items = HashSet::new();
|
||||||
|
|
||||||
|
for (x, y) in prev_move {
|
||||||
|
let x1 = if x == &u8::MIN { u8::MIN } else { x - 1 };
|
||||||
|
let x2 = if x == &u8::MAX { u8::MAX } else { x + 1 };
|
||||||
|
let y1 = if y == &u8::MIN { u8::MIN } else { y - 1 };
|
||||||
|
let y2: u8 = if y == &u8::MAX { u8::MAX } else { y + 1 };
|
||||||
|
|
||||||
|
for nx in x1..=x2 {
|
||||||
|
for ny in y1..=y2 {
|
||||||
|
self.paper
|
||||||
|
.entry((nx, ny))
|
||||||
|
.and_modify(|e| {
|
||||||
|
let x: u8 = *e;
|
||||||
|
if x > 4 {
|
||||||
|
*e -= 1;
|
||||||
|
} else {
|
||||||
|
items.insert((nx, ny));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to_remove = items.into_iter().collect();
|
||||||
|
} else {
|
||||||
|
// This is (likely) the first time we remove rolls!
|
||||||
|
// Hence, do the less optimized option of finding all rolls
|
||||||
|
// with few neighbours directly in the HashMap.
|
||||||
|
to_remove = self.paper
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| **v < 4)
|
||||||
|
.map(|(k, _)| *k)
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
for r in &to_remove {
|
||||||
|
self.paper.remove(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
let size: u32 = to_remove.len() as u32;
|
||||||
|
|
||||||
|
self.prev_move = Some(to_remove);
|
||||||
|
self.rolls_moved += size;
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from(s : &str) -> PaperRolls {
|
||||||
|
let rolls : HashSet<( u8, u8 )> = s
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(
|
.flat_map(move |(row, s)|
|
||||||
|(row, s)| s.chars().enumerate().filter_map(
|
s.chars().enumerate().filter_map(move |(col, c)|
|
||||||
move |(col, c)| if c == '@' { Some(( col as i32, row as i32 )) } else { None }
|
if c == '@' { Some(( col as u8, row as u8 )) } else { None }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let part_1 = paper_rolls
|
|
||||||
|
PaperRolls {
|
||||||
|
paper: rolls
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(x, y)| count_neighbours(&paper_rolls, *x, *y) < 5)
|
.map(|(x, y)|
|
||||||
.count();
|
((*x, *y), count_neighbours(&rolls, x, y))
|
||||||
|
)
|
||||||
let mut removes : HashSet<( i32, i32 )>;
|
.collect(),
|
||||||
let mut part_2 : u32 = 0;
|
prev_move : None,
|
||||||
|
rolls_moved: 0,
|
||||||
loop {
|
|
||||||
(removes, paper_rolls) = paper_rolls
|
|
||||||
.iter()
|
|
||||||
.partition(|(x, y)| count_neighbours(&paper_rolls, *x, *y) < 5);
|
|
||||||
|
|
||||||
// println!("removes: ({} total, {} remaining) {:?}", removes.len(), paper_rolls.len(), removes);
|
|
||||||
|
|
||||||
if removes.len() == 0 {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
part_2 += removes.len() as u32;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
( part_1 as u32, part_2 )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_neighbours(paper_rolls : &HashSet<( i32, i32 )>, x : i32, y : i32) -> u8 {
|
fn count_neighbours(rolls : &HashSet<(u8, u8)>, x : &u8, y : &u8) -> u8 {
|
||||||
let mut total: u8 = 0;
|
let x1 : u8 = if x == &u8::MIN { u8::MIN } else { x - 1 };
|
||||||
|
let x2 : u8 = if x == &u8::MAX { u8::MAX } else { x + 1 };
|
||||||
|
let y1 : u8 = if y == &u8::MIN { u8::MIN } else { y - 1 };
|
||||||
|
let y2 : u8 = if y == &u8::MAX { u8::MAX } else { y + 1 };
|
||||||
|
|
||||||
for nx in (x-1)..=(x+1) {
|
let mut total = 0;
|
||||||
for ny in (y-1)..=(y+1) {
|
|
||||||
if paper_rolls.contains(&(nx, ny)) {
|
for nx in x1..=x2 {
|
||||||
|
for ny in y1..=y2 {
|
||||||
|
if x == &nx && y == &ny {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if rolls.contains(&(nx, ny)) {
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!("({}, {}) has {} neighbours - including itself.", x, y, total);
|
|
||||||
|
|
||||||
total
|
total
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ pub fn str_to_i16(s : &str) -> Option<i16> {
|
||||||
// s.trim().to_string().parse::<u32>().ok()
|
// s.trim().to_string().parse::<u32>().ok()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn str_to_u64(s : &str) -> Option<u64> {
|
// pub fn str_to_u64(s : &str) -> Option<u64> {
|
||||||
s.trim().to_string().parse::<u64>().ok()
|
// s.trim().to_string().parse::<u64>().ok()
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn str_to_u128(s : &str) -> Option<u128> {
|
pub fn str_to_u128(s : &str) -> Option<u128> {
|
||||||
s.trim().to_string().parse::<u128>().ok()
|
s.trim().to_string().parse::<u128>().ok()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue