Refactoring

This commit is contained in:
Jonathan Flueren 2022-12-15 15:00:53 +01:00
parent ae19a80e72
commit 0f30709aa8
12 changed files with 370 additions and 344 deletions

View file

@ -3,8 +3,7 @@ use std::fs;
pub fn solve() { pub fn solve() {
let path = "res/01/input.txt"; let path = "res/01/input.txt";
let contents = fs::read_to_string(path) let contents = fs::read_to_string(path).expect("Should have been able to read the file");
.expect("Should have been able to read the file");
let cont_arr = contents.split("\n"); let cont_arr = contents.split("\n");

View file

@ -18,8 +18,6 @@ pub fn solve() {
println!("Result 2: {}", res); println!("Result 2: {}", res);
} }
// Finds 1st occurence of l unique characters in chars and returns // Finds 1st occurence of l unique characters in chars and returns
// the index of the last of them or -1 // the index of the last of them or -1
fn find_marker(l: usize, chars: &Vec<char>) -> i32 { fn find_marker(l: usize, chars: &Vec<char>) -> i32 {
@ -38,7 +36,8 @@ fn find_marker(l: usize, chars: &Vec<char>) -> i32 {
} }
fn _find_marker_v2(l: usize, chars: &Vec<char>) -> usize { fn _find_marker_v2(l: usize, chars: &Vec<char>) -> usize {
chars.iter() chars
.iter()
.filter(|c| **c != '\n') .filter(|c| **c != '\n')
.collect::<Vec<&char>>() .collect::<Vec<&char>>()
.windows(l) .windows(l)

View file

@ -1,4 +1,4 @@
use std::{fs, collections::HashMap}; use std::{collections::HashMap, fs};
pub fn solve() { pub fn solve() {
let path = "res/07/input.txt"; let path = "res/07/input.txt";
@ -13,19 +13,25 @@ pub fn solve() {
let mut path = Vec::<&str>::new(); let mut path = Vec::<&str>::new();
// Put all paths into the HashMap, add sizes to all parent paths as well // Put all paths into the HashMap, add sizes to all parent paths as well
cont_arr.iter() cont_arr
.iter()
.filter(|line| **line != "") // remove last line .filter(|line| **line != "") // remove last line
.for_each(|line| { .for_each(|line| {
let words = line.split(" ").collect::<Vec<&str>>(); let words = line.split(" ").collect::<Vec<&str>>();
if line.starts_with("dir ") { } // ignore if line.starts_with("dir ") {
else if line.starts_with("$ ls") { } // ignore }
else if line.starts_with("$ cd ..") { // go folder up by deleting deepest folder // ignore
else if line.starts_with("$ ls") {
}
// ignore
else if line.starts_with("$ cd ..") {
// go folder up by deleting deepest folder
path.pop(); path.pop();
} } else if line.starts_with("$ cd") {
else if line.starts_with("$ cd") { // add new folder to path // add new folder to path
path.push(words[2]) path.push(words[2])
} } else {
else { // file, add filesize to current and all parent paths // file, add filesize to current and all parent paths
let size = words[0].parse::<i32>().unwrap(); let size = words[0].parse::<i32>().unwrap();
for i in 0..path.len() { for i in 0..path.len() {
let current_path = path[0..i + 1].join("/"); let current_path = path[0..i + 1].join("/");
@ -39,7 +45,8 @@ pub fn solve() {
}); });
// Sum of all paths lower than 100000 is result // Sum of all paths lower than 100000 is result
let res = paths.iter() let res = paths
.iter()
.map(|pair| *pair.1) .map(|pair| *pair.1)
.filter(|size| *size <= 100000) .filter(|size| *size <= 100000)
.sum::<i32>(); .sum::<i32>();
@ -51,10 +58,12 @@ pub fn solve() {
let min_to_delete = 30000000 - (70000000 - space_occupied); let min_to_delete = 30000000 - (70000000 - space_occupied);
// Find min folder size higher-or-equal to min_to_delete // Find min folder size higher-or-equal to min_to_delete
let res = paths.iter() let res = paths
.iter()
.map(|pair| *pair.1) .map(|pair| *pair.1)
.filter(|size| *size >= min_to_delete) .filter(|size| *size >= min_to_delete)
.min().unwrap(); .min()
.unwrap();
println!("Result 2: {}", res) println!("Result 2: {}", res)
} }

View file

@ -8,25 +8,26 @@ pub fn solve() {
let cont_arr = contents.lines().collect::<Vec<&str>>(); let cont_arr = contents.lines().collect::<Vec<&str>>();
// parse trees as 2D i32 Vec // parse trees as 2D i32 Vec
let trees: Vec<Vec<i32>> = cont_arr.iter() let trees: Vec<Vec<i32>> = cont_arr
.iter()
.filter(|line| **line != "") .filter(|line| **line != "")
.map(|line| .map(|line| {
line.chars().collect::<Vec<char>>() line.chars()
.iter().map(|t| return t.to_digit(10).unwrap() as i32) .collect::<Vec<char>>()
.iter()
.map(|t| return t.to_digit(10).unwrap() as i32)
.collect() .collect()
).collect(); })
.collect();
let width = trees[0].len(); let width = trees[0].len();
let height = trees.len(); let height = trees.len();
// task 1 // task 1
// initialize visibilities with 0 // initialize visibilities with 0
let mut visibilities: Vec<Vec<i32>> = (0..height).map(|_| { let mut visibilities: Vec<Vec<i32>> = (0..height)
(0..width).map(|_| 0).collect() .map(|_| (0..width).map(|_| 0).collect())
}).collect(); .collect();
// mark visible trees with 1 // mark visible trees with 1
// left to right & right to left // left to right & right to left
@ -43,7 +44,6 @@ pub fn solve() {
visibilities[i][width - j - 1] = 1; visibilities[i][width - j - 1] = 1;
last_max_right = trees[i][width - j - 1]; last_max_right = trees[i][width - j - 1];
} }
} }
} }
@ -61,54 +61,67 @@ pub fn solve() {
visibilities[height - j - 1][i] = 1; visibilities[height - j - 1][i] = 1;
last_max_bot = trees[height - j - 1][i]; last_max_bot = trees[height - j - 1][i];
} }
} }
} }
// sum all visible trees // sum all visible trees
let res = visibilities.iter() let res = visibilities
.iter()
.map(|line| line.iter().sum::<i32>()) .map(|line| line.iter().sum::<i32>())
.sum::<i32>(); .sum::<i32>();
println!("Result 1: {}", res); println!("Result 1: {}", res);
// task 2 // task 2
let scenic_scores: Vec<Vec<i32>> = (0..height).map(|i| { let scenic_scores: Vec<Vec<i32>> = (0..height)
(0..width).map(|j| { .map(|i| {
(0..width)
.map(|j| {
// calculate view range in each direction // calculate view range in each direction
let mut to_top = 0; let mut to_top = 0;
for k in (0..i).rev() { for k in (0..i).rev() {
to_top += 1; to_top += 1;
if trees[k][j] >= trees[i][j] { break; } if trees[k][j] >= trees[i][j] {
break;
}
} }
let mut to_bot = 0; let mut to_bot = 0;
for k in i + 1..height { for k in i + 1..height {
to_bot += 1; to_bot += 1;
if trees[k][j] >= trees[i][j] { break; } if trees[k][j] >= trees[i][j] {
break;
}
} }
let mut to_left = 0; let mut to_left = 0;
for k in (0..j).rev() { for k in (0..j).rev() {
to_left += 1; to_left += 1;
if trees[i][k] >= trees[i][j] { break; } if trees[i][k] >= trees[i][j] {
break;
}
} }
let mut to_right = 0; let mut to_right = 0;
for k in j + 1..width { for k in j + 1..width {
to_right += 1; to_right += 1;
if trees[i][k] >= trees[i][j] { break; } if trees[i][k] >= trees[i][j] {
break;
}
} }
to_top * to_bot * to_left * to_right to_top * to_bot * to_left * to_right
}).collect() })
}).collect(); .collect()
})
.collect();
// find max scenic score // find max scenic score
let res = scenic_scores.iter() let res = scenic_scores
.iter()
.map(|line| line.iter().max().unwrap()) .map(|line| line.iter().max().unwrap())
.max().unwrap(); .max()
.unwrap();
println!("Result 2: {}", res) println!("Result 2: {}", res)
} }

