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