Moved aoc challenges from their own repos to this one

This commit is contained in:
2024-10-25 11:07:47 +02:00
commit ae00eb4f80
51 changed files with 11067 additions and 0 deletions

20
y2022/src/bin/d1.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d1;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/1_input.txt")).unwrap();
println!("{}", d1::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/1_input.txt")).unwrap();
println!("{}", d1::process_part2(&content));
}

20
y2022/src/bin/d2.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d2::{process_part1, process_part2};
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/2_input.txt")).unwrap();
println!("{}", process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/2_input.txt")).unwrap();
println!("{}", process_part2(&content));
}

20
y2022/src/bin/d3.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d3;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/3_input.txt")).unwrap();
println!("{}", d3::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/3_input.txt")).unwrap();
println!("{}", d3::process_part2(&content));
}

20
y2022/src/bin/d4.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d4;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/4_input.txt")).unwrap();
println!("{}", d4::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/4_input.txt")).unwrap();
println!("{}", d4::process_part2(&content));
}

20
y2022/src/bin/d5.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d5;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/5_input.txt")).unwrap();
println!("{}", d5::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/5_input.txt")).unwrap();
println!("{}", d5::process_part2(&content));
}

20
y2022/src/bin/d6.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d6;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/6_input.txt")).unwrap();
println!("{}", d6::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/6_input.txt")).unwrap();
println!("{}", d6::process_part2(&content));
}

20
y2022/src/bin/d7.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d7;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/7_input.txt")).unwrap();
println!("{}", d7::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/7_input.txt")).unwrap();
println!("{}", d7::process_part2(&content));
}

20
y2022/src/bin/d8.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d8;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/8_input.txt")).unwrap();
println!("{}", d8::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/8_input.txt")).unwrap();
println!("{}", d8::process_part2(&content));
}

20
y2022/src/bin/d9.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2022::days::d9;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/9_input.txt")).unwrap();
println!("{}", d9::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/9_input.txt")).unwrap();
println!("{}", d9::process_part2(&content));
}

49
y2022/src/days/d1.rs Normal file
View File

@@ -0,0 +1,49 @@
pub fn process_part1(input: &str) -> i32 {
let mut vector: Vec<i32> = input
.split("\n\n")
.map(|lines| lines.lines().map(|line| line.parse::<i32>().unwrap()).sum())
.collect();
vector.sort_by(|a, b| b.cmp(a));
vector[0]
}
pub fn process_part2(input: &str) -> i32 {
let mut vector: Vec<i32> = input
.split("\n\n")
.map(|lines| lines.lines().map(|line| line.parse::<i32>().unwrap()).sum())
.collect();
vector.sort_by(|a, b| b.cmp(a));
vector.iter().take(3).sum()
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "1000
2000
3000
4000
5000
6000
7000
8000
9000
10000";
#[test]
fn it_works() {
let result = process_part1(INPUT);
assert_eq!(result, 24000);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 45000);
}
}

106
y2022/src/days/d2.rs Normal file
View File

@@ -0,0 +1,106 @@
pub fn process_part1(input: &str) -> i32 {
let result = input
.lines()
.map(|round| {
let (opponent_move, my_move) = round.split_once(" ").unwrap();
get_points(opponent_move, my_move)
})
.sum();
result
}
fn get_points(opponent_move: &str, my_move: &str) -> i32 {
let mut round_score = 0;
match my_move {
"X" => {
round_score += 1;
match opponent_move {
"C" => round_score += 6,
"A" => round_score += 3,
_ => (),
}
}
"Y" => {
round_score += 2;
match opponent_move {
"A" => round_score += 6,
"B" => round_score += 3,
_ => (),
}
}
"Z" => {
round_score += 3;
match opponent_move {
"B" => round_score += 6,
"C" => round_score += 3,
_ => (),
}
}
_ => panic!("Shouldn't happen"),
}
round_score
}
pub fn process_part2(input: &str) -> i32 {
let result = input
.lines()
.map(|round| {
let (opponent_move, round_result) = round.split_once(" ").unwrap();
get_points_fixed(opponent_move, round_result)
})
.sum();
result
}
fn get_points_fixed(opponent_move: &str, round_result: &str) -> i32 {
let mut round_score = 0;
match round_result {
"X" => match opponent_move {
"A" => round_score += 3,
"B" => round_score += 1,
"C" => round_score += 2,
_ => (),
},
"Y" => {
round_score += 3;
match opponent_move {
"A" => round_score += 1,
"B" => round_score += 2,
"C" => round_score += 3,
_ => (),
}
}
"Z" => {
round_score += 6;
match opponent_move {
"A" => round_score += 2,
"B" => round_score += 3,
"C" => round_score += 1,
_ => (),
}
}
_ => panic!("Shouldn't happen"),
}
round_score
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "A Y
B X
C Z";
#[test]
fn it_works() {
let result = process_part1(INPUT);
assert_eq!(result, 15);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 12);
}
}

