Improve solutions
This commit is contained in:
@@ -1,57 +1,60 @@
|
||||
use std::cmp::min;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
use std::u64;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Machine {
|
||||
#[allow(dead_code)]
|
||||
lights: Vec<u64>,
|
||||
buttons: Vec<Vec<u64>>,
|
||||
buttons: Vec<Vec<usize>>,
|
||||
joltages: Vec<u64>
|
||||
}
|
||||
|
||||
impl FromStr for Machine {
|
||||
type Err = io::Error;
|
||||
type Err = ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let groups: Vec<_> = s.split(' ').collect();
|
||||
|
||||
let lights_part = groups[0];
|
||||
let lights = lights_part[1..lights_part.len()-1]
|
||||
.chars()
|
||||
.rev()
|
||||
.map(|c| if c == '#' { 1 } else { 0 })
|
||||
.collect();
|
||||
|
||||
let buttons: Vec<_> = (1..groups.len()-1)
|
||||
.map(|i| parse_button_group(groups[i]))
|
||||
.collect();
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let joltages_part = groups[groups.len()-1];
|
||||
let joltages: Vec<_> = joltages_part[1..joltages_part.len()-1]
|
||||
.split(',')
|
||||
.map(|j_s| j_s.parse::<u64>().unwrap())
|
||||
.collect();
|
||||
.map(|j_s| j_s.parse::<u64>())
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(Machine { lights: lights, buttons: buttons , joltages: joltages })
|
||||
Ok(Machine { lights, buttons , joltages })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_button_group(s: &str) -> Vec<u64> {
|
||||
fn parse_button_group(s: &str) -> Result<Vec<usize>, ParseIntError> {
|
||||
s[1..s.len()-1].split(',')
|
||||
.map(|x_s| x_s.parse::<u64>().unwrap())
|
||||
.map(str::parse::<usize>)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parity_solve(machine: &Machine, target: &Vec<u64>) -> Vec<u64> {
|
||||
|
||||
fn parity_solve(machine: &Machine, target: &[u64]) -> Vec<u64> {
|
||||
let mut solutions: Vec<u64> = Vec::new();
|
||||
for selection in 0..(1 << machine.buttons.len()) {
|
||||
let mut parity = target.iter().rev()
|
||||
.fold(0, |state, x| (state << 1) + (x & 1));
|
||||
.fold(0, |state, x| (state << 1) | (x & 1));
|
||||
for (i, button) in machine.buttons.iter().enumerate() {
|
||||
if selection & (1 << i) != 0 {
|
||||
for j in button {
|
||||
parity ^= 1 << j;
|
||||
}
|
||||
parity = button.iter().fold(parity, |parity, j| {
|
||||
parity ^ (1 << j)
|
||||
});
|
||||
}
|
||||
}
|
||||
if parity == 0 {
|
||||
@@ -62,25 +65,28 @@ fn parity_solve(machine: &Machine, target: &Vec<u64>) -> Vec<u64> {
|
||||
}
|
||||
|
||||
fn minimum_solve(machine: &Machine) -> u64 {
|
||||
fn apply_button(machine: &Machine, button_idx: usize, mut current: Vec<u64>) -> Option<Vec<u64>> {
|
||||
fn apply_button<'a>(machine: &Machine, button_idx: usize, current: &'a mut Vec<u64>) -> Option<&'a mut Vec<u64>> {
|
||||
for i in &machine.buttons[button_idx] {
|
||||
if current[*i as usize] == 0 {
|
||||
if current[*i] == 0 {
|
||||
return None;
|
||||
}
|
||||
current[*i as usize] -= 1;
|
||||
current[*i] -= 1;
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
|
||||
fn recurse(machine: &Machine, target: &Vec<u64>, max_cnt: i64) -> Option<u64> {
|
||||
fn recurse(machine: &Machine, target: &[u64], max_cnt: i64) -> Option<u64> {
|
||||
if target.iter().sum::<u64>() == 0 { return Some(0) };
|
||||
if max_cnt <= 0 { return None };
|
||||
|
||||
let parity_solutions = parity_solve(machine, target);
|
||||
let mut min_solution = None;
|
||||
|
||||
let mut min_presses = None;
|
||||
let mut current_storage = target.to_vec();
|
||||
for parity_sln in parity_solutions {
|
||||
current_storage.copy_from_slice(target);
|
||||
let current = (0..machine.buttons.len())
|
||||
.fold(Some(target.clone()), |state, i| {
|
||||
.fold(Some(&mut current_storage), |state, i| {
|
||||
if parity_sln & (1 << i) != 0 {
|
||||
apply_button(machine, i, state?)
|
||||
} else {
|
||||
@@ -91,40 +97,34 @@ fn minimum_solve(machine: &Machine) -> u64 {
|
||||
let parity_ones = parity_sln.count_ones() as i64;
|
||||
|
||||
let new_max_cnt =
|
||||
(match min_solution {
|
||||
(match min_presses {
|
||||
None => max_cnt,
|
||||
Some(ms) => min(ms as i64, max_cnt)
|
||||
} - parity_ones) / 2;
|
||||
let new_target = current.iter().map(|&x| x / 2).collect();
|
||||
let sln = recurse(machine, &new_target, new_max_cnt);
|
||||
let Some(sln) = sln else { continue };
|
||||
min_solution =
|
||||
match min_solution {
|
||||
None => Some(parity_ones as u64 + 2u64 * sln),
|
||||
Some(ms) => Some(min(ms, parity_ones as u64 + 2u64 * sln))
|
||||
};
|
||||
let new_target: Vec<_> = current.iter().map(|&x| x / 2).collect();
|
||||
let Some(sln) = recurse(machine, &new_target, new_max_cnt) else { continue };
|
||||
let presses = parity_ones as u64 + 2u64 * sln;
|
||||
min_presses = Some(match min_presses {
|
||||
None => presses,
|
||||
Some(ms) => min(ms, presses)
|
||||
});
|
||||
}
|
||||
min_solution
|
||||
min_presses
|
||||
}
|
||||
|
||||
let result = recurse(machine, &machine.joltages, i64::MAX).unwrap_or(0);
|
||||
println!("Result: {}", result);
|
||||
result
|
||||
recurse(machine, &machine.joltages, i64::MAX).unwrap_or(0)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("10-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let machines: Vec<_> = reader.lines()
|
||||
.map(|l| l?.parse::<Machine>())
|
||||
.collect::<Result<_,_>>()?;
|
||||
println!("Parsed {} machines: \n {:?}", machines.len(), machines);
|
||||
|
||||
let presses: u64 = machines.iter()
|
||||
.map(|m| minimum_solve(&m))
|
||||
.sum();
|
||||
.map(|l| Ok(l?.parse::<Machine>()?))
|
||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||
println!("Parsed {} machines", machines.len());
|
||||
|
||||
let presses: u64 = machines.iter().map(minimum_solve).sum();
|
||||
println!("Result: {}", presses);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use std::convert::Infallible;
|
||||
use std::error::Error;
|
||||
use std::num::ParseIntError;
|
||||
use std::string::ParseError;
|
||||
use std::{fs::File, io::{self, BufRead, BufReader}, str::FromStr};
|
||||
|
||||
struct Piece {
|
||||
@@ -5,27 +9,28 @@ struct Piece {
|
||||
}
|
||||
|
||||
impl FromStr for Piece {
|
||||
type Err = ();
|
||||
type Err = Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let cells: Vec<_> =
|
||||
let cells =
|
||||
s.split('\n').map(|row| {
|
||||
row.chars().fold(Vec::new(), |mut state, c| {
|
||||
row.chars().filter_map(|c| {
|
||||
match c {
|
||||
'#' => state.push(true),
|
||||
'.' => state.push(false),
|
||||
_ => ()
|
||||
};
|
||||
state
|
||||
'#' => Some(true),
|
||||
'.' => Some(false),
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
Ok(Piece { cells: cells })
|
||||
Ok(Piece { cells })
|
||||
}
|
||||
}
|
||||
|
||||
impl Piece {
|
||||
fn bounds_area(&self) -> u64 {
|
||||
#[allow(dead_code)]
|
||||
fn bounding_area(&self) -> u64 {
|
||||
let height = self.cells.len();
|
||||
if height > 0 {
|
||||
(self.cells[0].len() * height) as u64
|
||||
@@ -37,8 +42,8 @@ impl Piece {
|
||||
fn true_area(&self) -> u64 {
|
||||
self.cells.iter()
|
||||
.flatten()
|
||||
.map(|&b| if b { 1 } else { 0 })
|
||||
.sum()
|
||||
.filter(|&&b| b)
|
||||
.count() as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,21 +54,17 @@ struct Region {
|
||||
}
|
||||
|
||||
impl FromStr for Region {
|
||||
type Err = ();
|
||||
type Err = ParseIntError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (area_str, requirements_str) = s.split_once(':').unwrap();
|
||||
let (width_str, height_str) = area_str.split_once('x').unwrap();
|
||||
let width = width_str.parse::<u64>().unwrap();
|
||||
let height = height_str.parse::<u64>().unwrap();
|
||||
let requirements: Vec<_> = requirements_str.split(' ')
|
||||
.fold(Vec::new(), |mut state, count| {
|
||||
if let Ok(count) = count.parse::<u64>() {
|
||||
state.push(count);
|
||||
}
|
||||
state
|
||||
});
|
||||
Ok(Region { width: width, height: height, requirements: requirements })
|
||||
let width = width_str.parse::<u64>()?;
|
||||
let height = height_str.parse::<u64>()?;
|
||||
let requirements = requirements_str.split(' ')
|
||||
.filter_map(|s| s.parse::<u64>().ok())
|
||||
.collect();
|
||||
Ok(Region { width, height, requirements })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ fn is_solveable(pieces: &[Piece], region: &Region) -> bool {
|
||||
// Lower area bound = perfectly packed
|
||||
let region_area = region.width * region.height;
|
||||
let used_area: u64 = pieces.iter()
|
||||
.zip(region.requirements.clone())
|
||||
.zip(region.requirements.iter())
|
||||
.map(|(piece, cnt)| piece.true_area() * cnt)
|
||||
.sum();
|
||||
if used_area > region_area { return false };
|
||||
@@ -85,7 +86,7 @@ fn is_solveable(pieces: &[Piece], region: &Region) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("12-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
@@ -94,25 +95,19 @@ fn main() -> Result<(), io::Error> {
|
||||
|
||||
let pieces: Vec<_> = lines_pieces.chunks(5)
|
||||
.map(|lines| {
|
||||
lines[1..lines.len()-1].join("\n").parse::<Piece>().unwrap()
|
||||
Ok(lines[1..lines.len()-1].join("\n").parse::<Piece>()?)
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||
|
||||
let regions: Vec<_> = lines_regions.iter()
|
||||
.map(|line| {
|
||||
line.parse::<Region>().unwrap()
|
||||
Ok(line.parse::<Region>()?)
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||
|
||||
let result = regions.iter()
|
||||
.map(|region| {
|
||||
if is_solveable(&pieces, region) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.sum::<u64>();
|
||||
let result: u64 = regions.iter()
|
||||
.filter(|region| is_solveable(&pieces, region))
|
||||
.count() as u64;
|
||||
println!("Result: {}", result);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{
|
||||
cmp::max,
|
||||
fs::File,
|
||||
io::{self, BufRead, BufReader},
|
||||
};
|
||||
@@ -8,48 +9,37 @@ fn parse_range(s: &str) -> (i64, i64) {
|
||||
(low_s.parse().unwrap(), high_s.parse().unwrap())
|
||||
}
|
||||
|
||||
fn invalid_in_range(low: i64, high: i64) -> i64 {
|
||||
let mut total: i64 = 0;
|
||||
for i in low..=high {
|
||||
let len = i.ilog10() + 1;
|
||||
for j in (2..=len).filter(|x| len % x == 0) {
|
||||
let split = 10i64.pow(len / j);
|
||||
let target = i % split;
|
||||
let mut mut_i = i;
|
||||
while mut_i > 0 && (mut_i % split) == target {
|
||||
mut_i /= split;
|
||||
fn is_invalid(value: i64) -> bool {
|
||||
let len = value.ilog10() + 1;
|
||||
for j in (1..len).filter(|x| len % x == 0) {
|
||||
let split = 10_i64.pow(j);
|
||||
let target = value % split;
|
||||
let mut mut_value = value;
|
||||
while mut_value > 0 && (mut_value % split) == target {
|
||||
mut_value /= split;
|
||||
}
|
||||
if mut_i == 0 {
|
||||
// println!("{} in {}-{}", i, low, high);
|
||||
total += i;
|
||||
break;
|
||||
if mut_value == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
total
|
||||
false
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let f = File::open("2-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
let mut ranges = reader
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.split(",")
|
||||
let range_line = reader.lines().next().unwrap()?;
|
||||
let mut ranges: Vec<_> = range_line.split(",")
|
||||
.map(parse_range)
|
||||
.collect::<Vec<_>>();
|
||||
.collect();
|
||||
ranges.sort_unstable();
|
||||
|
||||
let mut total: i64 = 0;
|
||||
let mut last: i64 = 0;
|
||||
for (low, high) in ranges {
|
||||
let low = low.max(last);
|
||||
if low <= high {
|
||||
total += invalid_in_range(low, high);
|
||||
}
|
||||
last = high + 1;
|
||||
let low = max(low, last);
|
||||
last = max(high + 1, last);
|
||||
total += (low..last).filter(|x| is_invalid(*x)).sum::<i64>();
|
||||
}
|
||||
println!("Result {}", total);
|
||||
Ok(())
|
||||
|
||||
@@ -4,12 +4,13 @@ use std::{
|
||||
};
|
||||
|
||||
fn max_joltage(s: &str) -> u64 {
|
||||
let values = s
|
||||
let values: Vec<_> = s
|
||||
.chars()
|
||||
.map(|x| x.to_digit(10).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
.collect();
|
||||
|
||||
let max_idx = |xs: &[u32]| {
|
||||
|
||||
xs.iter()
|
||||
.enumerate()
|
||||
.fold(0, |max, (i, &x)| if x > xs[max] { i } else { max })
|
||||
@@ -26,10 +27,11 @@ fn main() -> Result<(), io::Error> {
|
||||
let f = File::open("3-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let mut total: u64 = 0;
|
||||
for line in reader.lines() {
|
||||
total += max_joltage(line?.as_str()) as u64;
|
||||
}
|
||||
let total: u64 = reader.lines()
|
||||
.map(|l| {
|
||||
max_joltage(&l.unwrap())
|
||||
})
|
||||
.sum();
|
||||
println!("Result: {}", total);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ const NEIGHBOURS: [(i32, i32); 8] = [
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
fn parse_grid_line(line: &str) -> Vec<bool> {
|
||||
line.chars()
|
||||
.map(|c| c == '@')
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_grid_cell(grid: &[Vec<bool>], x: i32, y: i32) -> bool {
|
||||
let (Ok(ux), Ok(uy)) = (usize::try_from(x), usize::try_from(y)) else {
|
||||
return false;
|
||||
@@ -55,21 +61,19 @@ fn count_all_true(grid: &[Vec<bool>]) -> usize {
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let f = File::open("4-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
let original_grid = reader
|
||||
let original_grid: Vec<_> = reader
|
||||
.lines()
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.iter()
|
||||
.map(|s| s.chars().map(|c| c == '@').collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>();
|
||||
.map(|line| Ok(parse_grid_line(&line?)))
|
||||
.collect::<Result<_, io::Error>>()?;
|
||||
|
||||
let mut last_grid = original_grid.clone();
|
||||
loop {
|
||||
let next_grid = update_grid(&last_grid);
|
||||
if next_grid == last_grid {
|
||||
break;
|
||||
}
|
||||
last_grid = next_grid;
|
||||
let mut current_grid = original_grid.clone();
|
||||
let last_grid = loop {
|
||||
let next_grid = update_grid(¤t_grid);
|
||||
if next_grid == current_grid {
|
||||
break next_grid;
|
||||
}
|
||||
current_grid = next_grid;
|
||||
};
|
||||
|
||||
println!(
|
||||
"Result: {}",
|
||||
|
||||
@@ -7,19 +7,19 @@ fn main() -> Result<(), io::Error> {
|
||||
let f = File::open("7-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let lines: Vec<_> = reader.lines().collect::<Result<_, _>>()?;
|
||||
let initial_state: Vec<_> = lines[0]
|
||||
let mut lines = reader.lines();
|
||||
let first = lines.next().transpose()?.unwrap();
|
||||
|
||||
let mut current_state: Vec<_> = first
|
||||
.chars()
|
||||
.map(|c| if c == 'S' { 1 } else { 0 })
|
||||
.collect();
|
||||
let mut next_state = vec![0; current_state.len()];
|
||||
let mut splits: u64 = 0;
|
||||
|
||||
let (final_state, splits) =
|
||||
lines[1..]
|
||||
.iter()
|
||||
.fold((initial_state, 0u64), |(state, mut splits), row| {
|
||||
let mut next_state = vec![0; state.len()];
|
||||
for (i, c) in row.chars().enumerate() {
|
||||
match (c, state[i]) {
|
||||
for line in lines {
|
||||
for (i, c) in line?.chars().enumerate() {
|
||||
match (c, current_state[i]) {
|
||||
(_, 0) => (),
|
||||
('.', x) => {
|
||||
next_state[i] += x;
|
||||
@@ -29,16 +29,18 @@ fn main() -> Result<(), io::Error> {
|
||||
if i > 0 {
|
||||
next_state[i - 1] += x;
|
||||
}
|
||||
if i < state.len() - 1 {
|
||||
if i < current_state.len() - 1 {
|
||||
next_state[i + 1] += x;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
(next_state, splits)
|
||||
});
|
||||
let paths: u64 = final_state.iter().sum();
|
||||
std::mem::swap(&mut current_state, &mut next_state);
|
||||
next_state.fill(0);
|
||||
}
|
||||
|
||||
let paths: u64 = current_state.iter().sum();
|
||||
println!("Result: {} splits, {} paths", splits, paths);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, fs::File, hash::Hash,io::{self, BufRead, BufReader}};
|
||||
use std::{error::Error, fs::File, io::{BufRead, BufReader}, num::ParseIntError, str::FromStr};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
x: u32,
|
||||
y: u32,
|
||||
@@ -16,88 +16,79 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Node {
|
||||
fn from(value: &str) -> Self {
|
||||
let coords: Vec<_> = value.split(',').map(|s| s.parse::<u32>().unwrap()).collect();
|
||||
Node {
|
||||
x: coords[0],
|
||||
y: coords[1],
|
||||
z: coords[2]
|
||||
impl FromStr for Node {
|
||||
type Err = ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut it = s.split(',').map(str::parse::<u32>);
|
||||
Ok(Node {
|
||||
x: it.next().unwrap()?,
|
||||
y: it.next().unwrap()?,
|
||||
z: it.next().unwrap()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Edge {
|
||||
a: Node,
|
||||
b: Node
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DisjointSet<T> {
|
||||
parents: HashMap<T, Option<T>>
|
||||
nodes: Vec<T>,
|
||||
parents: Vec<usize>
|
||||
}
|
||||
|
||||
impl<T: Eq + Hash> FromIterator<T> for DisjointSet<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
DisjointSet {
|
||||
parents: iter.into_iter().map(|x| (x, None)).collect()
|
||||
impl<T> DisjointSet<T> {
|
||||
fn new(nodes: Vec<T>) -> Self {
|
||||
let parents = (0..nodes.len()).collect();
|
||||
DisjointSet { nodes, parents }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + Hash + Clone> DisjointSet<T> {
|
||||
fn representative(&mut self, x: &T) -> Option<T> {
|
||||
match self.parents.get(x)?.clone() {
|
||||
None => Some(x.clone()),
|
||||
Some(p) => {
|
||||
let rep = self.representative(&p)?;
|
||||
self.parents.insert(x.clone(), Some(rep.clone()));
|
||||
Some(rep)
|
||||
}
|
||||
fn representative_idx(&mut self, i: usize) -> usize {
|
||||
let rep = self.parents[i];
|
||||
if rep == i {
|
||||
rep
|
||||
} else {
|
||||
let rep = self.representative_idx(rep);
|
||||
self.parents[i] = rep;
|
||||
rep
|
||||
}
|
||||
}
|
||||
|
||||
fn union(&mut self, a: &T, b: &T) -> Option<T> {
|
||||
let rep_a = self.representative(a).unwrap();
|
||||
let rep_b = self.representative(b).unwrap();
|
||||
if rep_a != rep_b {
|
||||
self.parents.insert(rep_a, Some(rep_b.clone()));
|
||||
Some(rep_b)
|
||||
fn union(&mut self, i: usize, j: usize) -> Option<usize> {
|
||||
let rep_i = self.representative_idx(i);
|
||||
let rep_j = self.representative_idx(j);
|
||||
if rep_i != rep_j {
|
||||
self.parents[rep_j] = rep_i;
|
||||
Some(rep_i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("8-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let nodes: Vec<Node> = reader.lines()
|
||||
.map(|lr| lr.map(|l| l.as_str().into()))
|
||||
.collect::<Result<_, _>>()?;
|
||||
let node_cnt = nodes.len();
|
||||
let nodes: Vec<_> = reader.lines()
|
||||
.map(|l| Ok(l?.parse::<Node>()?))
|
||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||
|
||||
let mut all_edges: Vec<_> =
|
||||
(0..node_cnt).flat_map(|a| {
|
||||
let na = &nodes[a];
|
||||
(a+1..node_cnt).map(|b| {
|
||||
let nb = &nodes[b];
|
||||
let sqr_dist = Node::square_dist(na, nb);
|
||||
(sqr_dist, Edge {a: na.clone(), b: nb.clone()})
|
||||
})
|
||||
})
|
||||
.filter(|(_, e)| e.a != e.b)
|
||||
.collect();
|
||||
all_edges.sort_unstable_by_key(|(d, _)| *d);
|
||||
let mut edges: Vec<(i64, usize, usize)> = Vec::new();
|
||||
for i in 0..nodes.len() {
|
||||
for j in i+1..nodes.len() {
|
||||
let sqr_dist = Node::square_dist(&nodes[i], &nodes[j]);
|
||||
edges.push((sqr_dist, i, j));
|
||||
}
|
||||
}
|
||||
edges.sort_unstable_by_key(|(d, _, _)| *d);
|
||||
|
||||
let mut ds: DisjointSet<_> = nodes.clone().into_iter().collect();
|
||||
let connections: Vec<_> = all_edges.iter()
|
||||
.filter_map(|(_, e)| ds.union(&e.a, &e.b).map(|_|e.clone()))
|
||||
let mut ds: DisjointSet<_> = DisjointSet::new(nodes);
|
||||
let connections: Vec<_> = edges.iter()
|
||||
.filter_map(|(_, i, j)| ds.union(*i, *j).map(|_| (*i, *j)))
|
||||
.collect();
|
||||
|
||||
let nodes = ds.nodes;
|
||||
let last_connection = connections.last().unwrap();
|
||||
println!("Result {}", u64::from(last_connection.a.x) * u64::from(last_connection.b.x));
|
||||
let last_from = &nodes[last_connection.0];
|
||||
let last_to = &nodes[last_connection.1];
|
||||
println!("Result {}", u64::from(last_from.x) * u64::from(last_to.x));
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,32 +1,42 @@
|
||||
use std::{cmp::{max, min, Ordering}, fs::File, i64, io::{self, BufRead, BufReader, ErrorKind}, fmt::Debug, str::FromStr};
|
||||
use std::cmp::{Ordering, max, min};
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ParseVertexError;
|
||||
|
||||
impl Display for ParseVertexError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "cannot parse vertex")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseVertexError {}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Vertex {
|
||||
x: i64,
|
||||
y: i64
|
||||
}
|
||||
|
||||
impl FromStr for Vertex {
|
||||
type Err = io::Error;
|
||||
type Err = ParseVertexError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let parts: Vec<_> = s.split(',')
|
||||
.map(|s| s.parse::<i64>())
|
||||
.collect();
|
||||
let mut values = s.split(',').map(str::parse::<i64>);
|
||||
|
||||
let err = io::Error::new(ErrorKind::Other, "Unable to parse vertex");
|
||||
let Some(&Ok(x)) = parts.get(0) else { return Err(err) };
|
||||
let Some(&Ok(y)) = parts.get(1) else { return Err(err) };
|
||||
Ok(Vertex { x: x, y: y})
|
||||
let Some(Ok(x)) = values.next() else { return Err(ParseVertexError) };
|
||||
let Some(Ok(y)) = values.next() else { return Err(ParseVertexError) };
|
||||
Ok(Vertex { x, y })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Edge {
|
||||
a: Vertex,
|
||||
b: Vertex
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
struct Segment {
|
||||
lo: i64,
|
||||
hi: i64,
|
||||
@@ -36,14 +46,14 @@ struct Segment {
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
fn new(e: Edge) -> Segment {
|
||||
fn new(start: &Vertex, end: &Vertex) -> Segment {
|
||||
Segment {
|
||||
lo: min(e.a.x, e.b.x),
|
||||
hi: max(e.a.x, e.b.x),
|
||||
lo: min(start.x, end.x),
|
||||
hi: max(start.x, end.x),
|
||||
truncate_lo: false,
|
||||
truncate_hi: false,
|
||||
dist:
|
||||
if e.a.x < e.b.x { Some(e.a.y) }
|
||||
if start.x < end.x { Some(start.y) }
|
||||
else { None }
|
||||
}
|
||||
}
|
||||
@@ -51,33 +61,28 @@ impl Segment {
|
||||
|
||||
impl PartialOrd for Segment {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
if self.hi <= other.lo {
|
||||
Some(Ordering::Less)
|
||||
} else if other.hi <= self.lo {
|
||||
Some(Ordering::Greater)
|
||||
} else {
|
||||
Some(Ordering::Equal)
|
||||
}
|
||||
Some(self.cmp(&other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Segment {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
self.lo.cmp(&other.lo)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Segment {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(format!("({}, {})", self.lo, self.hi).as_str())
|
||||
write!(f, "({}, {})", self.lo, self.hi)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn rect_area(x1: i64, x2: i64, y1: i64, y2: i64) -> i64 {
|
||||
(1 + i64::abs(x1 - x2)) * (1 + i64::abs(y1 - y2))
|
||||
}
|
||||
|
||||
fn rect_from_point(state: &Vec<Segment>, v: &Vertex) -> i64 {
|
||||
fn rect_from_point(state: &[Segment], v: &Vertex) -> i64 {
|
||||
let mut max_area = i64::MIN;
|
||||
|
||||
let mut max_y = i64::MIN;
|
||||
@@ -116,7 +121,7 @@ fn rect_from_point(state: &Vec<Segment>, v: &Vertex) -> i64 {
|
||||
|
||||
fn update_state(state: &mut Vec<Segment>, incoming: Segment) {
|
||||
for i in (0..state.len()).rev() {
|
||||
let current = state[i];
|
||||
let current = state[i].clone();
|
||||
if incoming.lo <= current.lo && current.hi <= incoming.hi {
|
||||
state.remove(i);
|
||||
} else if current.lo < incoming.lo && incoming.hi < current.hi {
|
||||
@@ -135,34 +140,31 @@ fn update_state(state: &mut Vec<Segment>, incoming: Segment) {
|
||||
state.sort();
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("9-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
let vertices: Vec<_> = reader.lines()
|
||||
.map(|l| l?.parse::<Vertex>())
|
||||
.collect::<Result<_, _>>()?;
|
||||
.map(|l| Ok(l?.parse::<Vertex>()?))
|
||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||
|
||||
let mut edges: Vec<Edge> = Vec::new();
|
||||
|
||||
let mut horizontal_edges: Vec<(usize, usize)> = Vec::new();
|
||||
for i in 0..vertices.len() {
|
||||
let j = (i + 1) % vertices.len();
|
||||
edges.push(Edge {
|
||||
a: vertices[i],
|
||||
b: vertices[j]
|
||||
});
|
||||
if vertices[i].y == vertices[j].y {
|
||||
horizontal_edges.push((i, j));
|
||||
}
|
||||
edges.sort_unstable_by_key(|e| e.a.y + e.b.y);
|
||||
|
||||
let horizontal_edges: Vec<_> = edges.into_iter()
|
||||
.filter(|e| e.a.y == e.b.y)
|
||||
.collect();
|
||||
}
|
||||
horizontal_edges.sort_unstable_by_key(|e| vertices[e.0].y);
|
||||
|
||||
let mut max_area: i64 = 0;
|
||||
let mut state: Vec<Segment> = Vec::new();
|
||||
state.push(Segment { lo: i64::MIN, hi: i64::MAX, truncate_lo: false, truncate_hi: false, dist: None });
|
||||
let mut state = vec![Segment { lo: i64::MIN, hi: i64::MAX, truncate_lo: false, truncate_hi: false, dist: None }];
|
||||
for e in horizontal_edges {
|
||||
max_area = max(max_area, rect_from_point(&state, &e.a));
|
||||
max_area = max(max_area, rect_from_point(&state, &e.b));
|
||||
update_state(&mut state, Segment::new(e));
|
||||
let start = &vertices[e.0];
|
||||
let end = &vertices[e.1];
|
||||
max_area = max(max_area, rect_from_point(&state, start));
|
||||
max_area = max(max_area, rect_from_point(&state, end));
|
||||
update_state(&mut state, Segment::new(start, end));
|
||||
}
|
||||
|
||||
println!("Result {}", max_area);
|
||||
|
||||
Reference in New Issue
Block a user