Compare commits

...

6 Commits

Author SHA1 Message Date
976cb3651c d18p2 2024-06-17 22:30:37 -07:00
5d522dc0f6 d18 2024-06-16 23:12:11 -07:00
1affc44c28 d17p2 2024-06-16 22:17:19 -07:00
40aae04d70 d17p1 2024-06-15 23:29:37 -07:00
0d60232b6f d16p2 2024-03-30 22:43:57 -07:00
a194cb2d6c d16p1 2024-03-30 10:49:01 -07:00
19 changed files with 3031 additions and 0 deletions

7
day16/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day16"
version = "0.1.0"

8
day16/Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "day16"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

52
day16/input.txt Normal file
View File

@@ -0,0 +1,52 @@
Valve AP has flow rate=0; tunnels lead to valves AA, ON
Valve QN has flow rate=21; tunnels lead to valves RI, CG
Valve LK has flow rate=0; tunnels lead to valves XM, AA
Valve HA has flow rate=0; tunnels lead to valves WH, KF
Valve DS has flow rate=16; tunnel leads to valve II
Valve KD has flow rate=0; tunnels lead to valves KG, QB
Valve JW has flow rate=0; tunnels lead to valves AD, KF
Valve HU has flow rate=0; tunnels lead to valves UK, CO
Valve AE has flow rate=10; tunnels lead to valves IR, PT, UV
Valve XA has flow rate=0; tunnels lead to valves CG, EU
Valve SE has flow rate=17; tunnels lead to valves YR, AD
Valve TR has flow rate=0; tunnels lead to valves AL, CS
Valve BS has flow rate=0; tunnels lead to valves YH, XM
Valve IJ has flow rate=24; tunnels lead to valves XN, WE
Valve AA has flow rate=0; tunnels lead to valves LK, AP, IZ, PC, QD
Valve KG has flow rate=0; tunnels lead to valves KD, CS
Valve QV has flow rate=0; tunnels lead to valves XM, II
Valve PC has flow rate=0; tunnels lead to valves AA, YF
Valve GJ has flow rate=20; tunnel leads to valve RI
Valve UV has flow rate=0; tunnels lead to valves UK, AE
Valve IR has flow rate=0; tunnels lead to valves EU, AE
Valve EU has flow rate=13; tunnels lead to valves IR, DT, XA, ON
Valve ED has flow rate=0; tunnels lead to valves XN, CO
Valve DT has flow rate=0; tunnels lead to valves EU, UK
Valve YE has flow rate=0; tunnels lead to valves XM, WS
Valve AD has flow rate=0; tunnels lead to valves JW, SE
Valve WE has flow rate=0; tunnels lead to valves IJ, NA
Valve UK has flow rate=5; tunnels lead to valves UV, DT, QD, HU
Valve YR has flow rate=0; tunnels lead to valves OS, SE
Valve II has flow rate=0; tunnels lead to valves QV, DS
Valve GT has flow rate=0; tunnels lead to valves CS, MN
Valve YH has flow rate=0; tunnels lead to valves BS, QB
Valve BQ has flow rate=0; tunnels lead to valves XM, KF
Valve OS has flow rate=0; tunnels lead to valves YR, NA
Valve WH has flow rate=0; tunnels lead to valves QB, HA
Valve QB has flow rate=4; tunnels lead to valves WH, KD, YH, IZ
Valve ON has flow rate=0; tunnels lead to valves AP, EU
Valve IZ has flow rate=0; tunnels lead to valves AA, QB
Valve MN has flow rate=25; tunnel leads to valve GT
Valve CG has flow rate=0; tunnels lead to valves XA, QN
Valve QD has flow rate=0; tunnels lead to valves UK, AA
Valve AL has flow rate=0; tunnels lead to valves KF, TR
Valve XN has flow rate=0; tunnels lead to valves ED, IJ
Valve WS has flow rate=0; tunnels lead to valves YE, CS
Valve CO has flow rate=18; tunnels lead to valves ED, PT, HU
Valve PT has flow rate=0; tunnels lead to valves CO, AE
Valve RI has flow rate=0; tunnels lead to valves QN, GJ
Valve CS has flow rate=9; tunnels lead to valves YF, GT, WS, TR, KG
Valve YF has flow rate=0; tunnels lead to valves PC, CS
Valve NA has flow rate=23; tunnels lead to valves OS, WE
Valve KF has flow rate=12; tunnels lead to valves HA, AL, JW, BQ
Valve XM has flow rate=3; tunnels lead to valves LK, QV, YE, BS, BQ

