Format all
This commit is contained in:
@@ -10,7 +10,7 @@ struct Machine {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
lights: Vec<u64>,
|
lights: Vec<u64>,
|
||||||
buttons: Vec<Vec<usize>>,
|
buttons: Vec<Vec<usize>>,
|
||||||
joltages: Vec<u64>
|
joltages: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Machine {
|
impl FromStr for Machine {
|
||||||
@@ -34,27 +34,31 @@ impl FromStr for Machine {
|
|||||||
.map(|j_s| j_s.parse::<u64>())
|
.map(|j_s| j_s.parse::<u64>())
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
Ok(Machine { lights, buttons , joltages })
|
Ok(Machine {
|
||||||
|
lights,
|
||||||
|
buttons,
|
||||||
|
joltages,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_button_group(s: &str) -> Result<Vec<usize>, ParseIntError> {
|
fn parse_button_group(s: &str) -> Result<Vec<usize>, ParseIntError> {
|
||||||
s[1..s.len()-1].split(',')
|
s[1..s.len() - 1]
|
||||||
|
.split(',')
|
||||||
.map(str::parse::<usize>)
|
.map(str::parse::<usize>)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parity_solve(machine: &Machine, target: &[u64]) -> Vec<u64> {
|
fn parity_solve(machine: &Machine, target: &[u64]) -> Vec<u64> {
|
||||||
let mut solutions: Vec<u64> = Vec::new();
|
let mut solutions: Vec<u64> = Vec::new();
|
||||||
for selection in 0..(1 << machine.buttons.len()) {
|
for selection in 0..(1 << machine.buttons.len()) {
|
||||||
let mut parity = target.iter().rev()
|
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() {
|
for (i, button) in machine.buttons.iter().enumerate() {
|
||||||
if selection & (1 << i) != 0 {
|
if selection & (1 << i) != 0 {
|
||||||
parity = button.iter().fold(parity, |parity, j| {
|
parity = button.iter().fold(parity, |parity, j| parity ^ (1 << j));
|
||||||
parity ^ (1 << j)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if parity == 0 {
|
if parity == 0 {
|
||||||
@@ -65,7 +69,11 @@ fn parity_solve(machine: &Machine, target: &[u64]) -> Vec<u64> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn minimum_solve(machine: &Machine) -> u64 {
|
fn minimum_solve(machine: &Machine) -> u64 {
|
||||||
fn apply_button<'a>(machine: &Machine, button_idx: usize, current: &'a mut Vec<u64>) -> Option<&'a mut 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] {
|
for i in &machine.buttons[button_idx] {
|
||||||
if current[*i] == 0 {
|
if current[*i] == 0 {
|
||||||
return None;
|
return None;
|
||||||
@@ -76,8 +84,12 @@ fn minimum_solve(machine: &Machine) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn recurse(machine: &Machine, target: &[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 target.iter().sum::<u64>() == 0 {
|
||||||
if max_cnt <= 0 { return None };
|
return Some(0);
|
||||||
|
};
|
||||||
|
if max_cnt <= 0 {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
let parity_solutions = parity_solve(machine, target);
|
let parity_solutions = parity_solve(machine, target);
|
||||||
|
|
||||||
@@ -85,8 +97,8 @@ fn minimum_solve(machine: &Machine) -> u64 {
|
|||||||
let mut current_storage = target.to_vec();
|
let mut current_storage = target.to_vec();
|
||||||
for parity_sln in parity_solutions {
|
for parity_sln in parity_solutions {
|
||||||
current_storage.copy_from_slice(target);
|
current_storage.copy_from_slice(target);
|
||||||
let current = (0..machine.buttons.len())
|
let current =
|
||||||
.fold(Some(&mut current_storage), |state, i| {
|
(0..machine.buttons.len()).fold(Some(&mut current_storage), |state, i| {
|
||||||
if parity_sln & (1 << i) != 0 {
|
if parity_sln & (1 << i) != 0 {
|
||||||
apply_button(machine, i, state?)
|
apply_button(machine, i, state?)
|
||||||
} else {
|
} else {
|
||||||
@@ -96,17 +108,19 @@ fn minimum_solve(machine: &Machine) -> u64 {
|
|||||||
let Some(current) = current else { continue };
|
let Some(current) = current else { continue };
|
||||||
let parity_ones = parity_sln.count_ones() as i64;
|
let parity_ones = parity_sln.count_ones() as i64;
|
||||||
|
|
||||||
let new_max_cnt =
|
let new_max_cnt = (match min_presses {
|
||||||
(match min_presses {
|
|
||||||
None => max_cnt,
|
None => max_cnt,
|
||||||
Some(ms) => min(ms as i64, max_cnt)
|
Some(ms) => min(ms as i64, max_cnt),
|
||||||
} - parity_ones) / 2;
|
} - parity_ones)
|
||||||
|
/ 2;
|
||||||
let new_target: Vec<_> = current.iter().map(|&x| x / 2).collect();
|
let new_target: Vec<_> = current.iter().map(|&x| x / 2).collect();
|
||||||
let Some(sln) = recurse(machine, &new_target, new_max_cnt) else { continue };
|
let Some(sln) = recurse(machine, &new_target, new_max_cnt) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let presses = parity_ones as u64 + 2u64 * sln;
|
let presses = parity_ones as u64 + 2u64 * sln;
|
||||||
min_presses = Some(match min_presses {
|
min_presses = Some(match min_presses {
|
||||||
None => presses,
|
None => presses,
|
||||||
Some(ms) => min(ms, presses)
|
Some(ms) => min(ms, presses),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
min_presses
|
min_presses
|
||||||
@@ -119,7 +133,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let f = File::open("10-input.txt")?;
|
let f = File::open("10-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
|
|
||||||
let machines: Vec<_> = reader.lines()
|
let machines: Vec<_> = reader
|
||||||
|
.lines()
|
||||||
.map(|l| Ok(l?.parse::<Machine>()?))
|
.map(|l| Ok(l?.parse::<Machine>()?))
|
||||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||||
println!("Parsed {} machines", machines.len());
|
println!("Parsed {} machines", machines.len());
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
use std::{collections::HashMap, fs::File, io::{self, BufRead, BufReader}};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::File,
|
||||||
|
io::{self, BufRead, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum GraphNode {
|
enum GraphNode {
|
||||||
Output,
|
Output,
|
||||||
Branch(Vec<String>)
|
Branch(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_paths(
|
fn count_paths(
|
||||||
node: &str,
|
node: &str,
|
||||||
nodes: &HashMap<String, GraphNode>,
|
nodes: &HashMap<String, GraphNode>,
|
||||||
memo: &mut HashMap<String, usize>
|
memo: &mut HashMap<String, usize>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
if let Some(&count) = memo.get(node) {
|
if let Some(&count) = memo.get(node) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
let count =
|
let count = match nodes.get(node) {
|
||||||
match nodes.get(node) {
|
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(GraphNode::Output) => 1,
|
Some(GraphNode::Output) => 1,
|
||||||
Some(GraphNode::Branch(children)) => {
|
Some(GraphNode::Branch(children)) => {
|
||||||
children.iter()
|
children.iter().map(|c| count_paths(c, nodes, memo)).sum()
|
||||||
.map(|c| count_paths(c, nodes, memo))
|
|
||||||
.sum()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
memo.insert(node.to_string(), count);
|
memo.insert(node.to_string(), count);
|
||||||
@@ -33,7 +34,8 @@ fn main() -> Result<(), io::Error> {
|
|||||||
let f = File::open("11-input.txt")?;
|
let f = File::open("11-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
|
|
||||||
let nodes: HashMap<String, GraphNode> = reader.lines()
|
let nodes: HashMap<String, GraphNode> = reader
|
||||||
|
.lines()
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
let line = line?;
|
let line = line?;
|
||||||
let parts: Vec<_> = line.split(' ').collect();
|
let parts: Vec<_> = line.split(' ').collect();
|
||||||
@@ -48,23 +50,38 @@ fn main() -> Result<(), io::Error> {
|
|||||||
.collect::<Result<_, io::Error>>()?;
|
.collect::<Result<_, io::Error>>()?;
|
||||||
|
|
||||||
let svr_paths = count_paths("svr", &nodes, &mut HashMap::new());
|
let svr_paths = count_paths("svr", &nodes, &mut HashMap::new());
|
||||||
let missing_fft_paths = count_paths("svr",
|
let missing_fft_paths = count_paths(
|
||||||
&(nodes.clone()
|
"svr",
|
||||||
|
&(nodes
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(k, _)| k != "fft")
|
.filter(|(k, _)| k != "fft")
|
||||||
.collect()), &mut HashMap::new());
|
.collect()),
|
||||||
let missing_dac_paths = count_paths("svr",
|
&mut HashMap::new(),
|
||||||
&(nodes.clone()
|
);
|
||||||
|
let missing_dac_paths = count_paths(
|
||||||
|
"svr",
|
||||||
|
&(nodes
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(k, _)| k != "dac")
|
.filter(|(k, _)| k != "dac")
|
||||||
.collect()), &mut HashMap::new());
|
.collect()),
|
||||||
let missing_both_paths = count_paths("svr",
|
&mut HashMap::new(),
|
||||||
&(nodes.clone()
|
);
|
||||||
|
let missing_both_paths = count_paths(
|
||||||
|
"svr",
|
||||||
|
&(nodes
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(k, _)| k != "fft" && k != "dac")
|
.filter(|(k, _)| k != "fft" && k != "dac")
|
||||||
.collect()), &mut HashMap::new());
|
.collect()),
|
||||||
|
&mut HashMap::new(),
|
||||||
|
);
|
||||||
|
|
||||||
println!("Result {}", svr_paths + missing_both_paths - missing_fft_paths - missing_dac_paths);
|
println!(
|
||||||
|
"Result {}",
|
||||||
|
svr_paths + missing_both_paths - missing_fft_paths - missing_dac_paths
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,28 @@
|
|||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::string::ParseError;
|
use std::{
|
||||||
use std::{fs::File, io::{self, BufRead, BufReader}, str::FromStr};
|
fs::File,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
struct Piece {
|
struct Piece {
|
||||||
cells: Vec<Vec<bool>>
|
cells: Vec<Vec<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Piece {
|
impl FromStr for Piece {
|
||||||
type Err = Infallible;
|
type Err = Infallible;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let cells =
|
let cells = s
|
||||||
s.split('\n').map(|row| {
|
.split('\n')
|
||||||
row.chars().filter_map(|c| {
|
.map(|row| {
|
||||||
match c {
|
row.chars()
|
||||||
|
.filter_map(|c| match c {
|
||||||
'#' => Some(true),
|
'#' => Some(true),
|
||||||
'.' => Some(false),
|
'.' => Some(false),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
@@ -40,17 +43,14 @@ impl Piece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn true_area(&self) -> u64 {
|
fn true_area(&self) -> u64 {
|
||||||
self.cells.iter()
|
self.cells.iter().flatten().filter(|&&b| b).count() as u64
|
||||||
.flatten()
|
|
||||||
.filter(|&&b| b)
|
|
||||||
.count() as u64
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Region {
|
struct Region {
|
||||||
width: u64,
|
width: u64,
|
||||||
height: u64,
|
height: u64,
|
||||||
requirements: Vec<u64>
|
requirements: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Region {
|
impl FromStr for Region {
|
||||||
@@ -61,26 +61,36 @@ impl FromStr for Region {
|
|||||||
let (width_str, height_str) = area_str.split_once('x').unwrap();
|
let (width_str, height_str) = area_str.split_once('x').unwrap();
|
||||||
let width = width_str.parse::<u64>()?;
|
let width = width_str.parse::<u64>()?;
|
||||||
let height = height_str.parse::<u64>()?;
|
let height = height_str.parse::<u64>()?;
|
||||||
let requirements = requirements_str.split(' ')
|
let requirements = requirements_str
|
||||||
|
.split(' ')
|
||||||
.filter_map(|s| s.parse::<u64>().ok())
|
.filter_map(|s| s.parse::<u64>().ok())
|
||||||
.collect();
|
.collect();
|
||||||
Ok(Region { width, height, requirements })
|
Ok(Region {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
requirements,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_solveable(pieces: &[Piece], region: &Region) -> bool {
|
fn is_solveable(pieces: &[Piece], region: &Region) -> bool {
|
||||||
// Lower area bound = perfectly packed
|
// Lower area bound = perfectly packed
|
||||||
let region_area = region.width * region.height;
|
let region_area = region.width * region.height;
|
||||||
let used_area: u64 = pieces.iter()
|
let used_area: u64 = pieces
|
||||||
|
.iter()
|
||||||
.zip(region.requirements.iter())
|
.zip(region.requirements.iter())
|
||||||
.map(|(piece, cnt)| piece.true_area() * cnt)
|
.map(|(piece, cnt)| piece.true_area() * cnt)
|
||||||
.sum();
|
.sum();
|
||||||
if used_area > region_area { return false };
|
if used_area > region_area {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// Upper area bound = 3x3 pieces
|
// Upper area bound = 3x3 pieces
|
||||||
let available_3x3s = region.width / 3 * region.height / 3;
|
let available_3x3s = region.width / 3 * region.height / 3;
|
||||||
let piece_cnt: u64 = region.requirements.iter().sum();
|
let piece_cnt: u64 = region.requirements.iter().sum();
|
||||||
if piece_cnt <= available_3x3s { return true };
|
if piece_cnt <= available_3x3s {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
println!("Non-trivial solution");
|
println!("Non-trivial solution");
|
||||||
false
|
false
|
||||||
@@ -93,19 +103,18 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let lines: Vec<_> = reader.lines().collect::<Result<_, _>>()?;
|
let lines: Vec<_> = reader.lines().collect::<Result<_, _>>()?;
|
||||||
let (lines_pieces, lines_regions) = lines.split_at(30);
|
let (lines_pieces, lines_regions) = lines.split_at(30);
|
||||||
|
|
||||||
let pieces: Vec<_> = lines_pieces.chunks(5)
|
let pieces: Vec<_> = lines_pieces
|
||||||
.map(|lines| {
|
.chunks(5)
|
||||||
Ok(lines[1..lines.len()-1].join("\n").parse::<Piece>()?)
|
.map(|lines| Ok(lines[1..lines.len() - 1].join("\n").parse::<Piece>()?))
|
||||||
})
|
|
||||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||||
|
|
||||||
let regions: Vec<_> = lines_regions.iter()
|
let regions: Vec<_> = lines_regions
|
||||||
.map(|line| {
|
.iter()
|
||||||
Ok(line.parse::<Region>()?)
|
.map(|line| Ok(line.parse::<Region>()?))
|
||||||
})
|
|
||||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||||
|
|
||||||
let result: u64 = regions.iter()
|
let result: u64 = regions
|
||||||
|
.iter()
|
||||||
.filter(|region| is_solveable(&pieces, region))
|
.filter(|region| is_solveable(&pieces, region))
|
||||||
.count() as u64;
|
.count() as u64;
|
||||||
println!("Result: {}", result);
|
println!("Result: {}", result);
|
||||||
|
|||||||
@@ -29,9 +29,7 @@ fn main() -> Result<(), io::Error> {
|
|||||||
let f = File::open("2-input.txt")?;
|
let f = File::open("2-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let range_line = reader.lines().next().unwrap()?;
|
let range_line = reader.lines().next().unwrap()?;
|
||||||
let mut ranges: Vec<_> = range_line.split(",")
|
let mut ranges: Vec<_> = range_line.split(",").map(parse_range).collect();
|
||||||
.map(parse_range)
|
|
||||||
.collect();
|
|
||||||
ranges.sort_unstable();
|
ranges.sort_unstable();
|
||||||
|
|
||||||
let mut total: i64 = 0;
|
let mut total: i64 = 0;
|
||||||
|
|||||||
@@ -4,13 +4,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn max_joltage(s: &str) -> u64 {
|
fn max_joltage(s: &str) -> u64 {
|
||||||
let values: Vec<_> = s
|
let values: Vec<_> = s.chars().map(|x| x.to_digit(10).unwrap()).collect();
|
||||||
.chars()
|
|
||||||
.map(|x| x.to_digit(10).unwrap())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let max_idx = |xs: &[u32]| {
|
let max_idx = |xs: &[u32]| {
|
||||||
|
|
||||||
xs.iter()
|
xs.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.fold(0, |max, (i, &x)| if x > xs[max] { i } else { max })
|
.fold(0, |max, (i, &x)| if x > xs[max] { i } else { max })
|
||||||
@@ -27,11 +23,7 @@ fn main() -> Result<(), io::Error> {
|
|||||||
let f = File::open("3-input.txt")?;
|
let f = File::open("3-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
|
|
||||||
let total: u64 = reader.lines()
|
let total: u64 = reader.lines().map(|l| max_joltage(&l.unwrap())).sum();
|
||||||
.map(|l| {
|
|
||||||
max_joltage(&l.unwrap())
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
println!("Result: {}", total);
|
println!("Result: {}", total);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ const NEIGHBOURS: [(i32, i32); 8] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
fn parse_grid_line(line: &str) -> Vec<bool> {
|
fn parse_grid_line(line: &str) -> Vec<bool> {
|
||||||
line.chars()
|
line.chars().map(|c| c == '@').collect()
|
||||||
.map(|c| c == '@')
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_grid_cell(grid: &[Vec<bool>], x: i32, y: i32) -> bool {
|
fn get_grid_cell(grid: &[Vec<bool>], x: i32, y: i32) -> bool {
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
use std::{error::Error, fs::File, io::{BufRead, BufReader}, num::ParseIntError, str::FromStr};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
num::ParseIntError,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Node {
|
struct Node {
|
||||||
@@ -31,7 +37,7 @@ impl FromStr for Node {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct DisjointSet<T> {
|
struct DisjointSet<T> {
|
||||||
nodes: Vec<T>,
|
nodes: Vec<T>,
|
||||||
parents: Vec<usize>
|
parents: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DisjointSet<T> {
|
impl<T> DisjointSet<T> {
|
||||||
@@ -67,7 +73,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let f = File::open("8-input.txt")?;
|
let f = File::open("8-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
|
|
||||||
let nodes: Vec<_> = reader.lines()
|
let nodes: Vec<_> = reader
|
||||||
|
.lines()
|
||||||
.map(|l| Ok(l?.parse::<Node>()?))
|
.map(|l| Ok(l?.parse::<Node>()?))
|
||||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||||
|
|
||||||
@@ -81,7 +88,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
edges.sort_unstable_by_key(|(d, _, _)| *d);
|
edges.sort_unstable_by_key(|(d, _, _)| *d);
|
||||||
|
|
||||||
let mut ds: DisjointSet<_> = DisjointSet::new(nodes);
|
let mut ds: DisjointSet<_> = DisjointSet::new(nodes);
|
||||||
let connections: Vec<_> = edges.iter()
|
let connections: Vec<_> = edges
|
||||||
|
.iter()
|
||||||
.filter_map(|(_, i, j)| ds.union(*i, *j).map(|_| (*i, *j)))
|
.filter_map(|(_, i, j)| ds.union(*i, *j).map(|_| (*i, *j)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use std::fs::File;
|
|||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParseVertexError;
|
struct ParseVertexError;
|
||||||
|
|
||||||
@@ -17,11 +16,10 @@ impl Display for ParseVertexError {
|
|||||||
|
|
||||||
impl Error for ParseVertexError {}
|
impl Error for ParseVertexError {}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
x: i64,
|
x: i64,
|
||||||
y: i64
|
y: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Vertex {
|
impl FromStr for Vertex {
|
||||||
@@ -29,20 +27,23 @@ impl FromStr for Vertex {
|
|||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let mut values = s.split(',').map(str::parse::<i64>);
|
let mut values = s.split(',').map(str::parse::<i64>);
|
||||||
|
|
||||||
let Some(Ok(x)) = values.next() else { return Err(ParseVertexError) };
|
let Some(Ok(x)) = values.next() else {
|
||||||
let Some(Ok(y)) = values.next() else { return Err(ParseVertexError) };
|
return Err(ParseVertexError);
|
||||||
|
};
|
||||||
|
let Some(Ok(y)) = values.next() else {
|
||||||
|
return Err(ParseVertexError);
|
||||||
|
};
|
||||||
Ok(Vertex { x, y })
|
Ok(Vertex { x, y })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
struct Segment {
|
struct Segment {
|
||||||
lo: i64,
|
lo: i64,
|
||||||
hi: i64,
|
hi: i64,
|
||||||
truncate_lo: bool,
|
truncate_lo: bool,
|
||||||
truncate_hi: bool,
|
truncate_hi: bool,
|
||||||
dist: Option<i64>
|
dist: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segment {
|
impl Segment {
|
||||||
@@ -52,9 +53,7 @@ impl Segment {
|
|||||||
hi: max(start.x, end.x),
|
hi: max(start.x, end.x),
|
||||||
truncate_lo: false,
|
truncate_lo: false,
|
||||||
truncate_hi: false,
|
truncate_hi: false,
|
||||||
dist:
|
dist: if start.x < end.x { Some(start.y) } else { None },
|
||||||
if start.x < end.x { Some(start.y) }
|
|
||||||
else { None }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +76,6 @@ impl Debug for Segment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn rect_area(x1: i64, x2: i64, y1: i64, y2: i64) -> i64 {
|
fn rect_area(x1: i64, x2: i64, y1: i64, y2: i64) -> i64 {
|
||||||
(1 + i64::abs(x1 - x2)) * (1 + i64::abs(y1 - y2))
|
(1 + i64::abs(x1 - x2)) * (1 + i64::abs(y1 - y2))
|
||||||
}
|
}
|
||||||
@@ -87,7 +85,9 @@ fn rect_from_point(state: &[Segment], v: &Vertex) -> i64 {
|
|||||||
|
|
||||||
let mut max_y = i64::MIN;
|
let mut max_y = i64::MIN;
|
||||||
for segment in state {
|
for segment in state {
|
||||||
if segment.hi <= v.x { continue }
|
if segment.hi <= v.x {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let Some(seg_y) = segment.dist else { break };
|
let Some(seg_y) = segment.dist else { break };
|
||||||
if seg_y >= max_y {
|
if seg_y >= max_y {
|
||||||
@@ -103,7 +103,9 @@ fn rect_from_point(state: &[Segment], v: &Vertex) -> i64 {
|
|||||||
|
|
||||||
let mut max_y = i64::MIN;
|
let mut max_y = i64::MIN;
|
||||||
for segment in state.iter().rev() {
|
for segment in state.iter().rev() {
|
||||||
if segment.lo >= v.x { continue }
|
if segment.lo >= v.x {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let Some(seg_y) = segment.dist else { break };
|
let Some(seg_y) = segment.dist else { break };
|
||||||
if seg_y >= max_y {
|
if seg_y >= max_y {
|
||||||
@@ -125,8 +127,16 @@ fn update_state(state: &mut Vec<Segment>, incoming: Segment) {
|
|||||||
if incoming.lo <= current.lo && current.hi <= incoming.hi {
|
if incoming.lo <= current.lo && current.hi <= incoming.hi {
|
||||||
state.remove(i);
|
state.remove(i);
|
||||||
} else if current.lo < incoming.lo && incoming.hi < current.hi {
|
} else if current.lo < incoming.lo && incoming.hi < current.hi {
|
||||||
state.push(Segment { hi: incoming.lo, truncate_hi: true, ..current });
|
state.push(Segment {
|
||||||
state.push(Segment { lo: incoming.hi, truncate_lo: true, ..current });
|
hi: incoming.lo,
|
||||||
|
truncate_hi: true,
|
||||||
|
..current
|
||||||
|
});
|
||||||
|
state.push(Segment {
|
||||||
|
lo: incoming.hi,
|
||||||
|
truncate_lo: true,
|
||||||
|
..current
|
||||||
|
});
|
||||||
state.remove(i);
|
state.remove(i);
|
||||||
} else if current.lo < incoming.lo && incoming.lo < current.hi {
|
} else if current.lo < incoming.lo && incoming.lo < current.hi {
|
||||||
state[i].hi = incoming.lo;
|
state[i].hi = incoming.lo;
|
||||||
@@ -143,11 +153,11 @@ fn update_state(state: &mut Vec<Segment>, incoming: Segment) {
|
|||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let f = File::open("9-input.txt")?;
|
let f = File::open("9-input.txt")?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let vertices: Vec<_> = reader.lines()
|
let vertices: Vec<_> = reader
|
||||||
|
.lines()
|
||||||
.map(|l| Ok(l?.parse::<Vertex>()?))
|
.map(|l| Ok(l?.parse::<Vertex>()?))
|
||||||
.collect::<Result<_, Box<dyn Error>>>()?;
|
.collect::<Result<_, Box<dyn Error>>>()?;
|
||||||
|
|
||||||
|
|
||||||
let mut horizontal_edges: Vec<(usize, usize)> = Vec::new();
|
let mut horizontal_edges: Vec<(usize, usize)> = Vec::new();
|
||||||
for i in 0..vertices.len() {
|
for i in 0..vertices.len() {
|
||||||
let j = (i + 1) % vertices.len();
|
let j = (i + 1) % vertices.len();
|
||||||
@@ -158,7 +168,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
horizontal_edges.sort_unstable_by_key(|e| vertices[e.0].y);
|
horizontal_edges.sort_unstable_by_key(|e| vertices[e.0].y);
|
||||||
|
|
||||||
let mut max_area: i64 = 0;
|
let mut max_area: i64 = 0;
|
||||||
let mut state = vec![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 {
|
for e in horizontal_edges {
|
||||||
let start = &vertices[e.0];
|
let start = &vertices[e.0];
|
||||||
let end = &vertices[e.1];
|
let end = &vertices[e.1];
|
||||||
|
|||||||
Reference in New Issue
Block a user