68
y2022/src/days/d3.rs Normal file
View File

@@ -0,0 +1,68 @@
fn char_to_prio(char: char) -> i32 {
let ascii = char as i32;
match ascii {
65..=90 => ascii - 38,
97..=122 => ascii - 96,
_ => panic!("Shouldn't happen"),
}
}
pub fn process_part1(input: &str) -> i32 {
input
.lines()
.map(|line| {
let (first, second) = line.split_at(line.len() / 2);
let mut prio = 0;
for first_char in first.chars() {
let found_char = second
.chars()
.find(|second_char| second_char.eq(&first_char));
if let Some(char) = found_char {
prio = char_to_prio(char);
break;
}
}
prio
})
.sum()
}
pub fn process_part2(input: &str) -> i32 {
let mut lines = input.lines();
let mut result = 0;
while let Some(elf_1) = lines.next() {
let elf_2 = lines.next().unwrap();
let elf_3 = lines.next().unwrap();
for elf_1_char in elf_1.chars() {
if elf_2.contains(elf_1_char) && elf_3.contains(elf_1_char) {
result += char_to_prio(elf_1_char);
break;
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, 157);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 70);
}
}

79
y2022/src/days/d4.rs Normal file
View File

@@ -0,0 +1,79 @@
pub fn process_part1(input: &str) -> i32 {
let result = input
.lines()
.map(|line| {
let (elf1, elf2) = line.split_once(",").unwrap();
let elf1 = elf1
.split_once("-")
.map(|(start, end)| start.parse::<i32>().unwrap()..=end.parse::<i32>().unwrap())
.unwrap();
let elf2 = elf2
.split_once("-")
.map(|(start, end)| start.parse::<i32>().unwrap()..=end.parse::<i32>().unwrap())
.unwrap();
if (elf1.contains(elf2.start()) && elf1.contains(elf2.end()))
|| (elf2.contains(elf1.start()) && elf2.contains(elf1.end()))
{
return 1;
}
0
})
.sum();
result
}
pub fn process_part2(input: &str) -> i32 {
let result = input
.lines()
.map(|line| {
let (elf1, elf2) = line.split_once(",").unwrap();
let elf1 = elf1
.split_once("-")
.map(|(start, end)| start.parse::<i32>().unwrap()..=end.parse::<i32>().unwrap())
.unwrap();
let elf2 = elf2
.split_once("-")
.map(|(start, end)| start.parse::<i32>().unwrap()..=end.parse::<i32>().unwrap())
.unwrap();
if elf1.contains(elf2.start())
|| elf1.contains(elf2.end())
|| elf2.contains(elf1.start())
|| elf2.contains(elf1.end())
{
return 1;
}
0
})
.sum();
result
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, 2);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 4);
}
}

110
y2022/src/days/d5.rs Normal file
View File