View file

@ -5,16 +5,12 @@ const GRID_HEIGHT: i32 = 1000;
const START_X: i32 = 500; const START_X: i32 = 500;
const START_Y: i32 = 500; const START_Y: i32 = 500;
pub fn solve() { pub fn solve() {
let path = "res/09/input.txt"; let path = "res/09/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 lines: Vec<&str> = contents let lines: Vec<&str> = contents.lines().filter(|line| *line != "").collect();
.lines()
.filter(|line| *line != "")
.collect();
// task 1 - rope with 2 knots // task 1 - rope with 2 knots
let mut rope2 = Rope::new(2); let mut rope2 = Rope::new(2);
@ -30,7 +26,7 @@ pub fn solve() {
"D" => Dir::Down, "D" => Dir::Down,
"L" => Dir::Left, "L" => Dir::Left,
"R" => Dir::Right, "R" => Dir::Right,
_ => Dir::Up _ => Dir::Up,
}; };
let amount = cmd[1].parse::<i32>().unwrap(); let amount = cmd[1].parse::<i32>().unwrap();
@ -48,9 +44,6 @@ pub fn solve() {
// task 2 res // task 2 res
let res = rope10.tail_visited_num(); let res = rope10.tail_visited_num();
println!("Result 1: {}", res); println!("Result 1: {}", res);
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -58,13 +51,13 @@ enum Dir {
Up, Up,
Down, Down,
Left, Left,
Right Right,
} }
struct Rope { struct Rope {
knots_x: Vec<i32>, knots_x: Vec<i32>,
knots_y: Vec<i32>, knots_y: Vec<i32>,
tail_visited_grid: Vec<Vec<bool>> // [Y][X] tail_visited_grid: Vec<Vec<bool>>, // [Y][X]
} }
impl Rope { impl Rope {
@ -73,27 +66,18 @@ impl Rope {
knots_x: (0..knots).map(|_| START_X).collect(), knots_x: (0..knots).map(|_| START_X).collect(),
knots_y: (0..knots).map(|_| START_Y).collect(), knots_y: (0..knots).map(|_| START_Y).collect(),
tail_visited_grid: (0..GRID_HEIGHT) tail_visited_grid: (0..GRID_HEIGHT)
.map(|_| (0..GRID_WIDTH) .map(|_| (0..GRID_WIDTH).map(|_| false).collect())
.map(|_| false).collect() .collect(),
).collect()
} }
} }
// move head (first knot) // move head (first knot)
pub fn mv(&mut self, dir: Dir) { pub fn mv(&mut self, dir: Dir) {
match dir { match dir {
Dir::Up => { Dir::Up => self.knots_y[0] -= 1,
self.knots_y[0] -= 1 Dir::Down => self.knots_y[0] += 1,
}, Dir::Left => self.knots_x[0] -= 1,
Dir::Down => { Dir::Right => self.knots_x[0] += 1,
self.knots_y[0] += 1
},
Dir::Left => {
self.knots_x[0] -= 1
},
Dir::Right => {
self.knots_x[0] += 1
}
} }
self.check_tail_pos() self.check_tail_pos()
} }
@ -102,14 +86,20 @@ impl Rope {
fn check_tail_pos(&mut self) { fn check_tail_pos(&mut self) {
// check pos of each knot except first // check pos of each knot except first
for i in 1..self.knots_x.len() { for i in 1..self.knots_x.len() {
if (self.knots_x[i-1] == self.knots_x[i] && (self.knots_y[i-1] - self.knots_y[i]).abs() == 1) if (self.knots_x[i - 1] == self.knots_x[i]
|| (self.knots_y[i-1] == self.knots_y[i] && (self.knots_x[i-1] - self.knots_x[i]).abs() == 1) { && (self.knots_y[i - 1] - self.knots_y[i]).abs() == 1)
|| (self.knots_y[i - 1] == self.knots_y[i]
&& (self.knots_x[i - 1] - self.knots_x[i]).abs() == 1)
{
// Knots are touching, nothing to do // Knots are touching, nothing to do
} else if (self.knots_x[i-1] - self.knots_x[i]).abs() == 1 && (self.knots_y[i-1] - self.knots_y[i]).abs() == 1 { } else if (self.knots_x[i - 1] - self.knots_x[i]).abs() == 1
&& (self.knots_y[i - 1] - self.knots_y[i]).abs() == 1
{
// Knots are touching diagonally, nothing to do // Knots are touching diagonally, nothing to do
} else { } else {
// Tail needs to be moved // Tail needs to be moved
if self.knots_x[i-1] != self.knots_x[i] && self.knots_y[i-1] != self.knots_y[i] { if self.knots_x[i - 1] != self.knots_x[i] && self.knots_y[i - 1] != self.knots_y[i]
{
// Move diagonally // Move diagonally
self.knots_x[i] += normalize(self.knots_x[i - 1] - self.knots_x[i]); self.knots_x[i] += normalize(self.knots_x[i - 1] - self.knots_x[i]);
self.knots_y[i] += normalize(self.knots_y[i - 1] - self.knots_y[i]); self.knots_y[i] += normalize(self.knots_y[i - 1] - self.knots_y[i]);
@ -125,19 +115,20 @@ impl Rope {
} }
// Set current tail (last knot) pos as visited // Set current tail (last knot) pos as visited
self.tail_visited_grid[*self.knots_y.last().unwrap() as usize][*self.knots_x.last().unwrap() as usize] = true; self.tail_visited_grid[*self.knots_y.last().unwrap() as usize]
[*self.knots_x.last().unwrap() as usize] = true;
} }
// returns number of cells visited by tail // returns number of cells visited by tail
pub fn tail_visited_num(&self) -> i32 { pub fn tail_visited_num(&self) -> i32 {
self.tail_visited_grid.iter() self.tail_visited_grid
.map(|row| .iter()
.map(|row| {
row.iter() row.iter()
.map(|cell| .map(|cell| if *cell { 1 as i32 } else { 0 as i32 })
if *cell { 1 as i32 } .sum::<i32>()
else { 0 as i32 } })
).sum::<i32>() .sum()
).sum()
} }
} }

View file

@ -5,10 +5,7 @@ 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?");
let lines: Vec<&str> = contents let lines: Vec<&str> = contents.lines().filter(|line| *line != "").collect();
.lines()
.filter(|line| *line != "")
.collect();
let mut reg_x = 1; let mut reg_x = 1;
let mut cycle = 0; let mut cycle = 0;
@ -27,7 +24,7 @@ pub fn solve() {
signal_strengths.push(cycle * reg_x); signal_strengths.push(cycle * reg_x);
} }
crt.push(sprite_draw(cycle, reg_x)); crt.push(sprite_draw(cycle, reg_x));
}, }
"addx" => { "addx" => {
// increase cycle 2 times // increase cycle 2 times
(0..2).for_each(|_| { (0..2).for_each(|_| {
@ -39,7 +36,7 @@ pub fn solve() {
}); });
// change regX according to parameter // change regX according to parameter
reg_x += parts[1].parse::<i32>().unwrap(); reg_x += parts[1].parse::<i32>().unwrap();
}, }
_ => {} _ => {}
} }
}); });
@ -52,8 +49,11 @@ pub fn solve() {
let mut print_buffer = "".to_string(); let mut print_buffer = "".to_string();
// print the crt line by line // print the crt line by line
crt.iter().enumerate().for_each(|(i, p)| { crt.iter().enumerate().for_each(|(i, p)| {
if *p { print_buffer += "#" } if *p {
else { print_buffer += "." } print_buffer += "#"
} else {
print_buffer += "."
}
// print buffer if a line is completed // print buffer if a line is completed
if (i + 1) % 40 == 0 { if (i + 1) % 40 == 0 {
@ -61,7 +61,6 @@ pub fn solve() {
print_buffer = "".to_string(); print_buffer = "".to_string();
} }
}) })
} }
// returns whether the passed cycle is a relevant one // returns whether the passed cycle is a relevant one
@ -75,5 +74,5 @@ fn rel_cycle(cycle: i32) -> bool {
// returns whether the sprite is currently in a position to draw a pixel // returns whether the sprite is currently in a position to draw a pixel
fn sprite_draw(cycle: i32, reg_x: i32) -> bool { fn sprite_draw(cycle: i32, reg_x: i32) -> bool {
return ((cycle-1)%40).abs_diff(reg_x) <= 1 return ((cycle - 1) % 40).abs_diff(reg_x) <= 1;
} }

View file

@ -5,11 +5,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?");
let monk_strings: Vec<&str> = contents let monk_strings: Vec<&str> = contents.split("\n\n").collect();
.split("\n\n")
.collect();
let mut monkeys: Vec<Monkey> = monk_strings.iter().map(|monkey| Monkey::new(*monkey)).collect(); let mut monkeys: Vec<Monkey> = monk_strings
.iter()
.map(|monkey| Monkey::new(*monkey))
.collect();
let mut monkeys2 = monkeys.clone(); let mut monkeys2 = monkeys.clone();
let monkeys_num = monkeys.len(); let monkeys_num = monkeys.len();
@ -19,7 +20,9 @@ pub fn solve() {
let new_items = monkeys[i].turn(monkeys_num, |x| x / 3); let new_items = monkeys[i].turn(monkeys_num, |x| x / 3);
// add items to correct monkeys // add items to correct monkeys
(0..monkeys_num).for_each(|i| { (0..monkeys_num).for_each(|i| {
new_items[i].iter().for_each(|item| monkeys[i].items.push(*item)) new_items[i]
.iter()
.for_each(|item| monkeys[i].items.push(*item))
}); });
}) })
}); });
@ -29,7 +32,6 @@ pub fn solve() {
println!("Result 1: {res}"); println!("Result 1: {res}");
(0..10000).for_each(|_| { (0..10000).for_each(|_| {
(0..monkeys_num).for_each(|i| { (0..monkeys_num).for_each(|i| {
// get changed items, modulo them with common divider of divisible by tests // get changed items, modulo them with common divider of divisible by tests
@ -37,7 +39,9 @@ pub fn solve() {
let new_items = monkeys2[i].turn(monkeys_num, |x| x % common_divider); let new_items = monkeys2[i].turn(monkeys_num, |x| x % common_divider);
// add items to correct monkeys // add items to correct monkeys
(0..monkeys_num).for_each(|i| { (0..monkeys_num).for_each(|i| {
new_items[i].iter().for_each(|item| monkeys2[i].items.push(*item)) new_items[i]
.iter()
.for_each(|item| monkeys2[i].items.push(*item))
}); });
}) })
}); });
@ -46,14 +50,12 @@ pub fn solve() {
let res = monkeys2[0].inspections * monkeys2[1].inspections; let res = monkeys2[0].inspections * monkeys2[1].inspections;
println!("Result 2: {res}"); println!("Result 2: {res}");
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
enum Operation { enum Operation {
Mult, Mult,
Add Add,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -78,9 +80,12 @@ impl Monkey {
test_divisible_by: 0, test_divisible_by: 0,
monkey_if_true: 0, monkey_if_true: 0,
monkey_if_false: 0, monkey_if_false: 0,
inspections: 0 inspections: 0,
}; };
input.split("\n").filter(|line| *line != "").for_each(|line| { input
.split("\n")
.filter(|line| *line != "")
.for_each(|line| {
let (ident, val) = line.split_at(line.find(":").unwrap()); let (ident, val) = line.split_at(line.find(":").unwrap());
match ident { match ident {
" Starting items" => { " Starting items" => {
@ -88,11 +93,11 @@ impl Monkey {
let val = val.replace(":", "").replace(" ", ""); let val = val.replace(":", "").replace(" ", "");
monkey.items = val monkey.items = val
.split(",") .split(",")
.collect::<Vec::<&str>>() .collect::<Vec<&str>>()
.iter() .iter()
.map(|i| (*i).parse::<u64>().unwrap()) .map(|i| (*i).parse::<u64>().unwrap())
.collect() .collect()
}, }
" Operation" => { " Operation" => {
// parse operator, parse last word as number // parse operator, parse last word as number
let val = val.replace(": new = old ", ""); let val = val.replace(": new = old ", "");
@ -107,22 +112,22 @@ impl Monkey {
} else { } else {
monkey.operation_num = num.trim().parse::<i32>().unwrap(); monkey.operation_num = num.trim().parse::<i32>().unwrap();
} }
}, }
" Test" => { " Test" => {
// parse last word as number // parse last word as number
let words: Vec<&str> = val.split(" ").collect(); let words: Vec<&str> = val.split(" ").collect();
monkey.test_divisible_by = words.last().unwrap().parse::<u64>().unwrap(); monkey.test_divisible_by = words.last().unwrap().parse::<u64>().unwrap();
}, }
" If true" => { " If true" => {
// parse last word as number // parse last word as number
let words: Vec<&str> = val.split(" ").collect(); let words: Vec<&str> = val.split(" ").collect();
monkey.monkey_if_true = words.last().unwrap().parse::<i32>().unwrap(); monkey.monkey_if_true = words.last().unwrap().parse::<i32>().unwrap();
}, }
" If false" => { " If false" => {
// parse last word as number // parse last word as number
let words: Vec<&str> = val.split(" ").collect(); let words: Vec<&str> = val.split(" ").collect();
monkey.monkey_if_false = words.last().unwrap().parse::<i32>().unwrap(); monkey.monkey_if_false = words.last().unwrap().parse::<i32>().unwrap();
}, }
_ => {} _ => {}
} }
}); });

View file

@ -1,60 +1,72 @@
use std::{fs, collections::{HashMap, HashSet}}; use std::{
collections::{HashMap, HashSet},
fs,
};
pub fn solve() { pub fn solve() {
let path = "res/12/input.txt"; let path = "res/12/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 lines: Vec<&str> = contents let lines: Vec<&str> = contents.lines().collect();
.lines()
.collect();
// Build grid // Build grid
let mut start = (0, 0); let mut start = (0, 0);
let mut end = (0, 0); let mut end = (0, 0);
let grid: Vec<Vec<u32>> = lines.iter().enumerate().map(|(y, line)| { let grid: Vec<Vec<u32>> = lines
line.chars().enumerate().map(|(x, c)| .iter()
match c { .enumerate()
.map(|(y, line)| {
line.chars()
.enumerate()
.map(|(x, c)| match c {
'S' => { 'S' => {
start = (x as u32, y as u32); start = (x as u32, y as u32);
return char_to_numeric('a') return char_to_numeric('a');
}
},
'E' => { 'E' => {
end = (x as u32, y as u32); end = (x as u32, y as u32);
return char_to_numeric('z') return char_to_numeric('z');
},
_ => {
return char_to_numeric(c)
} }
}).collect() _ => return char_to_numeric(c),
}).collect(); })
.collect()
})
.collect();
// Build adjacent lists // Build adjacent lists
let mut adjacents = HashMap::<(u32, u32), Vec<(u32, u32)>>::new(); let mut adjacents = HashMap::<(u32, u32), Vec<(u32, u32)>>::new();
grid.iter() grid.iter().enumerate().for_each(|(y, line)| {
.enumerate() line.iter().enumerate().for_each(|(x, height)| {
.for_each(|(y, line)| {
line.iter()
.enumerate()
.for_each(|(x, height)| {
adjacents.insert((x as u32, y as u32), Vec::<(u32, u32)>::new()); adjacents.insert((x as u32, y as u32), Vec::<(u32, u32)>::new());
// top // top
if y != 0 && grid[y - 1][x] <= height + 1 { if y != 0 && grid[y - 1][x] <= height + 1 {
adjacents.get_mut(&(x as u32, y as u32)).unwrap().push((x as u32, (y-1) as u32)) adjacents
.get_mut(&(x as u32, y as u32))
.unwrap()
.push((x as u32, (y - 1) as u32))
} }
// bot // bot
if y != grid.len() - 1 && grid[y + 1][x] <= height + 1 { if y != grid.len() - 1 && grid[y + 1][x] <= height + 1 {
adjacents.get_mut(&(x as u32, y as u32)).unwrap().push((x as u32, (y+1) as u32)) adjacents
.get_mut(&(x as u32, y as u32))
.unwrap()
.push((x as u32, (y + 1) as u32))
} }
//left //left
if x != 0 && grid[y][x - 1] <= height + 1 { if x != 0 && grid[y][x - 1] <= height + 1 {
adjacents.get_mut(&(x as u32, y as u32)).unwrap().push(((x-1) as u32, y as u32)) adjacents
.get_mut(&(x as u32, y as u32))
.unwrap()
.push(((x - 1) as u32, y as u32))
} }
// right // right
if x != grid[0].len() - 1 && grid[y][x + 1] <= height + 1 { if x != grid[0].len() - 1 && grid[y][x + 1] <= height + 1 {
adjacents.get_mut(&(x as u32, y as u32)).unwrap().push(((x+1) as u32, y as u32)) adjacents
.get_mut(&(x as u32, y as u32))
.unwrap()
.push(((x + 1) as u32, y as u32))
} }
}) })
}); });
@ -66,26 +78,16 @@ pub fn solve() {
// task 2 - find min distance for each node with height 1, select min // task 2 - find min distance for each node with height 1, select min
let mut distances = Vec::<i32>::new(); let mut distances = Vec::<i32>::new();
grid.iter() grid.iter().enumerate().for_each(|(y, line)| {
.enumerate() line.iter().enumerate().for_each(|(x, height)| {
.for_each(|(y, line)| {
line.iter()
.enumerate()
.for_each(|(x, height)| {
if *height == 1 { if *height == 1 {
distances.push( distances.push(bfs((x as u32, y as u32), end, &adjacents))
bfs((x as u32, y as u32), end, &adjacents)
)
} }
}) })
}); });
let res = *distances.iter() let res = *distances.iter().filter(|dist| **dist != -1).min().unwrap();
.filter(|dist| **dist != -1)
.min()
.unwrap();
println!("Result 2: {res}") println!("Result 2: {res}")
} }
// Maps lowercase chars to 1..=26 // Maps lowercase chars to 1..=26
@ -94,7 +96,11 @@ fn char_to_numeric(c: char) -> u32 {
} }
// Runs a Breadth-first search on the given graph and returns the minimal steps necessary to reach end from start, -1 if not reachable // Runs a Breadth-first search on the given graph and returns the minimal steps necessary to reach end from start, -1 if not reachable
fn bfs(start: (u32,u32), end: (u32,u32), adjacents: &HashMap<(u32,u32),Vec<(u32,u32)>>) -> i32 { fn bfs(
start: (u32, u32),
end: (u32, u32),
adjacents: &HashMap<(u32, u32), Vec<(u32, u32)>>,
) -> i32 {
let mut queue = Vec::<(u32, u32)>::new(); let mut queue = Vec::<(u32, u32)>::new();
let mut seen_nodes = HashSet::<(u32, u32)>::new(); let mut seen_nodes = HashSet::<(u32, u32)>::new();
let mut predecessor = HashMap::<(u32, u32), (u32, u32)>::new(); let mut predecessor = HashMap::<(u32, u32), (u32, u32)>::new();
@ -105,9 +111,7 @@ fn bfs(start: (u32,u32), end: (u32,u32), adjacents: &HashMap<(u32,u32),Vec<(u32,
if node == end { if node == end {
break; break;
} }
adjacents.get(&node).unwrap() adjacents.get(&node).unwrap().iter().for_each(|child| {
.iter()
.for_each(|child| {
if !seen_nodes.contains(child) { if !seen_nodes.contains(child) {
queue.push(*child); queue.push(*child);
seen_nodes.insert(*child); seen_nodes.insert(*child);
@ -121,7 +125,7 @@ fn bfs(start: (u32,u32), end: (u32,u32), adjacents: &HashMap<(u32,u32),Vec<(u32,
while node != start { while node != start {
node = match predecessor.get(&node) { node = match predecessor.get(&node) {
Some(n) => *n, Some(n) => *n,
None => return -1 // return -1 if end not reachable None => return -1, // return -1 if end not reachable
}; };
res += 1; res += 1;
} }

View file

@ -1,5 +1,5 @@
use std::{fs, cmp::Ordering};
use serde_json::Value; use serde_json::Value;
use std::{cmp::Ordering, fs};
pub fn solve() { pub fn solve() {
let path = "res/13/input.txt"; let path = "res/13/input.txt";
@ -42,11 +42,10 @@ pub fn solve() {
packets.push(serde_json::from_str("[[2]]").unwrap()); packets.push(serde_json::from_str("[[2]]").unwrap());
// sort by compare function using is_right_order // sort by compare function using is_right_order
packets.sort_by(|a, b| packets.sort_by(|a, b| match is_right_order((a, b)) {
match is_right_order((a, b)) {
Ordered::Yes => Ordering::Less, Ordered::Yes => Ordering::Less,
Ordered::Maybe => Ordering::Equal, Ordered::Maybe => Ordering::Equal,
Ordered::No => Ordering::Greater Ordered::No => Ordering::Greater,
}); });
// find [[2]] and [[6]] indices // find [[2]] and [[6]] indices
@ -59,8 +58,7 @@ pub fn solve() {
let v = v[0].as_array().unwrap(); let v = v[0].as_array().unwrap();
if v[0].is_number() && v[0].as_u64().unwrap() == 2 { if v[0].is_number() && v[0].as_u64().unwrap() == 2 {
i2 = i + 1 i2 = i + 1
} } else if v[0].is_number() && v[0].as_u64().unwrap() == 6 {
else if v[0].is_number() && v[0].as_u64().unwrap() == 6 {
i6 = i + 1 i6 = i + 1
} }
} }
@ -76,7 +74,7 @@ pub fn solve() {
enum Ordered { enum Ordered {
Yes, Yes,
Maybe, Maybe,
No No,
} }
// returns whether the passed Values are in the right order // returns whether the passed Values are in the right order
@ -90,23 +88,23 @@ fn is_right_order(values: (&Value, &Value)) -> Ordered {
let v1 = values.1.as_u64().unwrap(); let v1 = values.1.as_u64().unwrap();
// wrong order if right is higher than left // wrong order if right is higher than left
if v0 < v1 { if v0 < v1 {
return Ordered::Yes return Ordered::Yes;
} else if v0 == v1 { } else if v0 == v1 {
return Ordered::Maybe return Ordered::Maybe;
} else { } else {
return Ordered::No return Ordered::No;
} }
} }
// left number, right array // left number, right array
else if values.0.is_number() && values.1.is_array() { else if values.0.is_number() && values.1.is_array() {
// wrap number into arr, then compare again // wrap number into arr, then compare again
let left = Value::Array(vec!(values.0.clone())); let left = Value::Array(vec![values.0.clone()]);
return is_right_order((&left, &values.1)); return is_right_order((&left, &values.1));
} }
// left array, right number // left array, right number
else if values.0.is_array() && values.1.is_number() { else if values.0.is_array() && values.1.is_number() {
// wrap number into arr, then compare again // wrap number into arr, then compare again
let right = Value::Array(vec!(values.1.clone())); let right = Value::Array(vec![values.1.clone()]);
return is_right_order((&values.0, &right)); return is_right_order((&values.0, &right));
} }
// both array // both array
@ -123,17 +121,17 @@ fn is_right_order(values: (&Value, &Value)) -> Ordered {
// left smaller, counts as ordered // left smaller, counts as ordered
if left.is_none() && right.is_some() { if left.is_none() && right.is_some() {
return Ordered::Yes return Ordered::Yes;
} }
// right smaller, counts as unordered // right smaller, counts as unordered
if left.is_some() && right.is_none() { if left.is_some() && right.is_none() {
return Ordered::No return Ordered::No;
} }
// both have same length, doesn't say anything about ordering // both have same length, doesn't say anything about ordering
if left.is_none() && right.is_none() { if left.is_none() && right.is_none() {
return Ordered::Maybe return Ordered::Maybe;
} }
let left = left.unwrap(); let left = left.unwrap();
@ -142,7 +140,7 @@ fn is_right_order(values: (&Value, &Value)) -> Ordered {
// only go into next iteration if not definitely yes or no // only go into next iteration if not definitely yes or no
let res = is_right_order((&left, &right)); let res = is_right_order((&left, &right));
if res != Ordered::Maybe { if res != Ordered::Maybe {
return res return res;
} }
} }
} }

View file

@ -18,18 +18,23 @@ pub fn solve() {
line.split(" -> ") line.split(" -> ")
.map(|coord| { .map(|coord| {
let coord_arr: Vec<&str> = coord.split(",").collect(); let coord_arr: Vec<&str> = coord.split(",").collect();
(coord_arr[0].parse::<u32>().unwrap(), (
coord_arr[1].parse::<u32>().unwrap()) coord_arr[0].parse::<u32>().unwrap(),
}).collect() coord_arr[1].parse::<u32>().unwrap(),
}).collect(); )
})
.collect()
})
.collect();
// cave[X][Y] // cave[X][Y]
let mut cave: Vec<Vec<bool>> = (0..CAVE_WIDTH).map(|_| (0..CAVE_HEIGHT).map(|_| false).collect()).collect(); let mut cave: Vec<Vec<bool>> = (0..CAVE_WIDTH)
.map(|_| (0..CAVE_HEIGHT).map(|_| false).collect())
.collect();
// set cave path structure // set cave path structure
rock_paths.iter().for_each(|path| { rock_paths.iter().for_each(|path| {
path.windows(2) path.windows(2).for_each(|pairs| {
.for_each(|pairs| {
// draw rock lines // draw rock lines
let x_iter = if pairs[0].0 > pairs[1].0 { let x_iter = if pairs[0].0 > pairs[1].0 {
pairs[1].0..=pairs[0].0 pairs[1].0..=pairs[0].0
@ -46,11 +51,9 @@ pub fn solve() {
cave[(x - X_OFFSET) as usize][y as usize] = true; cave[(x - X_OFFSET) as usize][y as usize] = true;
}) })
}); });
}) })
}); });
// task 1 - normal cave // task 1 - normal cave
// let sand fall // let sand fall
let mut sand_unit_counter: u32 = 0; let mut sand_unit_counter: u32 = 0;
@ -63,24 +66,16 @@ pub fn solve() {
println!("Result 1: {sand_unit_counter}"); println!("Result 1: {sand_unit_counter}");
// task 2 - cave with ground // task 2 - cave with ground
// find ground - cave height is 2 + max y value // find ground - cave height is 2 + max y value
let cave_height = 2 + rock_paths let cave_height = 2 + rock_paths
.iter() .iter()
.map(|line| .map(|line| line.iter().map(|r| r.1).max().unwrap())
line
.iter()
.map(|r| r.1)
.max()
.unwrap()
)
.max() .max()
.unwrap(); .unwrap();
// build ground // build ground
cave.iter_mut().for_each(|col| { cave.iter_mut()
col[(cave_height) as usize] = true .for_each(|col| col[(cave_height) as usize] = true);
});
// let sand fall again, until it reaches the start point // let sand fall again, until it reaches the start point
while sand_pos != (START_POINT.0 - X_OFFSET, START_POINT.1) { while sand_pos != (START_POINT.0 - X_OFFSET, START_POINT.1) {
@ -100,10 +95,12 @@ fn next_sand_pos(cave: &Vec<Vec<bool>>) -> (u32, u32) {
// first check directly below // first check directly below
if !cave[(pos.0) as usize][(pos.1 + 1) as usize] { if !cave[(pos.0) as usize][(pos.1 + 1) as usize] {
pos = (pos.0, pos.1 + 1) pos = (pos.0, pos.1 + 1)
} // then diagonally down-left }
// then diagonally down-left
else if !cave[(pos.0 - 1) as usize][(pos.1 + 1) as usize] { else if !cave[(pos.0 - 1) as usize][(pos.1 + 1) as usize] {
pos = (pos.0 - 1, pos.1 + 1) pos = (pos.0 - 1, pos.1 + 1)
} // then diagonally down-right }
// then diagonally down-right
else if !cave[(pos.0 + 1) as usize][(pos.1 + 1) as usize] { else if !cave[(pos.0 + 1) as usize][(pos.1 + 1) as usize] {
pos = (pos.0 + 1, pos.1 + 1) pos = (pos.0 + 1, pos.1 + 1)
} }
@ -116,13 +113,14 @@ fn next_sand_pos(cave: &Vec<Vec<bool>>) -> (u32, u32) {
fn is_end_pos(pos: (u32, u32), cave: &Vec<Vec<bool>>) -> bool { fn is_end_pos(pos: (u32, u32), cave: &Vec<Vec<bool>>) -> bool {
if pos.1 as usize == cave[0].len() - 1 { if pos.1 as usize == cave[0].len() - 1 {
// pos is on ground of the cave, lays still // pos is on ground of the cave, lays still
return true return true;
} }
// don't need to check for enough space to left+right since cave is big enough // don't need to check for enough space to left+right since cave is big enough
if cave[(pos.0 - 1) as usize][(pos.1 + 1) as usize] if cave[(pos.0 - 1) as usize][(pos.1 + 1) as usize]
&& cave[(pos.0) as usize][(pos.1 + 1) as usize] && cave[(pos.0) as usize][(pos.1 + 1) as usize]
&& cave[(pos.0+1) as usize][(pos.1+1) as usize] { && cave[(pos.0 + 1) as usize][(pos.1 + 1) as usize]
return true {
return true;
} }
false false
@ -132,12 +130,10 @@ fn is_end_pos(pos: (u32, u32), cave: &Vec<Vec<bool>>) -> bool {
fn _print_cave(cave: &Vec<Vec<bool>>) { fn _print_cave(cave: &Vec<Vec<bool>>) {
let mut out: Vec<String> = (0..CAVE_HEIGHT).map(|_| "".to_string()).collect(); let mut out: Vec<String> = (0..CAVE_HEIGHT).map(|_| "".to_string()).collect();
cave.iter().for_each(|line| { cave.iter().for_each(|line| {
line.iter().enumerate().for_each(|(i, cell)| line.iter().enumerate().for_each(|(i, cell)| match *cell {
match *cell {
true => out[i] += "#", true => out[i] += "#",
false => out[i] += "." false => out[i] += ".",
} });
);
}); });
out.iter().for_each(|s| println!("{s}")); out.iter().for_each(|s| println!("{s}"));
} }

9
src/days/d15.rs Normal file
View file

@ -0,0 +1,9 @@
use std::fs;
pub fn solve() {
let path = "res/15/input.txt";
let contents = fs::read_to_string(path).expect("File read error");
}

View file

@ -1,7 +1,7 @@
pub mod days; pub mod days;
fn main() { fn main() {
days::d14::solve() days::d15::solve()
//_all_days() //_all_days()
} }
@ -32,4 +32,8 @@ fn _all_days() {
days::d12::solve(); days::d12::solve();
println!("\nDay 13"); println!("\nDay 13");
days::d13::solve(); days::d13::solve();
println!("\nDay 14");
days::d14::solve();
println!("\nDay 15");
days::d14::solve();
} }