Days 8-11
This commit is contained in:
131
src/10-factory.rs
Normal file
131
src/10-factory.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use std::cmp::min;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use std::str::FromStr;
|
||||
use std::u64;
|
||||
use nalgebra::{DMatrix, DVector};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Machine {
|
||||
lights: Vec<u64>,
|
||||
buttons: Vec<Vec<u64>>,
|
||||
joltages: Vec<u64>
|
||||
}
|
||||
|
||||
impl FromStr for Machine {
|
||||
type Err = io::Error;
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
Ok(Machine { lights: lights, buttons: buttons , joltages: joltages })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_button_group(s: &str) -> Vec<u64> {
|
||||
s[1..s.len()-1].split(',')
|
||||
.map(|x_s| x_s.parse::<u64>().unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parity_solve(machine: &Machine, target: &Vec<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));
|
||||
for (i, button) in machine.buttons.iter().enumerate() {
|
||||
if selection & (1 << i) != 0 {
|
||||
for j in button {
|
||||
parity ^= 1 << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if parity == 0 {
|
||||
solutions.push(selection);
|
||||
}
|
||||
}
|
||||
solutions
|
||||
}
|
||||
|
||||
fn minimum_solve(machine: &Machine) -> u64 {
|
||||
fn apply_button(machine: &Machine, button_idx: usize, mut current: Vec<u64>) -> Option<Vec<u64>> {
|
||||
for i in &machine.buttons[button_idx] {
|
||||
if current[*i as usize] == 0 {
|
||||
return None;
|
||||
}
|
||||
current[*i as usize] -= 1;
|
||||
}
|
||||
Some(current)
|
||||
}
|
||||
|
||||
fn recurse(machine: &Machine, target: &Vec<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;
|
||||
for parity_sln in parity_solutions {
|
||||
let current = (0..machine.buttons.len())
|
||||
.fold(Some(target.clone()), |state, i| {
|
||||
if parity_sln & (1 << i) != 0 {
|
||||
apply_button(machine, i, state?)
|
||||
} else {
|
||||
state
|
||||
}
|
||||
});
|
||||
let Some(current) = current else { continue };
|
||||
let parity_ones = parity_sln.count_ones() as i64;
|
||||
|
||||
let new_max_cnt =
|
||||
(match min_solution {
|
||||
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))
|
||||
};
|
||||
}
|
||||
min_solution
|
||||
}
|
||||
|
||||
let result = recurse(machine, &machine.joltages, i64::MAX).unwrap_or(0);
|
||||
println!("Result: {}", result);
|
||||
result
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::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();
|
||||
|
||||
println!("Result: {}", presses);
|
||||
Ok(())
|
||||
}
|
||||
70
src/11-reactor.rs
Normal file
70
src/11-reactor.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use std::{collections::HashMap, fs::File, io::{self, BufRead, BufReader}};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum GraphNode {
|
||||
Output,
|
||||
Branch(Vec<String>)
|
||||
}
|
||||
|
||||
fn count_paths(
|
||||
node: &str,
|
||||
nodes: &HashMap<String, GraphNode>,
|
||||
memo: &mut HashMap<String, usize>
|
||||
) -> usize {
|
||||
if let Some(&count) = memo.get(node) {
|
||||
return count;
|
||||
}
|
||||
|
||||
let count =
|
||||
match nodes.get(node) {
|
||||
None => 0,
|
||||
Some(GraphNode::Output) => 1,
|
||||
Some(GraphNode::Branch(children)) => {
|
||||
children.iter()
|
||||
.map(|c| count_paths(c, nodes, memo))
|
||||
.sum()
|
||||
}
|
||||
};
|
||||
memo.insert(node.to_string(), count);
|
||||
count
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let f = File::open("11-input.txt")?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let nodes: HashMap<String, GraphNode> = reader.lines()
|
||||
.map(|line| {
|
||||
let line = line?;
|
||||
let parts: Vec<_> = line.split(' ').collect();
|
||||
let name = parts[0][..3].to_string();
|
||||
if parts[1] == "out" {
|
||||
Ok((name, GraphNode::Output))
|
||||
} else {
|
||||
let branches: Vec<String> = parts[1..].iter().map(|s| s.to_string()).collect();
|
||||
Ok((name, GraphNode::Branch(branches)))
|
||||
}
|
||||
})
|
||||
.collect::<Result<_, io::Error>>()?;
|
||||
|
||||
let svr_paths = count_paths("svr", &nodes, &mut HashMap::new());
|
||||
let missing_fft_paths = count_paths("svr",
|
||||
&(nodes.clone()
|
||||
.into_iter()
|
||||
.filter(|(k, _)| k != "fft")
|
||||
.collect()), &mut HashMap::new());
|
||||
let missing_dac_paths = count_paths("svr",
|
||||
&(nodes.clone()
|
||||
.into_iter()
|
||||
.filter(|(k, _)| k != "dac")
|
||||
.collect()), &mut HashMap::new());
|
||||
let missing_both_paths = count_paths("svr",
|
||||
&(nodes.clone()
|
||||
.into_iter()
|
||||
.filter(|(k, _)| k != "fft" && k != "dac")
|
||||
.collect()), &mut HashMap::new());
|
||||
|
||||
println!("Result {}", svr_paths + missing_both_paths - missing_fft_paths - missing_dac_paths);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
103
src/8-playground.rs
Normal file
103
src/8-playground.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use std::{collections::HashMap, fs::File, hash::Hash,io::{self, BufRead, BufReader}};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
struct Node {
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn square_dist(a: &Node, b: &Node) -> i64 {
|
||||
let dx = i64::from(a.x) - i64::from(b.x);
|
||||
let dy = i64::from(a.y) - i64::from(b.y);
|
||||
let dz = i64::from(a.z) - i64::from(b.z);
|
||||
dx*dx + dy*dy + dz*dz
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Edge {
|
||||
a: Node,
|
||||
b: Node
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DisjointSet<T> {
|
||||
parents: HashMap<T, Option<T>>
|
||||
}
|
||||
|
||||
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: 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 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)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::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 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 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()))
|
||||
.collect();
|
||||
|
||||
let last_connection = connections.last().unwrap();
|
||||
println!("Result {}", u64::from(last_connection.a.x) * u64::from(last_connection.b.x));
|
||||
Ok(())
|
||||
}
|
||||
170
src/9-movie-theater.rs
Normal file
170
src/9-movie-theater.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
use std::{cmp::{max, min, Ordering}, fs::File, i64, io::{self, BufRead, BufReader, ErrorKind}, fmt::Debug, str::FromStr};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Vertex {
|
||||
x: i64,
|
||||
y: i64
|
||||
}
|
||||
|
||||
impl FromStr for Vertex {
|
||||
type Err = io::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let parts: Vec<_> = s.split(',')
|
||||
.map(|s| s.parse::<i64>())
|
||||
.collect();
|
||||
|
||||
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})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Edge {
|
||||
a: Vertex,
|
||||
b: Vertex
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
struct Segment {
|
||||
lo: i64,
|
||||
hi: i64,
|
||||
truncate_lo: bool,
|
||||
truncate_hi: bool,
|
||||
dist: Option<i64>
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
fn new(e: Edge) -> Segment {
|
||||
Segment {
|
||||
lo: min(e.a.x, e.b.x),
|
||||
hi: max(e.a.x, e.b.x),
|
||||
truncate_lo: false,
|
||||
truncate_hi: false,
|
||||
dist:
|
||||
if e.a.x < e.b.x { Some(e.a.y) }
|
||||
else { None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Segment {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut max_area = i64::MIN;
|
||||
|
||||
let mut max_y = i64::MIN;
|
||||
for segment in state {
|
||||
if segment.hi <= v.x { continue }
|
||||
|
||||
let Some(seg_y) = segment.dist else { break };
|
||||
if seg_y >= max_y {
|
||||
max_y = seg_y;
|
||||
if !segment.truncate_hi {
|
||||
max_area = max(max_area, rect_area(v.x, segment.hi, v.y, seg_y));
|
||||
}
|
||||
if !segment.truncate_lo {
|
||||
max_area = max(max_area, rect_area(v.x, segment.lo, v.y, seg_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut max_y = i64::MIN;
|
||||
for segment in state.iter().rev() {
|
||||
if segment.lo >= v.x { continue }
|
||||
|
||||
let Some(seg_y) = segment.dist else { break };
|
||||
if seg_y >= max_y {
|
||||
max_y = seg_y;
|
||||
if !segment.truncate_hi {
|
||||
max_area = max(max_area, rect_area(v.x, segment.hi, v.y, seg_y));
|
||||
}
|
||||
if !segment.truncate_lo {
|
||||
max_area = max(max_area, rect_area(v.x, segment.lo, v.y, seg_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
max_area
|
||||
}
|
||||
|
||||
fn update_state(state: &mut Vec<Segment>, incoming: Segment) {
|
||||
for i in (0..state.len()).rev() {
|
||||
let current = state[i];
|
||||
if incoming.lo <= current.lo && current.hi <= incoming.hi {
|
||||
state.remove(i);
|
||||
} else if current.lo < incoming.lo && incoming.hi < current.hi {
|
||||
state.push(Segment { hi: incoming.lo, truncate_hi: true, ..current });
|
||||
state.push(Segment { lo: incoming.hi, truncate_lo: true, ..current });
|
||||
state.remove(i);
|
||||
} else if current.lo < incoming.lo && incoming.lo < current.hi {
|
||||
state[i].hi = incoming.lo;
|
||||
state[i].truncate_hi = true;
|
||||
} else if current.lo < incoming.hi && incoming.hi < current.hi {
|
||||
state[i].lo = incoming.hi;
|
||||
state[i].truncate_lo = true;
|
||||
}
|
||||
}
|
||||
state.push(incoming);
|
||||
state.sort();
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::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<_, _>>()?;
|
||||
|
||||
let mut edges: Vec<Edge> = Vec::new();
|
||||
for i in 0..vertices.len() {
|
||||
let j = (i + 1) % vertices.len();
|
||||
edges.push(Edge {
|
||||
a: vertices[i],
|
||||
b: vertices[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();
|
||||
|
||||
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 });
|
||||
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));
|
||||
}
|
||||
|
||||
println!("Result {}", max_area);
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user