@@ -0,0 +1,110 @@
fn is_string_numeric(str: &str) -> bool {
for c in str.chars() {
if !c.is_numeric() {
return false;
}
}
true
}
fn parse_move(crane_move: &str) -> (usize, usize, usize) {
let mut crane_move = crane_move
.split(" ")
.filter(|s| is_string_numeric(s))
.map(|m| m.parse::<usize>().unwrap());
(
crane_move.next().unwrap(),
crane_move.next().unwrap() - 1,
crane_move.next().unwrap() - 1,
)
}
fn parse_moves(crane_moves: &str) -> Vec<(usize, usize, usize)> {
crane_moves.lines().map(parse_move).collect()
}
fn parse_stacks(stacks: &str) -> Vec<String> {
let mut lines: Vec<&str> = stacks.lines().collect();
let mut last_line = lines.pop().unwrap().trim().to_string();
let num_stacks = last_line.pop().unwrap().to_digit(10).unwrap();
let mut parsed_stacks = vec!["".to_string(); num_stacks as usize];
for line in lines {
for (idx, c) in line.chars().skip(1).step_by(4).enumerate() {
if c.is_alphabetic() {
parsed_stacks[idx].insert(0, c);
}
}
}
parsed_stacks
}
pub fn process_part1(input: &str) -> String {
let (stacks, crane_moves) = input.split_once("\n\n").unwrap();
let mut stacks = parse_stacks(stacks);
let crane_moves = parse_moves(crane_moves);
for (iterations, from, to) in crane_moves {
for _i in 0..iterations {
let popped = stacks[from].pop().unwrap();
stacks[to].push(popped);
}
}
let mut result = "".to_string();
for mut stack in stacks {
result.push(stack.pop().unwrap());
}
result
}
pub fn process_part2(input: &str) -> String {
let (stacks, crane_moves) = input.split_once("\n\n").unwrap();
let mut stacks = parse_stacks(stacks);
let crane_moves = parse_moves(crane_moves);
for (iterations, from, to) in crane_moves {
let from_len = stacks[from].len();
let from_old = stacks[from].clone();
let (new_from, popped) = from_old.split_at(from_len - iterations);
stacks[from] = new_from.to_string();
stacks[to].push_str(popped);
}
let mut result = "".to_string();
for mut stack in stacks {
result.push(stack.pop().unwrap());
}
result
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = " [D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, "CMZ");
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, "MCD");
}
}

68
y2022/src/days/d6.rs Normal file
View File

@@ -0,0 +1,68 @@
pub fn process_part1(input: &str) -> i32 {
let mut marker = "".to_string();
for (idx, c) in input.chars().enumerate() {
if marker.len() == 4 {
return (idx).try_into().unwrap();
}
if let Some(c_pos) = marker.find(c) {
let (_, new_marker) = marker.split_at(c_pos + 1);
marker = new_marker.to_string();
}
marker.push(c);
}
0
}
pub fn process_part2(input: &str) -> i32 {
let mut marker = "".to_string();
for (idx, c) in input.chars().enumerate() {
if marker.len() == 14 {
return (idx).try_into().unwrap();
}
if let Some(c_pos) = marker.find(c) {
let (_, new_marker) = marker.split_at(c_pos + 1);
marker = new_marker.to_string();
}
marker.push(c);
}
0
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT1: &str = "mjqjpqmgbljsphdztnvjfqwrcgsmlb";
const INPUT2: &str = "bvwbjplbgvbhsrlpgdmjqwftvncz";
const INPUT3: &str = "nppdvjthqldpwncqszvftbrmjlhg";
const INPUT4: &str = "nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg";
const INPUT5: &str = "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw";
#[test]
fn part1() {
let result = process_part1(INPUT1);
assert_eq!(result, 7);
let result = process_part1(INPUT2);
assert_eq!(result, 5);
let result = process_part1(INPUT3);
assert_eq!(result, 6);
let result = process_part1(INPUT4);
assert_eq!(result, 10);
let result = process_part1(INPUT5);
assert_eq!(result, 11);
}
#[test]
fn part2() {
let result = process_part2(INPUT1);
assert_eq!(result, 19);
let result = process_part2(INPUT2);
assert_eq!(result, 23);
let result = process_part2(INPUT3);
assert_eq!(result, 23);
let result = process_part2(INPUT4);
assert_eq!(result, 29);
let result = process_part2(INPUT5);
assert_eq!(result, 26);
}
}

200
y2022/src/days/d7.rs Normal file
View File