157
day16/src/main.rs Normal file
View File

@@ -0,0 +1,157 @@
use std::env;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::collections::{HashMap, HashSet, VecDeque};
use std::cmp::max;
use std::str::FromStr;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
const TIME: u64 = 26;
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
let mut iter = str.chars().peekable();
let mut prefix = String::new();
while let Some(c) = iter.peek() {
if !c.to_string().parse::<T>().is_ok() {
break;
}
prefix.push(iter.next().unwrap());
}
Ok((prefix.parse::<T>()?, prefix.len()))
}
#[derive(Debug)]
struct Valve {
rate: u64,
links: Vec<(String, u64)>,
}
fn read_input(fname: &String) -> Result<HashMap<String, Valve>, <u64 as FromStr>::Err> {
let file = File::open(fname).expect("cannot open input file");
let lines = BufReader::new(file).lines();
let mut valves = HashMap::new();
for line in lines.flatten() {
let name = String::from(&line[6..=7]);
let (rate, rate_len) = parse_str::<u64>(&line[23..])?;
let links_str = &line[23 + rate_len + 24..];
let mut link = String::new();
let mut links = Vec::new();
let mut iter = links_str.chars();
loop {
match iter.next() {
Some(' ') | Some(',') => continue,
None => break,
Some(c) => {
link.push(c);
link.push(iter.next().unwrap());
links.push((link.clone(), 1));
link = String::new();
},
}
}
valves.insert(name, Valve { rate, links });
}
Ok(valves)
}
fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
let mut visited = HashSet::from([valve.clone()]);
let mut queue = VecDeque::from([(valve.clone(), 0)]);
let mut links = Vec::new();
while !queue.is_empty() {
let (current_valve, current_cost) = queue.pop_front().unwrap();
if current_valve != *valve && valves[&current_valve].rate > 0 {
// +1 because it takes 1min to open a valve
links.push((current_valve.clone(), current_cost + 1));
}
for (next_valve, _) in &valves[&current_valve].links {
if !visited.contains(next_valve) {
queue.push_back((next_valve.clone(), current_cost + 1));
visited.insert(next_valve.clone());
}
}
}
Valve { rate: valves[valve].rate, links: links }
}
fn print_map<T1: Debug, T2: Debug>(map: &HashMap<T1, T2>) {
for (k, v) in map {
println!("{:?}: {:?}", k, v);
}
println!("");
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct Visited {
set: HashSet<String>,
}
impl Hash for Visited {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = &mut self.set.iter()
.filter(|x| *x != "AA")
.cloned().collect::<Vec<String>>();
l.sort();
l.join("");
l.hash(state);
}
}
fn get_pressure_map(valves: &HashMap<String, Valve>) -> HashMap<Visited, u64> {
let mut max_pressure: HashMap<Visited, u64> = HashMap::new();
let mut queue: VecDeque<(String, u64, u64, Visited)> =
VecDeque::from([(
String::from("AA"), 0, 0,
Visited { set: HashSet::new() },
)]);
while !queue.is_empty() {
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
// println!("{}: {}, {}, {:?}", valve, cost, pressure, visited);
if let Some(last_max) = max_pressure.get_mut(&visited) {
*last_max = max(*last_max, pressure);
} else {
max_pressure.insert(visited.clone(), pressure);
}
for (hop, hop_cost) in &valves[&valve].links {
let new_cost = cost + hop_cost;
if new_cost >= TIME || visited.set.contains(hop) {
continue;
}
let new_pressure = pressure + (TIME - new_cost)*valves[hop].rate;
let mut new_visited = visited.clone();
new_visited.set.insert(hop.clone());
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
}
}
max_pressure
}
fn main() {
let input_fname = env::args().nth(1).expect("need input file");
let valves = read_input(&input_fname).expect("parse error");
let mut good_valves: HashMap<String, Valve> = HashMap::new();
for (name, valve) in &valves {
if valve.rate > 0 || name == "AA" {
good_valves.insert(name.clone(), routes_from(name, &valves));
}
}
print_map(&good_valves);
let pressure_map = get_pressure_map(&good_valves);
// print_map(&pressure_map);
println!("pressure_map.len(): {}", pressure_map.len());
let mut max_pressure = 0;
for (visited1, pressure1) in &pressure_map {
for (visited2, pressure2) in &pressure_map {
if visited1.set.is_disjoint(&visited2.set) {
max_pressure = max(max_pressure, pressure1 + pressure2);
}
}
}
println!(">> {} <<", max_pressure);
}

