This commit is contained in:
JonOfUs 2022-12-20 17:35:25 +01:00
parent 69a51e6299
commit c9808224ec
7 changed files with 5254 additions and 113 deletions

5000
res/20/input.txt Normal file

File diff suppressed because it is too large Load diff

7
res/20/test-input.txt Normal file
View file

@ -0,0 +1,7 @@
1
2
-3
3
-2
0
4

View file

@ -9,12 +9,12 @@ pub fn solve() {
let contents = fs::read_to_string(path).expect("I/O error, wrong path?"); let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
// constant definition of rocks, from bottom to top // constant definition of rocks, from bottom to top
let rocks: Vec<Vec<(u8,u8)>> = vec![ let rocks: Vec<Vec<(u8, u8)>> = vec![
vec![(0,0),(0,1),(0,2),(0,3)], vec![(0, 0), (0, 1), (0, 2), (0, 3)],
vec![(0,1),(1,0),(1,1),(1,2),(2,1)], vec![(0, 1), (1, 0), (1, 1), (1, 2), (2, 1)],
vec![(0,0),(0,1),(0,2),(1,2),(2,2)], vec![(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)],
vec![(0,0),(1,0),(2,0),(3,0)], vec![(0, 0), (1, 0), (2, 0), (3, 0)],
vec![(0,0),(0,1),(1,0),(1,1)] vec![(0, 0), (0, 1), (1, 0), (1, 1)],
]; ];
let directions: Vec<Dir> = contents let directions: Vec<Dir> = contents
@ -28,7 +28,7 @@ pub fn solve() {
.collect(); .collect();
// [height][width] // [height][width]
let mut chamber = vec![vec![false;WIDTH];4]; let mut chamber = vec![vec![false; WIDTH]; 4];
let mut highest_rock = -1; // floor let mut highest_rock = -1; // floor
@ -36,34 +36,30 @@ pub fn solve() {
let mut heights = Vec::<i64>::new(); let mut heights = Vec::<i64>::new();
/* /*
51 rocks 51 rocks
heights[50] - heights[15] heights[50] - heights[15]
(1_000_000_000_000 - 16) = 999_999_999_984 (1_000_000_000_000 - 16) = 999_999_999_984
% %
*/ */
for i in 0..2344 { for i in 0..2344 {
// spawn new rock // spawn new rock
let r_index = i as usize % rocks.len(); // get current rock index let r_index = i as usize % rocks.len(); // get current rock index
let mut rock = Rock::new(&rocks[r_index], highest_rock); let mut rock = Rock::new(&rocks[r_index], highest_rock);
while chamber.iter().filter(|row| !row.contains(&true)).count() < 7 { while chamber.iter().filter(|row| !row.contains(&true)).count() < 7 {
chamber.push(vec![false;WIDTH]) chamber.push(vec![false; WIDTH])
} }
loop { loop {
// move to left or right // move to left or right
let next_dir = dir_iter.next(); let next_dir = dir_iter.next();
let dir = match next_dir { let dir = match next_dir {
Some(x) => { x }, Some(x) => x,
None => { None => {
dir_iter = directions.iter(); dir_iter = directions.iter();
dir_iter.next().unwrap() dir_iter.next().unwrap()
@ -75,7 +71,7 @@ pub fn solve() {
if rock.left().valid_pos(&chamber) { if rock.left().valid_pos(&chamber) {
rock = rock.left() rock = rock.left()
} }
}, }
Dir::Right => { Dir::Right => {
if rock.right().valid_pos(&chamber) { if rock.right().valid_pos(&chamber) {
rock = rock.right() rock = rock.right()
@ -86,17 +82,18 @@ pub fn solve() {
if rock.down().valid_pos(&chamber) { if rock.down().valid_pos(&chamber) {
rock = rock.down(); rock = rock.down();
} else { } else {
rock.pos.iter().for_each(|coord| { rock.pos
chamber[coord.0 as usize][coord.1 as usize] = true .iter()
}); .for_each(|coord| chamber[coord.0 as usize][coord.1 as usize] = true);
highest_rock = match chamber highest_rock = match chamber
.iter() .iter()
.enumerate() .enumerate()
.filter(|row| row.1.contains(&true)) .filter(|row| row.1.contains(&true))
.last() { .last()
Some(x) => x.0 as i64, {
None => -1 Some(x) => x.0 as i64,
}; None => -1,
};
// find recurring patterns in amount of rocks and height // find recurring patterns in amount of rocks and height
heights.push(highest_rock); heights.push(highest_rock);
//for i in 2..heights.len() { //for i in 2..heights.len() {
@ -106,27 +103,38 @@ pub fn solve() {
} }
} }
} }
println!("Result 1: {}", highest_rock+1); println!("Result 1: {}", highest_rock + 1);
} }
fn _test(n: usize, heights: &Vec<i64>) { fn _test(n: usize, heights: &Vec<i64>) {
if heights.len() % n == 0 if heights.len() % n == 0
&& heights[heights.len()/n-1]*n as i64+n as i64 == heights[heights.len()-1]+1 { && heights[heights.len() / n - 1] * n as i64 + n as i64 == heights[heights.len() - 1] + 1
println!("{}: {}", n, heights.len()/n) {
println!("{}: {}", n, heights.len() / n)
} }
} }
fn _print_chamber(chamber: &Vec<Vec<bool>>, curr_rock: &Rock) { fn _print_chamber(chamber: &Vec<Vec<bool>>, curr_rock: &Rock) {
let mut str_chamber: Vec<Vec<char>> = chamber.iter().map(|line| line.iter().map(|elem| let mut str_chamber: Vec<Vec<char>> = chamber
match *elem { .iter()
true => '#', .map(|line| {
false => '.' line.iter()
} .map(|elem| match *elem {
).collect()).collect(); true => '#',
false => '.',
})
.collect()
})
.collect();
curr_rock.pos.iter().for_each(|pos| { str_chamber[pos.0 as usize][pos.1 as usize] = '@'; }); curr_rock.pos.iter().for_each(|pos| {
str_chamber[pos.0 as usize][pos.1 as usize] = '@';
});
str_chamber.iter().rev().for_each(|str| println!("{}",str.iter().collect::<String>())) str_chamber
.iter()
.rev()
.for_each(|str| println!("{}", str.iter().collect::<String>()))
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -137,15 +145,18 @@ enum Dir {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Rock { struct Rock {
pos: Vec<(i64,i64)> pos: Vec<(i64, i64)>,
} }
impl Rock { impl Rock {
pub fn new(rock: &Vec<(u8,u8)>, highest_rock: i64) -> Self{ pub fn new(rock: &Vec<(u8, u8)>, highest_rock: i64) -> Self {
let pos: Vec<(i64,i64)> = rock let pos: Vec<(i64, i64)> = rock
.iter() .iter()
.map(|coord| { .map(|coord| {
(coord.0 as i64 + (highest_rock + 4) as i64, coord.1 as i64 + 2) (
coord.0 as i64 + (highest_rock + 4) as i64,
coord.1 as i64 + 2,
)
}) })
.collect(); .collect();
Rock { pos } Rock { pos }
@ -153,48 +164,60 @@ impl Rock {
pub fn right(&self) -> Self { pub fn right(&self) -> Self {
for coord in self.pos.iter() { for coord in self.pos.iter() {
if coord.1 >= (WIDTH-1) as i64 { if coord.1 >= (WIDTH - 1) as i64 {
return self.clone() return self.clone();
} }
} }
Rock { Rock {
pos: self.pos.iter().map(|coord| { pos: self
(coord.0, coord.1 + 1) // move right, only check for wall ! .pos
}).collect() .iter()
.map(|coord| {
(coord.0, coord.1 + 1) // move right, only check for wall !
})
.collect(),
} }
} }
pub fn left(&self) -> Self { pub fn left(&self) -> Self {
for coord in self.pos.iter() { for coord in self.pos.iter() {
if coord.1 <= 0 { if coord.1 <= 0 {
return self.clone() return self.clone();
} }
} }
Rock { Rock {
pos: self.pos.iter().map(|coord| { pos: self
(coord.0, coord.1 - 1) // move left, only check for wall ! .pos
}).collect() .iter()
.map(|coord| {
(coord.0, coord.1 - 1) // move left, only check for wall !
})
.collect(),
} }
} }
pub fn down(&self) -> Self { pub fn down(&self) -> Self {
Rock { Rock {
pos: self.pos.iter().map(|coord| { pos: self
(coord.0 - 1, coord.1) // move down .pos
}).collect() .iter()
.map(|coord| {
(coord.0 - 1, coord.1) // move down
})
.collect(),
} }
} }
pub fn valid_pos(&self, chamber: &Vec<Vec<bool>>) -> bool { pub fn valid_pos(&self, chamber: &Vec<Vec<bool>>) -> bool {
for coord in &self.pos { for coord in &self.pos {
if coord.0 < 0 || coord.1 < 0 { if coord.0 < 0 || coord.1 < 0 {
return false return false;
} }
if chamber[coord.0 as usize][coord.1 as usize] { if chamber[coord.0 as usize][coord.1 as usize] {
return false return false;
} }
} }
true true
} }
} }

View file

@ -1,11 +1,14 @@
use std::{fs, collections::{HashMap, HashSet, VecDeque}}; use std::{
collections::{HashMap, HashSet, VecDeque},
fs,
};
pub fn solve() { pub fn solve() {
let path = "res/18/input.txt"; let path = "res/18/input.txt";
let contents = fs::read_to_string(path).expect("I/O error, wrong path?"); let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
let coords: Vec<(usize,usize,usize)> = contents let coords: Vec<(usize, usize, usize)> = contents
.lines() .lines()
.filter(|line| *line != "") .filter(|line| *line != "")
.map(|line| { .map(|line| {
@ -13,25 +16,21 @@ pub fn solve() {
( (
vals[0].parse::<usize>().unwrap(), vals[0].parse::<usize>().unwrap(),
vals[1].parse::<usize>().unwrap(), vals[1].parse::<usize>().unwrap(),
vals[2].parse::<usize>().unwrap() vals[2].parse::<usize>().unwrap(),
) )
}) })
.collect(); .collect();
let max: usize = coords let max: usize = coords
.iter() .iter()
.map(|coord| .map(|coord| coord.0.max(coord.1.max(coord.2)))
coord.0.max(
coord.1.max(coord.2)
)
)
.max() .max()
.unwrap(); .unwrap();
let world_size = max as usize + 2; let world_size = max as usize + 2;
// [x][y][z] // [x][y][z]
let mut world = vec![vec![vec![false;world_size];world_size];world_size]; let mut world = vec![vec![vec![false; world_size]; world_size]; world_size];
for coord in coords.iter() { for coord in coords.iter() {
world[coord.0 as usize][coord.1 as usize][coord.2 as usize] = true world[coord.0 as usize][coord.1 as usize][coord.2 as usize] = true
@ -40,46 +39,52 @@ pub fn solve() {
// task 1 - count surfaces // task 1 - count surfaces
let mut surfaces: u32 = 0; let mut surfaces: u32 = 0;
let mut surface_blocks = HashMap::<(usize,usize,usize), usize>::new(); let mut surface_blocks = HashMap::<(usize, usize, usize), usize>::new();
for (x1,y1,z1) in coords.iter() { for (x1, y1, z1) in coords.iter() {
let (x,y,z) = (*x1 as usize, *y1 as usize, *z1 as usize); let (x, y, z) = (*x1 as usize, *y1 as usize, *z1 as usize);
// x-1 // x-1
if x == 0 || !world[x-1][y][z] { if x == 0 || !world[x - 1][y][z] {
surfaces += 1; surfaces += 1;
if x != 0 { insert_or_increase((x-1,y,z), &mut surface_blocks) } if x != 0 {
insert_or_increase((x - 1, y, z), &mut surface_blocks)
}
} }
// x+1 // x+1
if !world[x+1][y][z] { if !world[x + 1][y][z] {
surfaces += 1; surfaces += 1;
insert_or_increase((x+1,y,z), &mut surface_blocks) insert_or_increase((x + 1, y, z), &mut surface_blocks)
} }
// y-1 // y-1
if y == 0 || !world[x][y-1][z] { if y == 0 || !world[x][y - 1][z] {
surfaces += 1; surfaces += 1;
if y != 0 { insert_or_increase((x,y-1,z), &mut surface_blocks) } if y != 0 {
insert_or_increase((x, y - 1, z), &mut surface_blocks)
}
} }
// y+1 // y+1
if !world[x][y+1][z] { if !world[x][y + 1][z] {
surfaces += 1; surfaces += 1;
insert_or_increase((x,y+1,z), &mut surface_blocks) insert_or_increase((x, y + 1, z), &mut surface_blocks)
} }
// z-1 // z-1
if z == 0 || !world[x][y][z-1] { if z == 0 || !world[x][y][z - 1] {
surfaces += 1; surfaces += 1;
if z != 0 { insert_or_increase((x,y,z-1), &mut surface_blocks) } if z != 0 {
insert_or_increase((x, y, z - 1), &mut surface_blocks)
}
} }
// z+1 // z+1
if !world[x][y][z+1] { if !world[x][y][z + 1] {
surfaces += 1; surfaces += 1;
insert_or_increase((x,y,z+1), &mut surface_blocks) insert_or_increase((x, y, z + 1), &mut surface_blocks)
} }
} }
println!("Result 1: {surfaces}"); println!("Result 1: {surfaces}");
// task 2 - find air bubbles by checking reachability between each surface block and a reference block outside with bfs // task 2 - find air bubbles by checking reachability between each surface block and a reference block outside with bfs
let reference_block: (usize, usize, usize) = (world_size-1, world_size-1, world_size-1); let reference_block: (usize, usize, usize) = (world_size - 1, world_size - 1, world_size - 1);
for (block, block_surfaces) in surface_blocks.iter() { for (block, block_surfaces) in surface_blocks.iter() {
if !bfs_reachable(*block, reference_block, &world) { if !bfs_reachable(*block, reference_block, &world) {
surfaces -= *block_surfaces as u32 surfaces -= *block_surfaces as u32
@ -87,10 +92,9 @@ pub fn solve() {
} }
println!("Result 2: {surfaces}"); println!("Result 2: {surfaces}");
} }
fn insert_or_increase(p: (usize,usize,usize), map: &mut HashMap::<(usize,usize,usize), usize>) { fn insert_or_increase(p: (usize, usize, usize), map: &mut HashMap<(usize, usize, usize), usize>) {
if map.contains_key(&p) { if map.contains_key(&p) {
*map.get_mut(&p).unwrap() += 1; *map.get_mut(&p).unwrap() += 1;
} else { } else {
@ -98,7 +102,11 @@ fn insert_or_increase(p: (usize,usize,usize), map: &mut HashMap::<(usize,usize,u
} }
} }
fn bfs_reachable(s: (usize, usize, usize), e: (usize, usize, usize), world: &Vec<Vec<Vec<bool>>>) -> bool { fn bfs_reachable(
s: (usize, usize, usize),
e: (usize, usize, usize),
world: &Vec<Vec<Vec<bool>>>,
) -> bool {
let mut queue = VecDeque::<(usize, usize, usize)>::new(); let mut queue = VecDeque::<(usize, usize, usize)>::new();
let mut seen_nodes = HashSet::<(usize, usize, usize)>::new(); let mut seen_nodes = HashSet::<(usize, usize, usize)>::new();
@ -121,33 +129,36 @@ fn bfs_reachable(s: (usize, usize, usize), e: (usize, usize, usize), world: &Vec
false false
} }
fn get_adjacents(p: (usize, usize, usize), world: &Vec<Vec<Vec<bool>>>) -> Vec<(usize,usize,usize)> { fn get_adjacents(
let mut adj = Vec::<(usize,usize,usize)>::new(); p: (usize, usize, usize),
let (x,y,z) = p; world: &Vec<Vec<Vec<bool>>>,
) -> Vec<(usize, usize, usize)> {
if x > 0 && !world[x-1][y][z] { let mut adj = Vec::<(usize, usize, usize)>::new();
adj.push((x-1,y,z)) let (x, y, z) = p;
if x > 0 && !world[x - 1][y][z] {
adj.push((x - 1, y, z))
} }
// x+1 // x+1
if x < world.len()-1 && !world[x+1][y][z] { if x < world.len() - 1 && !world[x + 1][y][z] {
adj.push((x+1,y,z)) adj.push((x + 1, y, z))
} }
// y-1 // y-1
if y > 0 && !world[x][y-1][z] { if y > 0 && !world[x][y - 1][z] {
adj.push((x,y-1,z)) adj.push((x, y - 1, z))
} }
// y+1 // y+1
if y < world.len()-1 && !world[x][y+1][z] { if y < world.len() - 1 && !world[x][y + 1][z] {
adj.push((x,y+1,z)) adj.push((x, y + 1, z))
} }
// z-1 // z-1
if z > 0 && !world[x][y][z-1] { if z > 0 && !world[x][y][z - 1] {
adj.push((x,y,z-1)) adj.push((x, y, z - 1))
} }
// z+1 // z+1
if z < world.len()-1 && !world[x][y][z+1] { if z < world.len() - 1 && !world[x][y][z + 1] {
adj.push((x,y,z+1)) adj.push((x, y, z + 1))
} }
adj adj
} }

View file

@ -1,16 +1,17 @@
use std::{fs, collections::{HashMap, HashSet, VecDeque}}; use std::fs;
use scan_fmt::scan_fmt; use scan_fmt::scan_fmt;
#[allow(dead_code)]
const MINUTES: u32 = 24; const MINUTES: u32 = 24;
#[allow(dead_code)]
pub fn solve() { pub fn solve() {
let path = "res/19/input.txt"; let path = "res/19/input.txt";
let contents = fs::read_to_string(path).expect("I/O error, wrong path?"); let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
// parse blueprints // parse blueprints
let blueprints: Vec<Blueprint> = contents let _blueprints: Vec<Blueprint> = contents
.lines() .lines()
.filter(|line| *line != "") .filter(|line| *line != "")
.map(|line| { .map(|line| {
@ -30,26 +31,23 @@ pub fn solve() {
}) })
.collect(); .collect();
} }
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
struct Blueprint { struct Blueprint {
id: u32, id: u32,
ore_bot: u32, ore_bot: u32,
clay_bot: u32, clay_bot: u32,
obsidian_bot: (u32, u32), // (ore, clay) obsidian_bot: (u32, u32), // (ore, clay)
geode_bot: (u32, u32), // (ore, obsidian) geode_bot: (u32, u32), // (ore, obsidian)
} }
#[allow(dead_code)]
impl Blueprint { impl Blueprint {
pub fn quality_level(&self) -> u32 { pub fn quality_level(&self) -> u32 {
// TODO dynamic programming? // TODO dynamic programming?
return self.id * 1; // TODO largest number of geodes that can be opened return self.id * 1; // TODO largest number of geodes that can be opened
} }
} }

102
src/days/d20.rs Normal file
View file

@ -0,0 +1,102 @@
use std::fs;
const DECRYPTION_KEY: i64 = 811_589_153;
pub fn solve() {
let path = "res/20/input.txt";
let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
let initial_arrangement: Vec<i64> = contents
.lines()
.filter(|line| *line != "")
.map(|line| line.parse::<i64>().unwrap())
.collect();
let size = initial_arrangement.len();
// list of indices
let mut work_arrangement: Vec<usize> = initial_arrangement
.iter()
.enumerate()
.map(|(i, _)| i)
.collect();
for (i, &n) in initial_arrangement.iter().enumerate() {
// position in current state
let work_i = work_arrangement.iter().position(|&elem| elem == i).unwrap();
mv(work_i, n, &mut work_arrangement);
//println!("{}\n", work_arrangement.iter().map(|i| initial_arrangement[*i].to_string()).collect::<Vec::<String>>().join(", "));
}
let offset = work_arrangement
.iter()
.position(|i| initial_arrangement[*i] == 0)
.unwrap();
let coord_1 = initial_arrangement[work_arrangement[(1000 + offset) % size]];
let coord_2 = initial_arrangement[work_arrangement[(2000 + offset) % size]];
let coord_3 = initial_arrangement[work_arrangement[(3000 + offset) % size]];
println!("Result 1: {}", coord_1 + coord_2 + coord_3);
// task 2
let decrypted_arrangement: Vec<i64> = initial_arrangement
.iter()
.map(|i| i * DECRYPTION_KEY)
.collect();
// list of indices
let mut work_arrangement: Vec<usize> = decrypted_arrangement
.iter()
.enumerate()
.map(|(i, _)| i)
.collect();
// do the whole thing 10x
for _ in 0..10 {
for (i, &n) in decrypted_arrangement.iter().enumerate() {
// position in current state
let work_i = work_arrangement.iter().position(|&elem| elem == i).unwrap();
mv(work_i, n, &mut work_arrangement);
//println!("{}\n", work_arrangement.iter().map(|i| decrypted_arrangement[*i].to_string()).collect::<Vec::<String>>().join(", "));
}
}
let offset = work_arrangement
.iter()
.position(|i| initial_arrangement[*i] == 0)
.unwrap();
let coord_1 = decrypted_arrangement[work_arrangement[(1000 + offset) % size]];
let coord_2 = decrypted_arrangement[work_arrangement[(2000 + offset) % size]];
let coord_3 = decrypted_arrangement[work_arrangement[(3000 + offset) % size]];
println!("Result 2: {}", coord_1 + coord_2 + coord_3);
}
fn mv(pos: usize, move_by: i64, arr: &mut Vec<usize>) {
// reduce move_by to modulo
let move_by = if move_by < 0 {
(move_by.abs() % (arr.len() as i64 - 1)) * -1
} else {
move_by % (arr.len() as i64 - 1)
};
let move_by = if pos as i64 + move_by <= 0 {
move_by + arr.len() as i64 - 1
} else if pos as i64 + move_by >= arr.len() as i64 - 1 {
move_by - arr.len() as i64 + 1
} else {
move_by
};
let mut curr_pos = pos;
let change = if move_by < 0 { -1 } else { 1 };
for _ in 0..move_by.abs() {
let other_pos = ((curr_pos + arr.len()) as i64 + change) as usize % arr.len();
let val = arr[curr_pos];
arr[curr_pos] = arr[other_pos];
arr[other_pos] = val;
curr_pos = other_pos;
}
}

View file

@ -1,7 +1,7 @@
pub mod days; pub mod days;
fn main() { fn main() {
days::d19::solve() days::d20::solve()
//_all_days() //_all_days()
} }