@@ -0,0 +1,200 @@
use std::collections::HashMap;
#[derive(Clone, Debug)]
struct Directory {
size: i64,
children: Vec<String>,
}
fn get_size(dir: Directory, directories: HashMap<String, Directory>) -> i64 {
let mut size = dir.size;
if !dir.children.is_empty() {
size += dir
.children
.iter()
.map(|child_name| {
if let Some((_dir_name, child_dir)) = directories.get_key_value(child_name) {
return get_size(child_dir.clone(), directories.clone());
}
0
})
.sum::<i64>();
}
size
}
pub fn process_part1(input: &str) -> i64 {
let mut pwd = String::from("");
let mut directories: HashMap<String, Directory> = HashMap::new();
let lines: Vec<Vec<&str>> = input
.lines()
.map(|line| line.split_whitespace().collect::<Vec<&str>>())
.collect();
for line in lines {
if line[0] == "$" {
if line[1] == "cd" {
let arg = line[2].to_string();
match arg.as_str() {
"/" => pwd = arg,
".." => match pwd.as_str() {
"/" => println!("Already at root"),
_ => pwd.truncate(pwd.rfind("/").unwrap()),
},
_ => match pwd.as_str() {
"/" => pwd.push_str(&arg),
_ => pwd.push_str(&("/".to_owned() + &arg)),
},
}
if !directories.contains_key(&pwd) {
directories.insert(
pwd.clone(),
Directory {
size: 0,
children: vec![],
},
);
}
}
} else if line[0] == "dir" {
if let Some((dir_name, dir)) = directories.get_key_value(&pwd) {
let mut new_children = dir.children.clone();
let mut new_child = "/".to_owned() + line[1];
if pwd != *"/" {
new_child.insert_str(0, &pwd);
}
new_children.push(new_child);
let new_dir = Directory {
size: dir.size,
children: new_children,
};
directories.insert(dir_name.to_string(), new_dir);
}
} else if line[0] != "dir" {
if let Some((dir_name, dir)) = directories.get_key_value(&pwd) {
let new_dir = Directory {
size: dir.size + line[0].parse::<i64>().unwrap(),
children: dir.children.clone(),
};
directories.insert(dir_name.to_string(), new_dir);
}
}
}
let sizes = directories
.values()
.map(|directory| get_size(directory.clone(), directories.clone()));
sizes.filter(|size| size <= &100000).sum()
}
pub fn process_part2(input: &str) -> i64 {
const TOTAL: i64 = 70000000;
const MIN_UNUSED: i64 = 30000000;
let mut pwd = String::from("");
let mut directories: HashMap<String, Directory> = HashMap::new();
let lines: Vec<Vec<&str>> = input
.lines()
.map(|line| line.split_whitespace().collect::<Vec<&str>>())
.collect();
for line in lines {
if line[0] == "$" {
if line[1] == "cd" {
let arg = line[2].to_string();
match arg.as_str() {
"/" => pwd = arg,
".." => match pwd.as_str() {
"/" => println!("Already at root"),
_ => pwd.truncate(pwd.rfind("/").unwrap()),
},
_ => match pwd.as_str() {
"/" => pwd.push_str(&arg),
_ => pwd.push_str(&("/".to_owned() + &arg)),
},
}
if !directories.contains_key(&pwd) {
directories.insert(
pwd.clone(),
Directory {
size: 0,
children: vec![],
},
);
}
}
} else if line[0] == "dir" {
if let Some((dir_name, dir)) = directories.get_key_value(&pwd) {
let mut new_children = dir.children.clone();
let mut new_child = "/".to_owned() + line[1];
if pwd != *"/" {
new_child.insert_str(0, &pwd);
}
new_children.push(new_child);
let new_dir = Directory {
size: dir.size,
children: new_children,
};
directories.insert(dir_name.to_string(), new_dir);
}
} else if line[0] != "dir" {
if let Some((dir_name, dir)) = directories.get_key_value(&pwd) {
let new_dir = Directory {
size: dir.size + line[0].parse::<i64>().unwrap(),
children: dir.children.clone(),
};
directories.insert(dir_name.to_string(), new_dir);
}
}
}
let sizes = directories
.values()
.map(|directory| get_size(directory.clone(), directories.clone()));
let unused = TOTAL - sizes.clone().max().unwrap();
let mut sizes = sizes.collect::<Vec<i64>>();
sizes.sort();
for size in sizes {
if size >= (MIN_UNUSED - unused) {
return size;
}
}
0
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, 95437);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 24933642);
}
}

125
y2022/src/days/d8.rs Normal file
View File