103
day16/src/main1.rs Normal file
View File

@@ -0,0 +1,103 @@
use std::env;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::collections::{HashMap, HashSet, VecDeque};
use std::cmp::max;
use std::str::FromStr;
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
let mut iter = str.chars().peekable();
let mut prefix = String::new();
while let Some(c) = iter.peek() {
if !c.to_string().parse::<T>().is_ok() {
break;
}
prefix.push(iter.next().unwrap());
}
Ok((prefix.parse::<T>()?, prefix.len()))
}
#[derive(Debug)]
struct Valve {
rate: u64,
links: Vec<(String, u64)>,
}
fn read_input(fname: &String) -> Result<HashMap<String, Valve>, <u64 as FromStr>::Err> {
let file = File::open(fname).expect("cannot open input file");
let lines = BufReader::new(file).lines();
let mut valves = HashMap::new();
for line in lines.flatten() {
let name = String::from(&line[6..=7]);
let (rate, rate_len) = parse_str::<u64>(&line[23..])?;
let links_str = &line[23 + rate_len + 24..];
let mut link = String::new();
let mut links = Vec::new();
let mut iter = links_str.chars();
loop {
match iter.next() {
Some(' ') | Some(',') => continue,
None => break,
Some(c) => {
link.push(c);
link.push(iter.next().unwrap());
links.push((link.clone(), 1));
link = String::new();
},
}
}
valves.insert(name, Valve { rate, links });
}
Ok(valves)
}
fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
let mut visited = HashSet::from([valve.clone()]);
let mut queue = VecDeque::from([(valve.clone(), 0)]);
let mut links = Vec::new();
while !queue.is_empty() {
let (current_valve, current_cost) = queue.pop_front().unwrap();
if current_valve != *valve && valves[&current_valve].rate > 0 {
// +1 because it takes 1min to open a valve
links.push((current_valve.clone(), current_cost + 1));
}
for (next_valve, _) in &valves[&current_valve].links {
if !visited.contains(next_valve) {
queue.push_back((next_valve.clone(), current_cost + 1));
visited.insert(next_valve.clone());
}
}
}
Valve { rate: valves[valve].rate, links: links }
}
fn main() {
let input_fname = env::args().nth(1).expect("need input file");
let valves = read_input(&input_fname).expect("parse error");
let mut good_valves = HashMap::new();
for (valve_name, valve) in &valves {
if valve.rate > 0 || valve_name == "AA" {
good_valves.insert(valve_name, routes_from(valve_name, &valves));
}
}
let mut max_pressure = 0;
let mut queue: VecDeque<(String, u64, u64, HashSet<_>)> = VecDeque::from([(
String::from("AA"), 0, 0, HashSet::from([String::from("AA")]))]);
while !queue.is_empty() {
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
max_pressure = max(max_pressure, pressure);
for (hop, hop_cost) in &good_valves[&valve].links {
if cost + hop_cost >= 30 || visited.contains(hop) {
continue;
}
let new_cost = cost + hop_cost;
let new_pressure = pressure + (30 - new_cost)*valves[hop].rate;
let mut new_visited = visited.clone();
new_visited.insert(hop.clone());
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
}
}
println!("Max pressure: {}", max_pressure);
}

