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?");
// constant definition of rocks, from bottom to top
let rocks: Vec<Vec<(u8,u8)>> = vec![
vec![(0,0),(0,1),(0,2),(0,3)],
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),(1,0),(2,0),(3,0)],
vec![(0,0),(0,1),(1,0),(1,1)]
let rocks: Vec<Vec<(u8, u8)>> = vec![
vec![(0, 0), (0, 1), (0, 2), (0, 3)],
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), (1, 0), (2, 0), (3, 0)],
vec![(0, 0), (0, 1), (1, 0), (1, 1)],
];
let directions: Vec<Dir> = contents
@ -28,7 +28,7 @@ pub fn solve() {
.collect();
// [height][width]
let mut chamber = vec![vec![false;WIDTH];4];
let mut chamber = vec![vec![false; WIDTH]; 4];
let mut highest_rock = -1; // floor
@ -36,7 +36,6 @@ pub fn solve() {
let mut heights = Vec::<i64>::new();
/*
51 rocks
@ -47,23 +46,20 @@ pub fn solve() {
%
*/
for i in 0..2344 {
// spawn new rock
let r_index = i as usize % rocks.len(); // get current rock index
let mut rock = Rock::new(&rocks[r_index], highest_rock);
while chamber.iter().filter(|row| !row.contains(&true)).count() < 7 {
chamber.push(vec![false;WIDTH])
chamber.push(vec![false; WIDTH])
}
loop {
// move to left or right
let next_dir = dir_iter.next();
let dir = match next_dir {
Some(x) => { x },
Some(x) => x,
None => {
dir_iter = directions.iter();
dir_iter.next().unwrap()
@ -75,7 +71,7 @@ pub fn solve() {
if rock.left().valid_pos(&chamber) {
rock = rock.left()
}
},
}
Dir::Right => {
if rock.right().valid_pos(&chamber) {
rock = rock.right()
@ -86,16 +82,17 @@ pub fn solve() {
if rock.down().valid_pos(&chamber) {
rock = rock.down();
} else {
rock.pos.iter().for_each(|coord| {
chamber[coord.0 as usize][coord.1 as usize] = true
});
rock.pos
.iter()
.for_each(|coord| chamber[coord.0 as usize][coord.1 as usize] = true);
highest_rock = match chamber
.iter()
.enumerate()
.filter(|row| row.1.contains(&true))
.last() {
.last()
{
Some(x) => x.0 as i64,
None => -1
None => -1,
};
// find recurring patterns in amount of rocks and height
heights.push(highest_rock);
@ -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>) {
if heights.len() % n == 0
&& heights[heights.len()/n-1]*n as i64+n as i64 == heights[heights.len()-1]+1 {
println!("{}: {}", n, heights.len()/n)
&& heights[heights.len() / n - 1] * n as i64 + n as i64 == heights[heights.len() - 1] + 1
{
println!("{}: {}", n, heights.len() / n)
}
}
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|
match *elem {
let mut str_chamber: Vec<Vec<char>> = chamber
.iter()
.map(|line| {
line.iter()
.map(|elem| match *elem {
true => '#',
false => '.'
}
).collect()).collect();
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)]
@ -137,15 +145,18 @@ enum Dir {
#[derive(Clone, Debug)]
struct Rock {
pos: Vec<(i64,i64)>
pos: Vec<(i64, i64)>,
}
impl Rock {
pub fn new(rock: &Vec<(u8,u8)>, highest_rock: i64) -> Self{
let pos: Vec<(i64,i64)> = rock
pub fn new(rock: &Vec<(u8, u8)>, highest_rock: i64) -> Self {
let pos: Vec<(i64, i64)> = rock
.iter()
.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();
Rock { pos }
@ -153,45 +164,57 @@ impl Rock {
pub fn right(&self) -> Self {
for coord in self.pos.iter() {
if coord.1 >= (WIDTH-1) as i64 {
return self.clone()
if coord.1 >= (WIDTH - 1) as i64 {
return self.clone();
}
}
Rock {
pos: self.pos.iter().map(|coord| {
pos: self
.pos
.iter()
.map(|coord| {
(coord.0, coord.1 + 1) // move right, only check for wall !
}).collect()
})
.collect(),
}
}
pub fn left(&self) -> Self {
for coord in self.pos.iter() {
if coord.1 <= 0 {
return self.clone()
return self.clone();
}
}
Rock {
pos: self.pos.iter().map(|coord| {
pos: self
.pos
.iter()
.map(|coord| {
(coord.0, coord.1 - 1) // move left, only check for wall !
}).collect()
})
.collect(),
}
}
pub fn down(&self) -> Self {
Rock {
pos: self.pos.iter().map(|coord| {
pos: self
.pos
.iter()
.map(|coord| {
(coord.0 - 1, coord.1) // move down
}).collect()
})
.collect(),
}
}
pub fn valid_pos(&self, chamber: &Vec<Vec<bool>>) -> bool {
for coord in &self.pos {
if coord.0 < 0 || coord.1 < 0 {
return false
return false;
}
if chamber[coord.0 as usize][coord.1 as usize] {
return false
return false;
}
}

View file

@ -1,11 +1,14 @@
use std::{fs, collections::{HashMap, HashSet, VecDeque}};
use std::{
collections::{HashMap, HashSet, VecDeque},
fs,
};
pub fn solve() {
let path = "res/18/input.txt";
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()
.filter(|line| *line != "")
.map(|line| {
@ -13,25 +16,21 @@ pub fn solve() {
(
vals[0].parse::<usize>().unwrap(),
vals[1].parse::<usize>().unwrap(),
vals[2].parse::<usize>().unwrap()
vals[2].parse::<usize>().unwrap(),
)
})
.collect();
let max: usize = coords
.iter()
.map(|coord|
coord.0.max(
coord.1.max(coord.2)
)
)
.map(|coord| coord.0.max(coord.1.max(coord.2)))
.max()
.unwrap();
let world_size = max as usize + 2;
// [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() {
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
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() {
let (x,y,z) = (*x1 as usize, *y1 as usize, *z1 as usize);
for (x1, y1, z1) in coords.iter() {
let (x, y, z) = (*x1 as usize, *y1 as usize, *z1 as usize);
// x-1
if x == 0 || !world[x-1][y][z] {
if x == 0 || !world[x - 1][y][z] {
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
if !world[x+1][y][z] {
if !world[x + 1][y][z] {
surfaces += 1;
insert_or_increase((x+1,y,z), &mut surface_blocks)
insert_or_increase((x + 1, y, z), &mut surface_blocks)
}
// y-1
if y == 0 || !world[x][y-1][z] {
if y == 0 || !world[x][y - 1][z] {
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
if !world[x][y+1][z] {
if !world[x][y + 1][z] {
surfaces += 1;
insert_or_increase((x,y+1,z), &mut surface_blocks)
insert_or_increase((x, y + 1, z), &mut surface_blocks)
}
// z-1
if z == 0 || !world[x][y][z-1] {
if z == 0 || !world[x][y][z - 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
if !world[x][y][z+1] {
if !world[x][y][z + 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}");
// 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() {
if !bfs_reachable(*block, reference_block, &world) {
surfaces -= *block_surfaces as u32
@ -87,10 +92,9 @@ pub fn solve() {
}
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) {
*map.get_mut(&p).unwrap() += 1;
} 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 seen_nodes = HashSet::<(usize, usize, usize)>::new();
@ -121,32 +129,35 @@ fn bfs_reachable(s: (usize, usize, usize), e: (usize, usize, usize), world: &Vec
false
}
fn get_adjacents(p: (usize, usize, usize), world: &Vec<Vec<Vec<bool>>>) -> Vec<(usize,usize,usize)> {
let mut adj = Vec::<(usize,usize,usize)>::new();
let (x,y,z) = p;
fn get_adjacents(
p: (usize, usize, usize),
world: &Vec<Vec<Vec<bool>>>,
) -> Vec<(usize, usize, usize)> {
let mut adj = Vec::<(usize, usize, usize)>::new();
let (x, y, z) = p;
if x > 0 && !world[x-1][y][z] {
adj.push((x-1,y,z))
if x > 0 && !world[x - 1][y][z] {
adj.push((x - 1, y, z))
}
// x+1
if x < world.len()-1 && !world[x+1][y][z] {
adj.push((x+1,y,z))
if x < world.len() - 1 && !world[x + 1][y][z] {
adj.push((x + 1, y, z))
}
// y-1
if y > 0 && !world[x][y-1][z] {
adj.push((x,y-1,z))
if y > 0 && !world[x][y - 1][z] {
adj.push((x, y - 1, z))
}
// y+1
if y < world.len()-1 && !world[x][y+1][z] {
adj.push((x,y+1,z))
if y < world.len() - 1 && !world[x][y + 1][z] {
adj.push((x, y + 1, z))
}
// z-1
if z > 0 && !world[x][y][z-1] {
adj.push((x,y,z-1))
if z > 0 && !world[x][y][z - 1] {
adj.push((x, y, z - 1))
}
// z+1
if z < world.len()-1 && !world[x][y][z+1] {
adj.push((x,y,z+1))
if z < world.len() - 1 && !world[x][y][z + 1] {
adj.push((x, y, z + 1))
}
adj

View file

@ -1,16 +1,17 @@
use std::{fs, collections::{HashMap, HashSet, VecDeque}};
use std::fs;
use scan_fmt::scan_fmt;
#[allow(dead_code)]
const MINUTES: u32 = 24;
#[allow(dead_code)]
pub fn solve() {
let path = "res/19/input.txt";
let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
// parse blueprints
let blueprints: Vec<Blueprint> = contents
let _blueprints: Vec<Blueprint> = contents
.lines()
.filter(|line| *line != "")
.map(|line| {
@ -30,11 +31,9 @@ pub fn solve() {
})
.collect();
}
#[allow(dead_code)]
#[derive(Debug)]
struct Blueprint {
id: u32,
@ -44,12 +43,11 @@ struct Blueprint {
geode_bot: (u32, u32), // (ore, obsidian)
}
#[allow(dead_code)]
impl Blueprint {
pub fn quality_level(&self) -> u32 {
// TODO dynamic programming?
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;
fn main() {
days::d19::solve()
days::d20::solve()
//_all_days()
}