@@ -0,0 +1,125 @@
use std::collections::HashSet;
fn is_visible_from_line(tree_line: Vec<u32>, tree_height: u32) -> bool {
for &tree in tree_line.iter() {
if tree >= tree_height {
return false;
}
}
true
}
fn is_tree_visible(tree_grid: Vec<Vec<u32>>, tree_pos: (usize, usize), tree_height: u32) -> bool {
let horizontal_line = tree_grid[tree_pos.0].clone();
let vertical_line: Vec<u32> = tree_grid
.iter()
.map(|horizontal_line| horizontal_line[tree_pos.1])
.collect();
let (left, right) = vertical_line.split_at(tree_pos.0);
let (top, bottom) = horizontal_line.split_at(tree_pos.1);
is_visible_from_line(left.to_vec(), tree_height)
|| is_visible_from_line(right[1..].to_vec(), tree_height)
|| is_visible_from_line(top.to_vec(), tree_height)
|| is_visible_from_line(bottom[1..].to_vec(), tree_height)
}
pub fn process_part1(input: &str) -> u32 {
let tree_grid = input
.lines()
.map(|line| {
line.chars()
.map(|char| char.to_digit(10).unwrap())
.collect()
})
.collect::<Vec<Vec<u32>>>();
let dimension = (tree_grid.len(), tree_grid[0].len());
let outer_trees = (dimension.0 as u32 * 2) + (dimension.1 as u32 * 2) - 4;
let mut visible_trees: HashSet<(usize, usize)> = HashSet::new();
for x in 1..dimension.0 - 1 {
for y in 1..dimension.1 - 1 {
if is_tree_visible(tree_grid.clone(), (x, y), tree_grid[x][y]) {
visible_trees.insert((x, y));
}
}
}
outer_trees + visible_trees.len() as u32
}
fn seeing_distance(tree_line: Vec<u32>, tree_height: u32) -> u32 {
let mut count = 0;
for tree in tree_line {
count += 1;
if tree >= tree_height {
break;
}
}
count
}
fn calc_score(tree_grid: Vec<Vec<u32>>, tree_pos: (usize, usize), tree_height: u32) -> u32 {
let horizontal_line = tree_grid[tree_pos.0].clone();
let vertical_line: Vec<u32> = tree_grid
.iter()
.map(|horizontal_line| horizontal_line[tree_pos.1])
.collect();
let (left, right) = vertical_line.split_at(tree_pos.0);
let mut left = left.to_vec();
left.reverse();
let (top, bottom) = horizontal_line.split_at(tree_pos.1);
let mut top = top.to_vec();
top.reverse();
seeing_distance(left.to_vec(), tree_height)
* seeing_distance(right[1..].to_vec(), tree_height)
* seeing_distance(top.to_vec(), tree_height)
* seeing_distance(bottom[1..].to_vec(), tree_height)
}
pub fn process_part2(input: &str) -> u32 {
let tree_grid = input
.lines()
.map(|line| {
line.chars()
.map(|char| char.to_digit(10).unwrap())
.collect()
})
.collect::<Vec<Vec<u32>>>();
let dimension = (tree_grid.len(), tree_grid[0].len());
let mut highest_score = 0;
for x in 1..dimension.0 - 1 {
for y in 1..dimension.1 - 1 {
if is_tree_visible(tree_grid.clone(), (x, y), tree_grid[x][y]) {
let score = calc_score(tree_grid.clone(), (x, y), tree_grid[x][y]);
if score > highest_score {
highest_score = score;
}
}
}
}
highest_score
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "30373
25512
65332
33549
35390
";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, 21);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 8);
}
}

229
y2022/src/days/d9.rs Normal file
View File