10
day16/test.txt Normal file
View File

@@ -0,0 +1,10 @@
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II

7
day17/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day17"
version = "0.1.0"

6
day17/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "day17"
version = "0.1.0"
edition = "2021"
[dependencies]

1
day17/input.txt Normal file

File diff suppressed because one or more lines are too long

210
day17/src/main.rs Normal file
View File

@@ -0,0 +1,210 @@
use std::io;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::fmt::Debug;
#[derive(Debug)]
struct Shape {
bot: [i8; 4], // distance from datum. -1 for unused.
top: [i8; 4],
left: [i8; 4],
right: [i8; 4],
width: usize,
height: usize,
}
// a Shape's datum is its bottom left corner
#[derive(Debug)]
struct Pos {y: usize, x: usize}
//static SHAPE_NAMES: [char; 5] = ['-', '+', 'L', '|', '.'];
static SHAPES: [Shape; 5] = [
Shape { // -
bot: [0, 0, 0, 0], top: [0, 0, 0, 0],
left: [0, -1, -1, -1], right: [3, -1, -1, -1],
width: 4, height: 1,
},
Shape { // +
bot: [1, 0, 1, -1], top: [1, 2, 1, -1],
left: [1, 0, 1, -1], right: [1, 2, 1, -1],
width: 3, height: 3,
},
Shape { // backward L
bot: [0, 0, 0, -1], top: [0, 0, 2, -1],
left: [0, 2, 2, -1], right: [2, 2, 2, -1],
width: 3, height: 3,
},
Shape { // |
bot: [0, -1, -1, -1], top: [0, -1, -1, -1],
left: [0, 0, 0, 0], right: [0, 0, 0, 0],
width: 1, height: 4,
},
Shape { // square
bot: [0, 0, -1, -1], top: [1, 1, -1, -1],
left: [0, 0, -1, -1], right: [1, 1, -1, -1],
width: 2, height: 2,
},
];
fn iterate(
map: &mut Vec<[u8; 7]>, shape: &Shape, pos: &mut Pos, wind: u8
) -> bool {
//println!(" __ {}, start {:?}", wind as char, pos);
// Wind move
match wind {
b'>' => 'rightmove: {
if pos.x + shape.width == 7 { break 'rightmove; }
let mut i = 0;
while i < 4 && shape.right[i] >= 0 {
let right_point = pos.x + shape.right[i] as usize;
if right_point + 1 == 7 { break 'rightmove; }
if map[pos.y + i][right_point + 1] != 0 { break 'rightmove; }
i += 1;
}
pos.x += 1;
//println!(" >> {:?}", pos);
},
b'<' => 'leftmove: {
if pos.x == 0 { break 'leftmove; }
let mut i = 0;
while i < 4 && shape.left[i] >= 0 {
let left_point = pos.x + shape.left[i] as usize;
if left_point == 0 { break 'leftmove; }
if map[pos.y + i][left_point - 1] != 0 { break 'leftmove; }
i += 1;
}
pos.x -= 1;
//println!(" << {:?}", pos);
},
_ => panic!(),
}
// Gravity move
'downmove: {
let mut i = 0;
while i < 4 && shape.bot[i] >= 0 {
let bot_point = pos.y + shape.bot[i] as usize;
if bot_point == 0 { break 'downmove; }
if map[bot_point - 1][pos.x + i] != 0 { break 'downmove; }
i += 1;
}
pos.y -= 1;
//println!(" vv {:?}", pos);
return false;
}
// Settling
let mut i = 0;
while i < 4 && shape.left[i] >= 0 && shape.right[i] >= 0 {
map[pos.y + i][pos.x + shape.left[i] as usize] = 1;
map[pos.y + i][pos.x + shape.right[i] as usize] = 1;
i += 1;
}
i = 0;
while i < 4 && shape.top[i] >= 0 && shape.bot[i] >= 0 {
map[pos.y + shape.top[i] as usize][pos.x + i] = 1;
map[pos.y + shape.bot[i] as usize][pos.x + i] = 1;
i += 1;
}
return true;
}
fn main() -> io::Result<()> {
let input_fname = env::args().nth(1).expect("need input file");
let limit = env::args().nth(2).expect("need limit").parse::<usize>().unwrap();
let mut winds: Vec<u8> = Vec::new();
let _ = BufReader::new(File::open(input_fname)?).read_until(b'\n', &mut winds);
if winds.last() == Some(&b'\n') { winds.pop(); }
println!("winds = {}, shapes = {}", winds.len(), SHAPES.len());
let mut shape_id = 0;
let mut shape = &SHAPES[shape_id];
let mut current_top = 0;
let mut shape_pos = Pos{x: 2, y: 3};
let mut map: Vec<[u8; 7]> = vec![
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
];
let mut answers: Vec<(usize, usize)> = Vec::new();
let mut i = 0;
'mainloop: while answers.len() < limit {
let c = winds[i % winds.len()];
if iterate(&mut map, shape, &mut shape_pos, c) {
let last_shape_top = shape_pos.y + shape.height - 1;
if last_shape_top > current_top {
current_top = last_shape_top;
}
shape_id = (shape_id + 1) % SHAPES.len(); // next shape
shape = &SHAPES[shape_id];
for _ in map.len()..(current_top + 4 + shape.height) {
map.push([0, 0, 0, 0, 0, 0, 0]);
}
shape_pos = Pos{x:2, y: current_top + 4};
answers.push((i, current_top));
let last_rock = answers.len() - 1;
print!(
"rock {} - (i {}, top {})",
last_rock, i, current_top
);
if last_rock >= 2*SHAPES.len() {
let mut j = last_rock - SHAPES.len();
'lookback: while j > (last_rock / 2) {
let (hist_i, hist_top) = answers[j];
let next_j = 2*j - last_rock;
let (hist2_i, hist2_top) = answers[next_j];
if (i - hist_i) % winds.len() == 0
&& (i - hist_i) == (hist_i - hist2_i)
&& (current_top - hist_top) == (hist_top - hist2_top) {
print!(
" {}-{}-{}-({}-{}-{})",
j, hist_i, hist_top,
next_j, hist2_i, hist2_top,
);
print!(
" rock cycle {}, off {} | \
top cycle {} off {} ",
last_rock - j, next_j,
current_top - hist_top, hist2_top,
);
if (limit - 1 - next_j) % (last_rock - j) == 0 {
let n_cycles = (limit - 1 - next_j) / (last_rock - j);
println!(
"\nheight = {}",
hist2_top + n_cycles*(current_top - hist_top) + 1
);
break 'mainloop;
} else {
break 'lookback;
}
}
j -= SHAPES.len();
}
}
println!();
//prettyprint(&map, &shape_pos, SHAPE_NAMES[shape_id]);
}
i += 1;
}
Ok(())
}
fn prettyprint(map: &Vec<[u8; 7]>, pos: &Pos, shape_name: char) {
let mut i = map.len();
for row in map.into_iter().rev() {
i -= 1;
print!("|");
for j in 0..7 {
print!("{}", if row[j] == 0 { "." } else { "#" });
}
println!("| {} {}", i, if i == pos.y {shape_name} else {' '});
}
}

168
day17/src/main1.rs Normal file
View File

@@ -0,0 +1,168 @@
use std::io;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::fmt::Debug;
#[derive(Debug)]
struct Shape {
bot: [i8; 4], // distance from datum. -1 for unused.
top: [i8; 4],
left: [i8; 4],
right: [i8; 4],
width: usize,
height: usize,
}
// a Shape's datum is its bottom left corner
#[derive(Debug)]
struct Pos {y: usize, x: usize}
static SHAPE_NAMES: [char; 5] = ['-', '+', 'L', '|', '.'];
static SHAPES: [Shape; 5] = [
Shape { // -
bot: [0, 0, 0, 0], top: [0, 0, 0, 0],
left: [0, -1, -1, -1], right: [3, -1, -1, -1],
width: 4, height: 1,
},
Shape { // +
bot: [1, 0, 1, -1], top: [1, 2, 1, -1],
left: [1, 0, 1, -1], right: [1, 2, 1, -1],
width: 3, height: 3,
},
Shape { // backward L
bot: [0, 0, 0, -1], top: [0, 0, 2, -1],
left: [0, 2, 2, -1], right: [2, 2, 2, -1],
width: 3, height: 3,
},
Shape { // |
bot: [0, -1, -1, -1], top: [0, -1, -1, -1],
left: [0, 0, 0, 0], right: [0, 0, 0, 0],
width: 1, height: 4,
},
Shape { // square
bot: [0, 0, -1, -1], top: [1, 1, -1, -1],
left: [0, 0, -1, -1], right: [1, 1, -1, -1],
width: 2, height: 2,
},
];
fn iterate(
map: &mut Vec<[u8; 7]>, shape: &Shape, pos: &mut Pos, wind: u8
) -> bool {
//println!(" __ {}, start {:?}", wind as char, pos);
// Wind move
match wind {
b'>' => 'rightmove: {
if pos.x + shape.width == 7 { break 'rightmove; }
let mut i = 0;
while i < 4 && shape.right[i] >= 0 {
let right_point = pos.x + shape.right[i] as usize;
if right_point + 1 == 7 { break 'rightmove; }
if map[pos.y + i][right_point + 1] != 0 { break 'rightmove; }
i += 1;
}
pos.x += 1;
//println!(" >> {:?}", pos);
},
b'<' => 'leftmove: {
if pos.x == 0 { break 'leftmove; }
let mut i = 0;
while i < 4 && shape.left[i] >= 0 {
let left_point = pos.x + shape.left[i] as usize;
if left_point == 0 { break 'leftmove; }
if map[pos.y + i][left_point - 1] != 0 { break 'leftmove; }
i += 1;
}
pos.x -= 1;
//println!(" << {:?}", pos);
},
_ => panic!(),
}
// Gravity move
'downmove: {
let mut i = 0;
while i < 4 && shape.bot[i] >= 0 {
let bot_point = pos.y + shape.bot[i] as usize;
if bot_point == 0 { break 'downmove; }
if map[bot_point - 1][pos.x + i] != 0 { break 'downmove; }
i += 1;
}
pos.y -= 1;
//println!(" vv {:?}", pos);
return false;
}
// Settling
let mut i = 0;
while i < 4 && shape.left[i] >= 0 && shape.right[i] >= 0 {
map[pos.y + i][pos.x + shape.left[i] as usize] = 1;
map[pos.y + i][pos.x + shape.right[i] as usize] = 1;
i += 1;
}
i = 0;
while i < 4 && shape.top[i] >= 0 && shape.bot[i] >= 0 {
map[pos.y + shape.top[i] as usize][pos.x + i] = 1;
map[pos.y + shape.bot[i] as usize][pos.x + i] = 1;
i += 1;
}
return true;
}
fn main() -> io::Result<()> {
let input_fname = env::args().nth(1).expect("need input file");
let mut winds: Vec<u8> = Vec::new();
let _ = BufReader::new(File::open(input_fname)?).read_until(b'\n', &mut winds);
if winds.last() == Some(&b'\n') { winds.pop(); }
let mut shape_id = 0;
let mut shape = &SHAPES[shape_id];
let mut current_top = 0;
let mut shape_pos = Pos{x: 2, y: 3};
let mut map: Vec<[u8; 7]> = vec![
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
];
prettyprint(&map, &shape_pos, SHAPE_NAMES[shape_id]);
let mut nrocks = 0;
let mut i = 0;
while nrocks < 2022 { //debug
let c = winds[i % winds.len()];
i += 1;
if iterate(&mut map, shape, &mut shape_pos, c) {
let last_shape_top = shape_pos.y + shape.height - 1;
if last_shape_top > current_top {
current_top = last_shape_top;
}
shape_id = (shape_id + 1) % SHAPES.len(); // next shape
shape = &SHAPES[shape_id];
//println!("{} -> {}", map.len(), last_shape_top + 4 + shape.height);
for _ in map.len()..(current_top + 4 + shape.height) {
map.push([0, 0, 0, 0, 0, 0, 0]);
}
nrocks += 1;
shape_pos = Pos{x:2, y: current_top + 4};
//println!("= {} ({})", current_top, nrocks);
prettyprint(&map, &shape_pos, SHAPE_NAMES[shape_id]);
}
}
println!("height = {}", current_top + 1);
Ok(())
}
fn prettyprint(map: &Vec<[u8; 7]>, pos: &Pos, shape_name: char) {
// let mut i = map.len();
// for row in map.into_iter().rev() {
// i -= 1;
// print!("|");
// for j in 0..7 {
// print!("{}", if row[j] == 0 { "." } else { "#" });
// }
// println!("| {} {}", i, if i == pos.y {shape_name} else {' '});
// }
}

1
day17/test.txt Normal file
View File

@@ -0,0 +1 @@
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>

7
day18/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day17"
version = "0.1.0"

6
day18/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "day17"
version = "0.1.0"
edition = "2021"
[dependencies]

2085
day18/input.txt Normal file

File diff suppressed because it is too large Load Diff

93
day18/src/main.array3d.rs Normal file
View File

@@ -0,0 +1,93 @@
use std::io;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashSet;
use std::collections::VecDeque;
mod rustsux {
use std::fmt;
pub struct Array3D<T: Copy> {
backing_vec: Vec<T>,
pub d1: usize, pub d2: usize, pub d3: usize,
}
impl<T: Copy> Array3D<T> {
pub fn new(d1: usize, d2: usize, d3: usize, init: T) -> Array3D<T> {
Array3D {
backing_vec: vec![init; d1 * d2 * d3],
d1: d1, d2: d2, d3: d3,
}
}
pub fn get(&self, x: usize, y: usize, z: usize) -> T {
self.backing_vec[x*self.d2*self.d3 + y*self.d3 + z]
}
pub fn set(&mut self, x: usize, y: usize, z: usize, val: T) {
self.backing_vec[x*self.d2*self.d3 + y*self.d3 + z] = val;
}
}
impl<T: fmt::Display + Copy> fmt::Debug for Array3D<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for x in 0..self.d1 {
write!(f, "")?;
for y in 0..self.d2 {
let row_start = x*self.d2*self.d3 + y*self.d3;
let row_end = x*self.d2*self.d3 + (y + 1)*self.d3;
for z in row_start..row_end {
write!(f, "{}", self.backing_vec[z])?;
}
write!(f, " ")?;
}
writeln!(f, "")?;
}
Ok(())
}
}
}
fn floodfill_surface<T: Copy>(map: rustsux::Array3D<T>, block_sym: T) -> usize {
// TODO: start from arbitrary spot instead of 0, 0, 0
let mut queue = VecDeque::new();
queue.push_back((0, 0, 0));
while let Some((x, y, z)) = queue.pop_front() {
println!("{} {} {}", x, y, z);
}
0
}
fn main() -> io::Result<()> {
let input_fname = env::args().nth(1).expect("need input file");
let lines = BufReader::new(File::open(input_fname)?).lines();
let mut cubes: HashSet<(usize, usize, usize)> = HashSet::new();
let (mut max_x, mut max_y, mut max_z) = (0, 0, 0);
for line in lines.flatten() {
let mut split = line.split(',');
// +1 so that we have a guard plane at 0 index
let x = 1 + split.next().unwrap().to_string().parse::<usize>().unwrap();
let y = 1 + split.next().unwrap().to_string().parse::<usize>().unwrap();
let z = 1 + split.next().unwrap().to_string().parse::<usize>().unwrap();
cubes.insert((x, y, z));
max_x = if x > max_x {x} else {max_x};
max_y = if y > max_y {y} else {max_y};
max_z = if z > max_z {z} else {max_z};
}
let mut map = rustsux::Array3D::new(max_x + 1, max_y + 1, max_z + 1, '.');
for (x, y, z) in &cubes {
map.set(*x, *y, *z, '#');
}
println!("{} {} {}", max_x, max_y, max_z);
println!("{:?}", map);
floodfill_surface(map, '#');
Ok(())
}

63
day18/src/main.rs Normal file
View File

@@ -0,0 +1,63 @@
use std::io;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashSet;
use std::collections::VecDeque;
type Map = HashSet<(i8, i8, i8)>;
fn floodfill(cubes: Map, max_x: i8, max_y: i8, max_z: i8) -> usize {
let mut visited: Map = HashSet::new();
let mut surfaces = 0;
let mut queue = VecDeque::new();
queue.push_back((0, 0, 0));
println!("cubes = {:?}", cubes);
println!("maxes = {} {} {}", max_x, max_y, max_z);
while let Some((x, y, z)) = queue.pop_front() {
visited.insert((x, y, z));
let all_neighbors = HashSet::from([
(x + 1, y, z), (x - 1, y, z),
(x, y + 1, z), (x, y - 1, z),
(x, y, z + 1), (x, y, z - 1)
]);
surfaces += all_neighbors.intersection(&cubes).count();
all_neighbors.difference(&cubes)
.filter(|&(x, y, z)|
*x >= 0 && *x <= max_x &&
*y >= 0 && *y <= max_y &&
*z >= 0 && *z <= max_z)
.filter(|&cube| !visited.contains(cube))
.for_each(|&cube|
if !queue.contains(&cube) {queue.push_back(cube)});
}
surfaces
}
fn main() -> io::Result<()> {
let input_fname = env::args().nth(1).expect("need input file");
let lines = BufReader::new(File::open(input_fname)?).lines();
let mut cubes: Map = HashSet::new();
let (mut max_x, mut max_y, mut max_z) = (0, 0, 0);
for line in lines.flatten() {
let mut split = line.split(',');
// +1 so we have 3 guard planes at 0
let x = 1 + split.next().unwrap().to_string().parse::<i8>().unwrap();
let y = 1 + split.next().unwrap().to_string().parse::<i8>().unwrap();
let z = 1 + split.next().unwrap().to_string().parse::<i8>().unwrap();
cubes.insert((x, y, z));
max_x = if x > max_x {x} else {max_x};
max_y = if y > max_y {y} else {max_y};
max_z = if z > max_z {z} else {max_z};
}
let surfaces = floodfill(cubes, max_x + 1, max_y + 1, max_z + 1);
println!("answer = {}", surfaces);
Ok(())
}

34
day18/src/main1.rs Normal file
View File

@@ -0,0 +1,34 @@
use std::io;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashSet;
fn main() -> io::Result<()> {
let input_fname = env::args().nth(1).expect("need input file");
let lines = BufReader::new(File::open(input_fname)?).lines();
let mut cubes: HashSet<(i8, i8, i8)> = HashSet::new();
for line in lines.flatten() {
let mut split = line.split(',');
let x = split.next().unwrap().to_string().parse::<i8>().unwrap();
let y = split.next().unwrap().to_string().parse::<i8>().unwrap();
let z = split.next().unwrap().to_string().parse::<i8>().unwrap();
cubes.insert((x, y, z));
}
let mut all_neighbors = 0;
for (x, y, z) in &cubes {
let neighbors = HashSet::from([
(*x + 1, *y, *z), (*x - 1, *y, *z),
(*x, *y + 1, *z), (*x, *y - 1, *z),
(*x, *y, *z + 1), (*x, *y, *z - 1)
]);
all_neighbors += cubes.intersection(&neighbors).count();
}
println!("{}", cubes.len() * 6 - all_neighbors);
Ok(())
}

13
day18/test.txt Normal file
View File

@@ -0,0 +1,13 @@
2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5