use std::collections::HashMap; use std::io::{self, BufRead}; fn distance(a: (i32, i32), b: (i32, i32)) -> i32 { (a.0 - b.0).abs() + (a.1 - b.1).abs() } #[derive(Clone, Copy, Debug)] enum State { Empty, Owner(usize, i32), Equal(i32), } #[derive(Clone, Copy, Debug)] enum Area { Infinite, Finite(usize), } fn main() { let coordinates = io::stdin() .lock() .lines() .filter_map(Result::ok) .map(|line| { let coords = line .split(", ") .map(|coord| coord.parse::().unwrap()) .collect::>(); (coords[0], coords[1]) }) .collect::>(); let width = coordinates .iter() .map(|(x, _)| *x as usize) .max() .expect("failed to find max x") + 1; let height = coordinates .iter() .map(|(_, y)| *y as usize) .max() .expect("failed to find max y") + 1; let mut grid_view = vec![State::Empty; width * height].into_boxed_slice(); for x in 0..width { for y in 0..height { for (i, c) in coordinates.iter().enumerate() { let distance = distance(*c, (x as i32, y as i32)); let state = &mut grid_view[x + (y * width)]; *state = match state { State::Empty => State::Owner(i, distance), State::Owner(_, d) if *d > distance => State::Owner(i, distance), State::Owner(o, d) if *d == distance && *o != i => State::Equal(distance), State::Equal(d) if *d > distance => State::Owner(i, distance), _ => *state, }; } } } let mut areas = HashMap::new(); for x in 0..width { for y in 0..height { if let State::Owner(o, _) = grid_view[x + (y * width)] { let a = areas.entry(o).or_insert(Area::Finite(0)); if x == 0 || x == width - 1 || y == 0 || y == height - 1 { *a = Area::Infinite; } else { match a { Area::Infinite => (), Area::Finite(area) => *area += 1, } } } } } let (_, area) = areas .iter() .filter_map(|(i, area)| { if let Area::Finite(area) = area { Some((i, area)) } else { None } }) .max_by_key(|(_, area)| *area) .expect("failed to find max area"); println!("part.one={}", area); let mut grid_view = vec!['.'; width * height].into_boxed_slice(); for y in 0..height { for x in 0..width { let total = coordinates .iter() .map(|c| distance(*c, (x as i32, y as i32))) .sum::(); if total < 10_000 { grid_view[x + (y * width)] = '#'; } } } let area = grid_view.iter().filter(|r| **r == '#').count(); println!("part.two={}", area); }