@@ -0,0 +1,229 @@
use std::collections::HashSet;
#[derive(Clone, Copy, Debug)]
enum Move {
Up(i32),
Down(i32),
Left(i32),
Right(i32),
}
#[derive(Clone)]
struct Position {
head: (i32, i32),
tail: (i32, i32),
visited_positions: HashSet<(i32, i32)>,
}
impl Position {
fn new() -> Position {
Position {
head: (0, 0),
tail: (0, 0),
visited_positions: HashSet::from([(0, 0)]),
}
}
fn is_touching(&self) -> bool {
if self.head == self.tail {
return true;
}
if self.head.0.abs_diff(self.tail.0) <= 1 && self.head.1.abs_diff(self.tail.1) <= 1 {
return true;
}
false
}
fn update(&mut self, movement: Move) {
match movement {
Move::Up(distance) => {
for _ in 1..=distance {
self.step(Move::Up(1));
}
}
Move::Down(distance) => {
for _ in 1..=distance {
self.step(Move::Down(1));
}
}
Move::Left(distance) => {
for _ in 1..=distance {
self.step(Move::Left(1));
}
}
Move::Right(distance) => {
for _ in 1..=distance {
self.step(Move::Right(1));
}
}
}
}
fn square(a: i32) -> i32 {
a * a
}
fn get_distance(point_a: (i32, i32), point_b: (i32, i32)) -> f64 {
(Self::square(point_b.0 - point_a.0) as f64 + Self::square(point_b.1 - point_a.1) as f64)
.sqrt()
}
fn move_tail(&mut self, movement: Move) {
let big_distance = Self::get_distance(self.head, self.tail) > 2f64.sqrt();
if !&self.is_touching() {
match movement {
Move::Up(_) => {
self.tail.0 = self.head.0 - 1;
if big_distance {
self.tail.1 -= 1;
} else {
self.tail.1 = self.head.1;
}
}
Move::Down(_) => {
self.tail.0 = self.head.0 + 1;
if big_distance {
self.tail.1 += 1;
} else {
self.tail.1 = self.head.1;
}
}
Move::Left(_) => {
self.tail.1 = self.head.1 + 1;
if big_distance {
self.tail.0 += 1;
} else {
self.tail.0 = self.head.0;
}
}
Move::Right(_) => {
self.tail.1 = self.head.1 - 1;
if big_distance {
self.tail.0 -= 1;
} else {
self.tail.0 = self.head.0;
}
}
}
}
self.visited_positions.insert(self.tail);
}
fn step(&mut self, movement: Move) {
match movement {
Move::Up(distance) => self.head.0 += distance,
Move::Down(distance) => self.head.0 -= distance,
Move::Left(distance) => self.head.1 -= distance,
Move::Right(distance) => self.head.1 += distance,
}
self.move_tail(movement);
}
}
fn parse_line(line: &str) -> Move {
let mut line = line.split_whitespace();
let direction = line.next();
let distance = line.next().unwrap().parse::<i32>().unwrap();
match direction {
Some("U") => Move::Up(distance),
Some("D") => Move::Down(distance),
Some("L") => Move::Left(distance),
Some("R") => Move::Right(distance),
_ => panic!("Shouldn_t happen"),
}
}
pub fn process_part1(input: &str) -> usize {
let mut position = Position {
head: (0, 0),
tail: (0, 0),
visited_positions: HashSet::from([(0, 0)]),
};
let moves = input.lines().map(parse_line);
for movement in moves {
position.update(movement);
}
position.visited_positions.len()
}
pub fn process_part2(input: &str) -> usize {
let mut positions = vec![Position::new(); 10];
let moves = input.lines().map(parse_line);
for movement in moves {
let mut steps = 0;
if let Move::Up(distance) = movement {
steps = distance;
} else if let Move::Down(distance) = movement {
steps = distance;
} else if let Move::Left(distance) = movement {
steps = distance;
} else if let Move::Right(distance) = movement {
steps = distance;
}
for _ in 0..steps {
for (idx, position) in positions.clone().iter().enumerate() {
let mut position = position.clone();
if idx == 0 {
match movement {
Move::Up(_) => {
position.step(Move::Up(1));
}
Move::Down(_) => {
position.step(Move::Down(1));
}
Move::Left(_) => {
position.step(Move::Left(1));
}
Move::Right(_) => {
position.step(Move::Right(1));
}
}
println!("head: {:?}", position.head)
} else {
position.head = positions[idx - 1].tail;
position.move_tail(movement);
println!("knot nr{}: {:?}", idx, position.head);
}
if idx == 9 {
println!("tail: {:?}", position.tail)
}
positions[idx] = position;
}
}
}
positions[9].visited_positions.len()
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT1: &str = "R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2";
const INPUT2: &str = "R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20";
#[test]
fn part1() {
let result = process_part1(INPUT1);
assert_eq!(result, 13);
}
#[test]
fn part2() {
let result = process_part2(INPUT2);
assert_eq!(result, 36);
}
}

9
y2022/src/days/mod.rs Normal file
View File

@@ -0,0 +1,9 @@
pub mod d1;
pub mod d2;
pub mod d3;
pub mod d4;
pub mod d5;
pub mod d6;
pub mod d7;
pub mod d8;
pub mod d9;

1
y2022/src/lib.rs Normal file
View File

@@ -0,0 +1 @@
pub mod days;