Refactoring
This commit is contained in:
		
							parent
							
								
									ae19a80e72
								
							
						
					
					
						commit
						0f30709aa8
					
				
					 12 changed files with 370 additions and 344 deletions
				
			
		| 
						 | 
				
			
			@ -3,18 +3,17 @@ use std::fs;
 | 
			
		|||
pub fn solve() {
 | 
			
		||||
    let path = "res/01/input.txt";
 | 
			
		||||
 | 
			
		||||
    let contents = fs::read_to_string(path)
 | 
			
		||||
        .expect("Should have been able to read the file");
 | 
			
		||||
    let contents = fs::read_to_string(path).expect("Should have been able to read the file");
 | 
			
		||||
 | 
			
		||||
    let cont_arr = contents.split("\n");
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    let mut calories = Vec::<i32>::new();
 | 
			
		||||
    calories.push(0);
 | 
			
		||||
 | 
			
		||||
    let mut index = 0;
 | 
			
		||||
    cont_arr.into_iter().for_each(|i| {
 | 
			
		||||
        if i == "" {
 | 
			
		||||
            index+=1;
 | 
			
		||||
            index += 1;
 | 
			
		||||
            calories.push(0);
 | 
			
		||||
        } else {
 | 
			
		||||
            calories[index] += i.parse::<i32>().unwrap();
 | 
			
		||||
| 
						 | 
				
			
			@ -34,5 +33,5 @@ pub fn solve() {
 | 
			
		|||
 | 
			
		||||
    let res3: i32 = calories.clone().into_iter().rev().take(3).sum();
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {}", res3); 
 | 
			
		||||
}
 | 
			
		||||
    println!("Result 2: {}", res3);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,6 @@ pub fn solve() {
 | 
			
		|||
    println!("Result 2: {}", res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Finds 1st occurence of l unique characters in chars and returns
 | 
			
		||||
// the index of the last of them or -1
 | 
			
		||||
fn find_marker(l: usize, chars: &Vec<char>) -> i32 {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,11 +36,12 @@ fn find_marker(l: usize, chars: &Vec<char>) -> i32 {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn _find_marker_v2(l: usize, chars: &Vec<char>) -> usize {
 | 
			
		||||
    chars.iter()
 | 
			
		||||
    chars
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter(|c| **c != '\n')
 | 
			
		||||
        .collect::<Vec<&char>>()
 | 
			
		||||
        .windows(l)
 | 
			
		||||
        .position(|window| window.iter().collect::<HashSet<_>>().len() == l)
 | 
			
		||||
        .map(|pos| pos+l)
 | 
			
		||||
        .map(|pos| pos + l)
 | 
			
		||||
        .unwrap()
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
use std::{fs, collections::HashMap};
 | 
			
		||||
use std::{collections::HashMap, fs};
 | 
			
		||||
 | 
			
		||||
pub fn solve() {
 | 
			
		||||
    let path = "res/07/input.txt";
 | 
			
		||||
| 
						 | 
				
			
			@ -13,22 +13,28 @@ pub fn solve() {
 | 
			
		|||
    let mut path = Vec::<&str>::new();
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
        .for_each(|line| {
 | 
			
		||||
            let words = line.split(" ").collect::<Vec<&str>>();
 | 
			
		||||
            if line.starts_with("dir ") { } // ignore
 | 
			
		||||
            else if line.starts_with("$ ls") { } // ignore
 | 
			
		||||
            else if line.starts_with("$ cd ..") { // go folder up by deleting deepest folder
 | 
			
		||||
            if line.starts_with("dir ") {
 | 
			
		||||
            }
 | 
			
		||||
            // ignore
 | 
			
		||||
            else if line.starts_with("$ ls") {
 | 
			
		||||
            }
 | 
			
		||||
            // ignore
 | 
			
		||||
            else if line.starts_with("$ cd ..") {
 | 
			
		||||
                // go folder up by deleting deepest folder
 | 
			
		||||
                path.pop();
 | 
			
		||||
            }
 | 
			
		||||
            else if line.starts_with("$ cd") { // add new folder to path
 | 
			
		||||
            } else if line.starts_with("$ cd") {
 | 
			
		||||
                // add new folder to path
 | 
			
		||||
                path.push(words[2])
 | 
			
		||||
            }
 | 
			
		||||
            else { // file, add filesize to current and all parent paths
 | 
			
		||||
            } else {
 | 
			
		||||
                // file, add filesize to current and all parent paths
 | 
			
		||||
                let size = words[0].parse::<i32>().unwrap();
 | 
			
		||||
                for i in 0..path.len() {
 | 
			
		||||
                    let current_path = path[0..i+1].join("/");
 | 
			
		||||
                    let current_path = path[0..i + 1].join("/");
 | 
			
		||||
                    if paths.contains_key(¤t_path) {
 | 
			
		||||
                        *paths.get_mut(¤t_path).unwrap() += size;
 | 
			
		||||
                    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,10 +42,11 @@ pub fn solve() {
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    // Sum of all paths lower than 100000 is result
 | 
			
		||||
    let res = paths.iter()
 | 
			
		||||
    let res = paths
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|pair| *pair.1)
 | 
			
		||||
        .filter(|size| *size <= 100000)
 | 
			
		||||
        .sum::<i32>();
 | 
			
		||||
| 
						 | 
				
			
			@ -51,10 +58,12 @@ pub fn solve() {
 | 
			
		|||
    let min_to_delete = 30000000 - (70000000 - space_occupied);
 | 
			
		||||
 | 
			
		||||
    // Find min folder size higher-or-equal to min_to_delete
 | 
			
		||||
    let res = paths.iter()
 | 
			
		||||
    let res = paths
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|pair| *pair.1)
 | 
			
		||||
        .filter(|size| *size >= min_to_delete)
 | 
			
		||||
        .min().unwrap();
 | 
			
		||||
    
 | 
			
		||||
        println!("Result 2: {}", res)
 | 
			
		||||
}
 | 
			
		||||
        .min()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {}", res)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										123
									
								
								src/days/d08.rs
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								src/days/d08.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -8,25 +8,26 @@ pub fn solve() {
 | 
			
		|||
    let cont_arr = contents.lines().collect::<Vec<&str>>();
 | 
			
		||||
 | 
			
		||||
    // 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 != "")
 | 
			
		||||
        .map(|line| 
 | 
			
		||||
            line.chars().collect::<Vec<char>>()
 | 
			
		||||
            .iter().map(|t| return t.to_digit(10).unwrap() as i32)
 | 
			
		||||
            .collect()
 | 
			
		||||
        ).collect();
 | 
			
		||||
        .map(|line| {
 | 
			
		||||
            line.chars()
 | 
			
		||||
                .collect::<Vec<char>>()
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|t| return t.to_digit(10).unwrap() as i32)
 | 
			
		||||
                .collect()
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let width = trees[0].len();
 | 
			
		||||
    let height = trees.len();
 | 
			
		||||
 | 
			
		||||
    // task 1
 | 
			
		||||
    // initialize visibilities with 0
 | 
			
		||||
    let mut visibilities: Vec<Vec<i32>> = (0..height).map(|_| {
 | 
			
		||||
        (0..width).map(|_| 0).collect()
 | 
			
		||||
    }).collect();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    let mut visibilities: Vec<Vec<i32>> = (0..height)
 | 
			
		||||
        .map(|_| (0..width).map(|_| 0).collect())
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    // mark visible trees with 1
 | 
			
		||||
    // left to right & right to left
 | 
			
		||||
| 
						 | 
				
			
			@ -39,11 +40,10 @@ pub fn solve() {
 | 
			
		|||
                visibilities[i][j] = 1;
 | 
			
		||||
                last_max_left = trees[i][j];
 | 
			
		||||
            }
 | 
			
		||||
            if trees[i][width-j-1] > last_max_right {
 | 
			
		||||
                visibilities[i][width-j-1] = 1;
 | 
			
		||||
                last_max_right = trees[i][width-j-1];
 | 
			
		||||
            } 
 | 
			
		||||
            
 | 
			
		||||
            if trees[i][width - j - 1] > last_max_right {
 | 
			
		||||
                visibilities[i][width - j - 1] = 1;
 | 
			
		||||
                last_max_right = trees[i][width - j - 1];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,58 +57,71 @@ pub fn solve() {
 | 
			
		|||
                visibilities[j][i] = 1;
 | 
			
		||||
                last_max_top = trees[j][i];
 | 
			
		||||
            }
 | 
			
		||||
            if trees[width-j-1][i] > last_max_bot {
 | 
			
		||||
                visibilities[height-j-1][i] = 1;
 | 
			
		||||
                last_max_bot = trees[height-j-1][i];
 | 
			
		||||
            } 
 | 
			
		||||
            
 | 
			
		||||
            if trees[width - j - 1][i] > last_max_bot {
 | 
			
		||||
                visibilities[height - j - 1][i] = 1;
 | 
			
		||||
                last_max_bot = trees[height - j - 1][i];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // sum all visible trees
 | 
			
		||||
    let res = visibilities.iter()
 | 
			
		||||
    let res = visibilities
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|line| line.iter().sum::<i32>())
 | 
			
		||||
        .sum::<i32>();
 | 
			
		||||
 | 
			
		||||
    println!("Result 1: {}", res);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // task 2
 | 
			
		||||
    let scenic_scores: Vec<Vec<i32>> = (0..height).map(|i| {
 | 
			
		||||
        (0..width).map(|j| {
 | 
			
		||||
            // calculate view range in each direction
 | 
			
		||||
            let mut to_top = 0;
 | 
			
		||||
            for k in (0..i).rev() {
 | 
			
		||||
                to_top += 1;
 | 
			
		||||
                if trees[k][j] >= trees[i][j] { break; }
 | 
			
		||||
            }
 | 
			
		||||
    let scenic_scores: Vec<Vec<i32>> = (0..height)
 | 
			
		||||
        .map(|i| {
 | 
			
		||||
            (0..width)
 | 
			
		||||
                .map(|j| {
 | 
			
		||||
                    // calculate view range in each direction
 | 
			
		||||
                    let mut to_top = 0;
 | 
			
		||||
                    for k in (0..i).rev() {
 | 
			
		||||
                        to_top += 1;
 | 
			
		||||
                        if trees[k][j] >= trees[i][j] {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
            let mut to_bot = 0;
 | 
			
		||||
            for k in i+1..height {
 | 
			
		||||
                to_bot += 1;
 | 
			
		||||
                if trees[k][j] >= trees[i][j] { break; }
 | 
			
		||||
            }
 | 
			
		||||
                    let mut to_bot = 0;
 | 
			
		||||
                    for k in i + 1..height {
 | 
			
		||||
                        to_bot += 1;
 | 
			
		||||
                        if trees[k][j] >= trees[i][j] {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
            let mut to_left = 0;
 | 
			
		||||
            for k in (0..j).rev() {
 | 
			
		||||
                to_left += 1;
 | 
			
		||||
                if trees[i][k] >= trees[i][j] { break; }
 | 
			
		||||
            }
 | 
			
		||||
                    let mut to_left = 0;
 | 
			
		||||
                    for k in (0..j).rev() {
 | 
			
		||||
                        to_left += 1;
 | 
			
		||||
                        if trees[i][k] >= trees[i][j] {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
            let mut to_right = 0;
 | 
			
		||||
            for k in j+1..width {
 | 
			
		||||
                to_right += 1;
 | 
			
		||||
                if trees[i][k] >= trees[i][j] { break; }
 | 
			
		||||
            }
 | 
			
		||||
                    let mut to_right = 0;
 | 
			
		||||
                    for k in j + 1..width {
 | 
			
		||||
                        to_right += 1;
 | 
			
		||||
                        if trees[i][k] >= trees[i][j] {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    to_top * to_bot * to_left * to_right
 | 
			
		||||
                })
 | 
			
		||||
                .collect()
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
            to_top*to_bot*to_left*to_right
 | 
			
		||||
        }).collect()
 | 
			
		||||
    }).collect();
 | 
			
		||||
    
 | 
			
		||||
    // find max scenic score
 | 
			
		||||
    let res = scenic_scores.iter()
 | 
			
		||||
    let res = scenic_scores
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|line| line.iter().max().unwrap())
 | 
			
		||||
        .max().unwrap();
 | 
			
		||||
    
 | 
			
		||||
        .max()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {}", res)
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,16 +5,12 @@ const GRID_HEIGHT: i32 = 1000;
 | 
			
		|||
const START_X: i32 = 500;
 | 
			
		||||
const START_Y: i32 = 500;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub fn solve() {
 | 
			
		||||
    let path = "res/09/input.txt";
 | 
			
		||||
 | 
			
		||||
    let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
 | 
			
		||||
 | 
			
		||||
    let lines: Vec<&str> = contents
 | 
			
		||||
        .lines()
 | 
			
		||||
        .filter(|line| *line != "")
 | 
			
		||||
        .collect();
 | 
			
		||||
    let lines: Vec<&str> = contents.lines().filter(|line| *line != "").collect();
 | 
			
		||||
 | 
			
		||||
    // task 1 - rope with 2 knots
 | 
			
		||||
    let mut rope2 = Rope::new(2);
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +26,7 @@ pub fn solve() {
 | 
			
		|||
            "D" => Dir::Down,
 | 
			
		||||
            "L" => Dir::Left,
 | 
			
		||||
            "R" => Dir::Right,
 | 
			
		||||
            _ => Dir::Up
 | 
			
		||||
            _ => Dir::Up,
 | 
			
		||||
        };
 | 
			
		||||
        let amount = cmd[1].parse::<i32>().unwrap();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,9 +44,6 @@ pub fn solve() {
 | 
			
		|||
    // task 2 res
 | 
			
		||||
    let res = rope10.tail_visited_num();
 | 
			
		||||
    println!("Result 1: {}", res);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Copy, Clone)]
 | 
			
		||||
| 
						 | 
				
			
			@ -58,13 +51,13 @@ enum Dir {
 | 
			
		|||
    Up,
 | 
			
		||||
    Down,
 | 
			
		||||
    Left,
 | 
			
		||||
    Right
 | 
			
		||||
    Right,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Rope {
 | 
			
		||||
    knots_x: Vec<i32>,
 | 
			
		||||
    knots_y: Vec<i32>,
 | 
			
		||||
    tail_visited_grid: Vec<Vec<bool>> // [Y][X]
 | 
			
		||||
    tail_visited_grid: Vec<Vec<bool>>, // [Y][X]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Rope {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,27 +66,18 @@ impl Rope {
 | 
			
		|||
            knots_x: (0..knots).map(|_| START_X).collect(),
 | 
			
		||||
            knots_y: (0..knots).map(|_| START_Y).collect(),
 | 
			
		||||
            tail_visited_grid: (0..GRID_HEIGHT)
 | 
			
		||||
                .map(|_| (0..GRID_WIDTH)
 | 
			
		||||
                    .map(|_| false).collect()
 | 
			
		||||
                ).collect()
 | 
			
		||||
                .map(|_| (0..GRID_WIDTH).map(|_| false).collect())
 | 
			
		||||
                .collect(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // move head (first knot)
 | 
			
		||||
    pub fn mv(&mut self, dir: Dir) {
 | 
			
		||||
        match dir {
 | 
			
		||||
            Dir::Up => {
 | 
			
		||||
                self.knots_y[0] -= 1
 | 
			
		||||
            },
 | 
			
		||||
            Dir::Down => {
 | 
			
		||||
                self.knots_y[0] += 1
 | 
			
		||||
            },
 | 
			
		||||
            Dir::Left => {
 | 
			
		||||
                self.knots_x[0] -= 1
 | 
			
		||||
            },
 | 
			
		||||
            Dir::Right => {
 | 
			
		||||
                self.knots_x[0] += 1
 | 
			
		||||
            }
 | 
			
		||||
            Dir::Up => self.knots_y[0] -= 1,
 | 
			
		||||
            Dir::Down => self.knots_y[0] += 1,
 | 
			
		||||
            Dir::Left => self.knots_x[0] -= 1,
 | 
			
		||||
            Dir::Right => self.knots_x[0] += 1,
 | 
			
		||||
        }
 | 
			
		||||
        self.check_tail_pos()
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -102,42 +86,49 @@ impl Rope {
 | 
			
		|||
    fn check_tail_pos(&mut self) {
 | 
			
		||||
        // check pos of each knot except first
 | 
			
		||||
        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)
 | 
			
		||||
                    || (self.knots_y[i-1] == self.knots_y[i] && (self.knots_x[i-1] - self.knots_x[i]).abs() == 1) {
 | 
			
		||||
            if (self.knots_x[i - 1] == self.knots_x[i]
 | 
			
		||||
                && (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
 | 
			
		||||
            } 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
 | 
			
		||||
            } else {
 | 
			
		||||
                // 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
 | 
			
		||||
                    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_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]);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Move vertically/horizontally
 | 
			
		||||
                    if self.knots_x[i-1] == self.knots_x[i] {
 | 
			
		||||
                        self.knots_y[i] += normalize(self.knots_y[i-1] - self.knots_y[i]);
 | 
			
		||||
                    if self.knots_x[i - 1] == self.knots_x[i] {
 | 
			
		||||
                        self.knots_y[i] += normalize(self.knots_y[i - 1] - self.knots_y[i]);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        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]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
    pub fn tail_visited_num(&self) -> i32 {
 | 
			
		||||
        self.tail_visited_grid.iter()
 | 
			
		||||
            .map(|row| 
 | 
			
		||||
        self.tail_visited_grid
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(|row| {
 | 
			
		||||
                row.iter()
 | 
			
		||||
                .map(|cell| 
 | 
			
		||||
                    if *cell { 1 as i32 } 
 | 
			
		||||
                    else { 0 as i32 }
 | 
			
		||||
                ).sum::<i32>()
 | 
			
		||||
            ).sum()
 | 
			
		||||
                    .map(|cell| if *cell { 1 as i32 } else { 0 as i32 })
 | 
			
		||||
                    .sum::<i32>()
 | 
			
		||||
            })
 | 
			
		||||
            .sum()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,4 +140,4 @@ fn normalize(n: i32) -> i32 {
 | 
			
		|||
    } else {
 | 
			
		||||
        0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,11 +5,8 @@ pub fn solve() {
 | 
			
		|||
 | 
			
		||||
    let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
 | 
			
		||||
 | 
			
		||||
    let lines: Vec<&str> = contents
 | 
			
		||||
        .lines()
 | 
			
		||||
        .filter(|line| *line != "")
 | 
			
		||||
        .collect();
 | 
			
		||||
    
 | 
			
		||||
    let lines: Vec<&str> = contents.lines().filter(|line| *line != "").collect();
 | 
			
		||||
 | 
			
		||||
    let mut reg_x = 1;
 | 
			
		||||
    let mut cycle = 0;
 | 
			
		||||
    let mut signal_strengths = Vec::<i32>::new();
 | 
			
		||||
| 
						 | 
				
			
			@ -24,22 +21,22 @@ pub fn solve() {
 | 
			
		|||
                // increase cycle 1 time
 | 
			
		||||
                cycle += 1;
 | 
			
		||||
                if rel_cycle(cycle) {
 | 
			
		||||
                    signal_strengths.push(cycle*reg_x);
 | 
			
		||||
                    signal_strengths.push(cycle * reg_x);
 | 
			
		||||
                }
 | 
			
		||||
                crt.push(sprite_draw(cycle, reg_x));
 | 
			
		||||
            },
 | 
			
		||||
            }
 | 
			
		||||
            "addx" => {
 | 
			
		||||
                // increase cycle 2 times
 | 
			
		||||
                (0..2).for_each(|_| {
 | 
			
		||||
                    cycle += 1;
 | 
			
		||||
                    if rel_cycle(cycle) {
 | 
			
		||||
                        signal_strengths.push(cycle*reg_x);
 | 
			
		||||
                        signal_strengths.push(cycle * reg_x);
 | 
			
		||||
                    }
 | 
			
		||||
                    crt.push(sprite_draw(cycle, reg_x));
 | 
			
		||||
                });
 | 
			
		||||
                // change regX according to parameter
 | 
			
		||||
                reg_x += parts[1].parse::<i32>().unwrap();
 | 
			
		||||
            },
 | 
			
		||||
            }
 | 
			
		||||
            _ => {}
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -52,21 +49,23 @@ pub fn solve() {
 | 
			
		|||
    let mut print_buffer = "".to_string();
 | 
			
		||||
    // print the crt line by line
 | 
			
		||||
    crt.iter().enumerate().for_each(|(i, p)| {
 | 
			
		||||
        if *p { print_buffer += "#" } 
 | 
			
		||||
        else { print_buffer += "." }
 | 
			
		||||
        if *p {
 | 
			
		||||
            print_buffer += "#"
 | 
			
		||||
        } else {
 | 
			
		||||
            print_buffer += "."
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // print buffer if a line is completed
 | 
			
		||||
        if (i+1) % 40 == 0  {
 | 
			
		||||
        if (i + 1) % 40 == 0 {
 | 
			
		||||
            println!("{}", print_buffer);
 | 
			
		||||
            print_buffer = "".to_string();
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns whether the passed cycle is a relevant one
 | 
			
		||||
fn rel_cycle(cycle: i32) -> bool {
 | 
			
		||||
    if (cycle-20) % 40 == 0 && cycle >= 20 {
 | 
			
		||||
    if (cycle - 20) % 40 == 0 && cycle >= 20 {
 | 
			
		||||
        true
 | 
			
		||||
    } else {
 | 
			
		||||
        false
 | 
			
		||||
| 
						 | 
				
			
			@ -75,5 +74,5 @@ fn rel_cycle(cycle: i32) -> bool {
 | 
			
		|||
 | 
			
		||||
// returns whether the sprite is currently in a position to draw a pixel
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										117
									
								
								src/days/d11.rs
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								src/days/d11.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -5,11 +5,12 @@ pub fn solve() {
 | 
			
		|||
 | 
			
		||||
    let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
 | 
			
		||||
 | 
			
		||||
    let monk_strings: Vec<&str> = contents
 | 
			
		||||
        .split("\n\n")
 | 
			
		||||
        .collect();
 | 
			
		||||
    let monk_strings: Vec<&str> = contents.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 monkeys_num = monkeys.len();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,9 @@ pub fn solve() {
 | 
			
		|||
            let new_items = monkeys[i].turn(monkeys_num, |x| x / 3);
 | 
			
		||||
            // add items to correct monkeys
 | 
			
		||||
            (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}");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    (0..10000).for_each(|_| {
 | 
			
		||||
        (0..monkeys_num).for_each(|i| {
 | 
			
		||||
            // 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);
 | 
			
		||||
            // add items to correct monkeys
 | 
			
		||||
            (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;
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {res}");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Clone)]
 | 
			
		||||
enum Operation {
 | 
			
		||||
    Mult,
 | 
			
		||||
    Add
 | 
			
		||||
    Add,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
| 
						 | 
				
			
			@ -78,54 +80,57 @@ impl Monkey {
 | 
			
		|||
            test_divisible_by: 0,
 | 
			
		||||
            monkey_if_true: 0,
 | 
			
		||||
            monkey_if_false: 0,
 | 
			
		||||
            inspections: 0
 | 
			
		||||
            inspections: 0,
 | 
			
		||||
        };
 | 
			
		||||
        input.split("\n").filter(|line| *line != "").for_each(|line| {
 | 
			
		||||
            let (ident, val) = line.split_at(line.find(":").unwrap());
 | 
			
		||||
            match ident {
 | 
			
		||||
                "  Starting items" => {
 | 
			
		||||
                    // remove whitespace and beginning, split by ,
 | 
			
		||||
                    let val = val.replace(":","").replace(" ", "");
 | 
			
		||||
                    monkey.items = val
 | 
			
		||||
                        .split(",")
 | 
			
		||||
                        .collect::<Vec::<&str>>()
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|i| (*i).parse::<u64>().unwrap())
 | 
			
		||||
                        .collect()
 | 
			
		||||
                },
 | 
			
		||||
                "  Operation" => {
 | 
			
		||||
                    // parse operator, parse last word as number
 | 
			
		||||
                    let val = val.replace(": new = old ", "");
 | 
			
		||||
                    let (op, num) = val.split_at(val.find(" ").unwrap());
 | 
			
		||||
                    match op {
 | 
			
		||||
                        "+" => monkey.operation_type = Operation::Add,
 | 
			
		||||
                        "*" => monkey.operation_type = Operation::Mult,
 | 
			
		||||
                        _ => {}
 | 
			
		||||
        input
 | 
			
		||||
            .split("\n")
 | 
			
		||||
            .filter(|line| *line != "")
 | 
			
		||||
            .for_each(|line| {
 | 
			
		||||
                let (ident, val) = line.split_at(line.find(":").unwrap());
 | 
			
		||||
                match ident {
 | 
			
		||||
                    "  Starting items" => {
 | 
			
		||||
                        // remove whitespace and beginning, split by ,
 | 
			
		||||
                        let val = val.replace(":", "").replace(" ", "");
 | 
			
		||||
                        monkey.items = val
 | 
			
		||||
                            .split(",")
 | 
			
		||||
                            .collect::<Vec<&str>>()
 | 
			
		||||
                            .iter()
 | 
			
		||||
                            .map(|i| (*i).parse::<u64>().unwrap())
 | 
			
		||||
                            .collect()
 | 
			
		||||
                    }
 | 
			
		||||
                    if num == " old" {
 | 
			
		||||
                        monkey.operation_quad = true
 | 
			
		||||
                    } else {
 | 
			
		||||
                        monkey.operation_num = num.trim().parse::<i32>().unwrap();
 | 
			
		||||
                    "  Operation" => {
 | 
			
		||||
                        // parse operator, parse last word as number
 | 
			
		||||
                        let val = val.replace(": new = old ", "");
 | 
			
		||||
                        let (op, num) = val.split_at(val.find(" ").unwrap());
 | 
			
		||||
                        match op {
 | 
			
		||||
                            "+" => monkey.operation_type = Operation::Add,
 | 
			
		||||
                            "*" => monkey.operation_type = Operation::Mult,
 | 
			
		||||
                            _ => {}
 | 
			
		||||
                        }
 | 
			
		||||
                        if num == " old" {
 | 
			
		||||
                            monkey.operation_quad = true
 | 
			
		||||
                        } else {
 | 
			
		||||
                            monkey.operation_num = num.trim().parse::<i32>().unwrap();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                "  Test" => {
 | 
			
		||||
                    // parse last word as number
 | 
			
		||||
                    let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                    monkey.test_divisible_by = words.last().unwrap().parse::<u64>().unwrap();
 | 
			
		||||
                },
 | 
			
		||||
                "    If true" => {
 | 
			
		||||
                    // parse last word as number
 | 
			
		||||
                    let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                    monkey.monkey_if_true = words.last().unwrap().parse::<i32>().unwrap();
 | 
			
		||||
                },
 | 
			
		||||
                "    If false" => {
 | 
			
		||||
                    // parse last word as number
 | 
			
		||||
                    let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                    monkey.monkey_if_false = words.last().unwrap().parse::<i32>().unwrap();
 | 
			
		||||
                },
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
                    "  Test" => {
 | 
			
		||||
                        // parse last word as number
 | 
			
		||||
                        let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                        monkey.test_divisible_by = words.last().unwrap().parse::<u64>().unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                    "    If true" => {
 | 
			
		||||
                        // parse last word as number
 | 
			
		||||
                        let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                        monkey.monkey_if_true = words.last().unwrap().parse::<i32>().unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                    "    If false" => {
 | 
			
		||||
                        // parse last word as number
 | 
			
		||||
                        let words: Vec<&str> = val.split(" ").collect();
 | 
			
		||||
                        monkey.monkey_if_false = words.last().unwrap().parse::<i32>().unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        monkey
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -158,4 +163,4 @@ impl Monkey {
 | 
			
		|||
 | 
			
		||||
        items
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										138
									
								
								src/days/d12.rs
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								src/days/d12.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,60 +1,72 @@
 | 
			
		|||
use std::{fs, collections::{HashMap, HashSet}};
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::{HashMap, HashSet},
 | 
			
		||||
    fs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub fn solve() {
 | 
			
		||||
    let path = "res/12/input.txt";
 | 
			
		||||
 | 
			
		||||
    let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
 | 
			
		||||
 | 
			
		||||
    let lines: Vec<&str> = contents
 | 
			
		||||
        .lines()
 | 
			
		||||
        .collect();
 | 
			
		||||
    let lines: Vec<&str> = contents.lines().collect();
 | 
			
		||||
 | 
			
		||||
    // Build grid
 | 
			
		||||
    let mut start = (0, 0);
 | 
			
		||||
    let mut end = (0, 0);
 | 
			
		||||
    let grid: Vec<Vec<u32>> = lines.iter().enumerate().map(|(y, line)| {
 | 
			
		||||
        line.chars().enumerate().map(|(x, c)|
 | 
			
		||||
            match c {
 | 
			
		||||
                'S' => {
 | 
			
		||||
                    start = (x as u32, y as u32);
 | 
			
		||||
                    return char_to_numeric('a')
 | 
			
		||||
 | 
			
		||||
                },
 | 
			
		||||
                'E' => {
 | 
			
		||||
                    end = (x as u32, y as u32);
 | 
			
		||||
                    return char_to_numeric('z')
 | 
			
		||||
                },
 | 
			
		||||
                _ => {
 | 
			
		||||
                    return char_to_numeric(c)
 | 
			
		||||
                }
 | 
			
		||||
        }).collect()
 | 
			
		||||
    }).collect();
 | 
			
		||||
    let grid: Vec<Vec<u32>> = lines
 | 
			
		||||
        .iter()
 | 
			
		||||
        .enumerate()
 | 
			
		||||
        .map(|(y, line)| {
 | 
			
		||||
            line.chars()
 | 
			
		||||
                .enumerate()
 | 
			
		||||
                .map(|(x, c)| match c {
 | 
			
		||||
                    'S' => {
 | 
			
		||||
                        start = (x as u32, y as u32);
 | 
			
		||||
                        return char_to_numeric('a');
 | 
			
		||||
                    }
 | 
			
		||||
                    'E' => {
 | 
			
		||||
                        end = (x as u32, y as u32);
 | 
			
		||||
                        return char_to_numeric('z');
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => return char_to_numeric(c),
 | 
			
		||||
                })
 | 
			
		||||
                .collect()
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    // 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()
 | 
			
		||||
        .enumerate()
 | 
			
		||||
        .for_each(|(y, line)| {
 | 
			
		||||
        line.iter()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .for_each(|(x, height)| {
 | 
			
		||||
            adjacents.insert((x as u32, y as u32), Vec::<(u32,u32)>::new());
 | 
			
		||||
    grid.iter().enumerate().for_each(|(y, line)| {
 | 
			
		||||
        line.iter().enumerate().for_each(|(x, height)| {
 | 
			
		||||
            adjacents.insert((x as u32, y as u32), Vec::<(u32, u32)>::new());
 | 
			
		||||
            // top
 | 
			
		||||
            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))
 | 
			
		||||
            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))
 | 
			
		||||
            }
 | 
			
		||||
            // bot
 | 
			
		||||
            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))
 | 
			
		||||
            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))
 | 
			
		||||
            }
 | 
			
		||||
            //left
 | 
			
		||||
            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))
 | 
			
		||||
            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))
 | 
			
		||||
            }
 | 
			
		||||
            // right
 | 
			
		||||
            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))
 | 
			
		||||
            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))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -66,26 +78,16 @@ pub fn solve() {
 | 
			
		|||
 | 
			
		||||
    // task 2 - find min distance for each node with height 1, select min
 | 
			
		||||
    let mut distances = Vec::<i32>::new();
 | 
			
		||||
    grid.iter()
 | 
			
		||||
        .enumerate()
 | 
			
		||||
        .for_each(|(y, line)| {
 | 
			
		||||
        line.iter()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .for_each(|(x, height)| {
 | 
			
		||||
    grid.iter().enumerate().for_each(|(y, line)| {
 | 
			
		||||
        line.iter().enumerate().for_each(|(x, height)| {
 | 
			
		||||
            if *height == 1 {
 | 
			
		||||
                distances.push(
 | 
			
		||||
                    bfs((x as u32, y as u32), end, &adjacents)
 | 
			
		||||
                )
 | 
			
		||||
                distances.push(bfs((x as u32, y as u32), end, &adjacents))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    });
 | 
			
		||||
    let res = *distances.iter()
 | 
			
		||||
        .filter(|dist| **dist != -1)
 | 
			
		||||
        .min()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    
 | 
			
		||||
    println!("Result 2: {res}")
 | 
			
		||||
    let res = *distances.iter().filter(|dist| **dist != -1).min().unwrap();
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {res}")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Maps lowercase chars to 1..=26
 | 
			
		||||
| 
						 | 
				
			
			@ -94,10 +96,14 @@ 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
 | 
			
		||||
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 seen_nodes = HashSet::<(u32,u32)>::new();
 | 
			
		||||
    let mut predecessor = HashMap::<(u32,u32),(u32,u32)>::new();
 | 
			
		||||
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 seen_nodes = HashSet::<(u32, u32)>::new();
 | 
			
		||||
    let mut predecessor = HashMap::<(u32, u32), (u32, u32)>::new();
 | 
			
		||||
    queue.push(start);
 | 
			
		||||
    seen_nodes.insert(start);
 | 
			
		||||
    while !queue.is_empty() {
 | 
			
		||||
| 
						 | 
				
			
			@ -105,15 +111,13 @@ fn bfs(start: (u32,u32), end: (u32,u32), adjacents: &HashMap<(u32,u32),Vec<(u32,
 | 
			
		|||
        if node == end {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        adjacents.get(&node).unwrap()
 | 
			
		||||
            .iter()
 | 
			
		||||
            .for_each(|child| {
 | 
			
		||||
                if !seen_nodes.contains(child) {
 | 
			
		||||
                    queue.push(*child);
 | 
			
		||||
                    seen_nodes.insert(*child);
 | 
			
		||||
                    predecessor.insert(*child, node);
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        adjacents.get(&node).unwrap().iter().for_each(|child| {
 | 
			
		||||
            if !seen_nodes.contains(child) {
 | 
			
		||||
                queue.push(*child);
 | 
			
		||||
                seen_nodes.insert(*child);
 | 
			
		||||
                predecessor.insert(*child, node);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    // if end is reachable, it now is in predecessor
 | 
			
		||||
    let mut res = 0; // steps
 | 
			
		||||
| 
						 | 
				
			
			@ -121,10 +125,10 @@ fn bfs(start: (u32,u32), end: (u32,u32), adjacents: &HashMap<(u32,u32),Vec<(u32,
 | 
			
		|||
    while node != start {
 | 
			
		||||
        node = match predecessor.get(&node) {
 | 
			
		||||
            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,5 +1,5 @@
 | 
			
		|||
use std::{fs, cmp::Ordering};
 | 
			
		||||
use serde_json::Value;
 | 
			
		||||
use std::{cmp::Ordering, fs};
 | 
			
		||||
 | 
			
		||||
pub fn solve() {
 | 
			
		||||
    let path = "res/13/input.txt";
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ pub fn solve() {
 | 
			
		|||
        .split("\n\n")
 | 
			
		||||
        .map(|pair| pair.split_at(pair.find("\n").unwrap()))
 | 
			
		||||
        .collect();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    let mut right_order_indices = Vec::<u32>::new();
 | 
			
		||||
    pairs.iter().enumerate().for_each(|(i, pair)| {
 | 
			
		||||
        let json1: Value = serde_json::from_str(pair.0).unwrap();
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ pub fn solve() {
 | 
			
		|||
        // println!("Pair {}: {res:?}\n", i+1);
 | 
			
		||||
 | 
			
		||||
        if res != Ordered::No {
 | 
			
		||||
            right_order_indices.push((i+1) as u32);
 | 
			
		||||
            right_order_indices.push((i + 1) as u32);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,17 +36,16 @@ pub fn solve() {
 | 
			
		|||
        .filter(|line| *line != "")
 | 
			
		||||
        .map(|line| serde_json::from_str(line).unwrap())
 | 
			
		||||
        .collect();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // add [[2]] and [[6]] as divider packets
 | 
			
		||||
    packets.push(serde_json::from_str("[[6]]").unwrap());
 | 
			
		||||
    packets.push(serde_json::from_str("[[2]]").unwrap());
 | 
			
		||||
 | 
			
		||||
    // sort by compare function using is_right_order
 | 
			
		||||
    packets.sort_by(|a, b| 
 | 
			
		||||
        match is_right_order((a, b)) {
 | 
			
		||||
            Ordered::Yes => Ordering::Less,
 | 
			
		||||
            Ordered::Maybe => Ordering::Equal,
 | 
			
		||||
            Ordered::No => Ordering::Greater
 | 
			
		||||
    packets.sort_by(|a, b| match is_right_order((a, b)) {
 | 
			
		||||
        Ordered::Yes => Ordering::Less,
 | 
			
		||||
        Ordered::Maybe => Ordering::Equal,
 | 
			
		||||
        Ordered::No => Ordering::Greater,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // find [[2]] and [[6]] indices
 | 
			
		||||
| 
						 | 
				
			
			@ -58,16 +57,15 @@ pub fn solve() {
 | 
			
		|||
            if v[0].is_array() && v[0].as_array().unwrap().len() == 1 {
 | 
			
		||||
                let v = v[0].as_array().unwrap();
 | 
			
		||||
                if v[0].is_number() && v[0].as_u64().unwrap() == 2 {
 | 
			
		||||
                    i2 = i+1
 | 
			
		||||
                }
 | 
			
		||||
                else if v[0].is_number() && v[0].as_u64().unwrap() == 6 {
 | 
			
		||||
                    i6 = i+1
 | 
			
		||||
                    i2 = i + 1
 | 
			
		||||
                } else if v[0].is_number() && v[0].as_u64().unwrap() == 6 {
 | 
			
		||||
                    i6 = i + 1
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    let res = i2*i6;
 | 
			
		||||
 | 
			
		||||
    let res = i2 * i6;
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {res}");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -76,37 +74,37 @@ pub fn solve() {
 | 
			
		|||
enum Ordered {
 | 
			
		||||
    Yes,
 | 
			
		||||
    Maybe,
 | 
			
		||||
    No
 | 
			
		||||
    No,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns whether the passed Values are in the right order
 | 
			
		||||
// with Ordered enum option
 | 
			
		||||
fn is_right_order(values: (&Value, &Value)) -> Ordered {
 | 
			
		||||
    //println!("Compare {} vs {}", values.0, values.1);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // both values numbers
 | 
			
		||||
    if values.0.is_number() && values.1.is_number() {
 | 
			
		||||
        let v0 = values.0.as_u64().unwrap();
 | 
			
		||||
        let v1 = values.1.as_u64().unwrap();
 | 
			
		||||
        // wrong order if right is higher than left
 | 
			
		||||
        if v0 < v1 {
 | 
			
		||||
            return Ordered::Yes
 | 
			
		||||
            return Ordered::Yes;
 | 
			
		||||
        } else if v0 == v1 {
 | 
			
		||||
            return Ordered::Maybe
 | 
			
		||||
            return Ordered::Maybe;
 | 
			
		||||
        } else {
 | 
			
		||||
            return Ordered::No
 | 
			
		||||
            return Ordered::No;
 | 
			
		||||
        }
 | 
			
		||||
    } 
 | 
			
		||||
    }
 | 
			
		||||
    // left number, right array
 | 
			
		||||
    else if values.0.is_number() && values.1.is_array() {
 | 
			
		||||
        // 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));
 | 
			
		||||
    }
 | 
			
		||||
    // left array, right number
 | 
			
		||||
    else if values.0.is_array() && values.1.is_number() {
 | 
			
		||||
        // 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));
 | 
			
		||||
    }
 | 
			
		||||
    // both array
 | 
			
		||||
| 
						 | 
				
			
			@ -123,17 +121,17 @@ fn is_right_order(values: (&Value, &Value)) -> Ordered {
 | 
			
		|||
 | 
			
		||||
            // left smaller, counts as ordered
 | 
			
		||||
            if left.is_none() && right.is_some() {
 | 
			
		||||
                return Ordered::Yes
 | 
			
		||||
                return Ordered::Yes;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // right smaller, counts as unordered
 | 
			
		||||
            if left.is_some() && right.is_none() {
 | 
			
		||||
                return Ordered::No
 | 
			
		||||
                return Ordered::No;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // both have same length, doesn't say anything about ordering
 | 
			
		||||
            if left.is_none() && right.is_none() {
 | 
			
		||||
                return Ordered::Maybe
 | 
			
		||||
                return Ordered::Maybe;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let left = left.unwrap();
 | 
			
		||||
| 
						 | 
				
			
			@ -142,10 +140,10 @@ fn is_right_order(values: (&Value, &Value)) -> Ordered {
 | 
			
		|||
            // only go into next iteration if not definitely yes or no
 | 
			
		||||
            let res = is_right_order((&left, &right));
 | 
			
		||||
            if res != Ordered::Maybe {
 | 
			
		||||
                return res
 | 
			
		||||
                return res;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ordered::Yes
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ use std::fs;
 | 
			
		|||
const CAVE_WIDTH: u32 = 400;
 | 
			
		||||
const CAVE_HEIGHT: u32 = 200;
 | 
			
		||||
const X_OFFSET: u32 = 300;
 | 
			
		||||
const START_POINT: (u32,u32) = (500,0);
 | 
			
		||||
const START_POINT: (u32, u32) = (500, 0);
 | 
			
		||||
 | 
			
		||||
pub fn solve() {
 | 
			
		||||
    let path = "res/14/input.txt";
 | 
			
		||||
| 
						 | 
				
			
			@ -18,18 +18,23 @@ pub fn solve() {
 | 
			
		|||
            line.split(" -> ")
 | 
			
		||||
                .map(|coord| {
 | 
			
		||||
                    let coord_arr: Vec<&str> = coord.split(",").collect();
 | 
			
		||||
                    (coord_arr[0].parse::<u32>().unwrap(), 
 | 
			
		||||
                    coord_arr[1].parse::<u32>().unwrap())
 | 
			
		||||
                }).collect()
 | 
			
		||||
        }).collect();
 | 
			
		||||
    
 | 
			
		||||
                    (
 | 
			
		||||
                        coord_arr[0].parse::<u32>().unwrap(),
 | 
			
		||||
                        coord_arr[1].parse::<u32>().unwrap(),
 | 
			
		||||
                    )
 | 
			
		||||
                })
 | 
			
		||||
                .collect()
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
    rock_paths.iter().for_each(|path| {
 | 
			
		||||
        path.windows(2)
 | 
			
		||||
            .for_each(|pairs| {
 | 
			
		||||
        path.windows(2).for_each(|pairs| {
 | 
			
		||||
            // draw rock lines
 | 
			
		||||
            let x_iter = if pairs[0].0 > pairs[1].0 {
 | 
			
		||||
                pairs[1].0..=pairs[0].0
 | 
			
		||||
| 
						 | 
				
			
			@ -43,19 +48,17 @@ pub fn solve() {
 | 
			
		|||
                    pairs[0].1..=pairs[1].1
 | 
			
		||||
                };
 | 
			
		||||
                y_iter.for_each(|y| {
 | 
			
		||||
                    cave[(x-X_OFFSET) as usize][y as usize] = true;
 | 
			
		||||
                    cave[(x - X_OFFSET) as usize][y as usize] = true;
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // task 1 - normal cave
 | 
			
		||||
    // let sand fall
 | 
			
		||||
    let mut sand_unit_counter: u32 = 0;
 | 
			
		||||
    let mut sand_pos = next_sand_pos(&cave);
 | 
			
		||||
    while sand_pos.1 < CAVE_HEIGHT-1 {
 | 
			
		||||
    while sand_pos.1 < CAVE_HEIGHT - 1 {
 | 
			
		||||
        cave[sand_pos.0 as usize][sand_pos.1 as usize] = true;
 | 
			
		||||
        sand_pos = next_sand_pos(&cave);
 | 
			
		||||
        sand_unit_counter += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,49 +66,43 @@ pub fn solve() {
 | 
			
		|||
 | 
			
		||||
    println!("Result 1: {sand_unit_counter}");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // task 2 - cave with ground
 | 
			
		||||
    // find ground - cave height is 2 + max y value
 | 
			
		||||
    let cave_height = 2 + rock_paths
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|line| 
 | 
			
		||||
            line
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|r| r.1)
 | 
			
		||||
                .max()
 | 
			
		||||
                .unwrap()
 | 
			
		||||
            )
 | 
			
		||||
        .map(|line| line.iter().map(|r| r.1).max().unwrap())
 | 
			
		||||
        .max()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    // build ground
 | 
			
		||||
    cave.iter_mut().for_each(|col| {
 | 
			
		||||
        col[(cave_height) as usize] = true
 | 
			
		||||
    });
 | 
			
		||||
    cave.iter_mut()
 | 
			
		||||
        .for_each(|col| col[(cave_height) as usize] = true);
 | 
			
		||||
 | 
			
		||||
    // 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) {
 | 
			
		||||
        cave[sand_pos.0 as usize][sand_pos.1 as usize] = true;
 | 
			
		||||
        sand_pos = next_sand_pos(&cave);
 | 
			
		||||
        sand_unit_counter += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    println!("Result 2: {sand_unit_counter}");    
 | 
			
		||||
    println!("Result 2: {sand_unit_counter}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns the next position a sand unit will come to rest at
 | 
			
		||||
fn next_sand_pos(cave: &Vec<Vec<bool>>) -> (u32, u32) {
 | 
			
		||||
    let start_pos = (START_POINT.0-X_OFFSET, START_POINT.1);
 | 
			
		||||
    let start_pos = (START_POINT.0 - X_OFFSET, START_POINT.1);
 | 
			
		||||
    let mut pos: (u32, u32) = start_pos;
 | 
			
		||||
    while !is_end_pos(pos, cave) {
 | 
			
		||||
        // first check directly below
 | 
			
		||||
        if !cave[(pos.0) as usize][(pos.1+1) as usize] {
 | 
			
		||||
            pos = (pos.0, pos.1+1)
 | 
			
		||||
        } // then diagonally down-left
 | 
			
		||||
        else if !cave[(pos.0-1) as usize][(pos.1+1) as usize] {
 | 
			
		||||
            pos = (pos.0-1, pos.1+1)
 | 
			
		||||
        } // then diagonally down-right
 | 
			
		||||
        else if !cave[(pos.0+1) as usize][(pos.1+1) as usize] {
 | 
			
		||||
            pos = (pos.0+1, pos.1+1)
 | 
			
		||||
        if !cave[(pos.0) as usize][(pos.1 + 1) as usize] {
 | 
			
		||||
            pos = (pos.0, pos.1 + 1)
 | 
			
		||||
        }
 | 
			
		||||
        // then diagonally down-left
 | 
			
		||||
        else if !cave[(pos.0 - 1) as usize][(pos.1 + 1) as usize] {
 | 
			
		||||
            pos = (pos.0 - 1, pos.1 + 1)
 | 
			
		||||
        }
 | 
			
		||||
        // then diagonally down-right
 | 
			
		||||
        else if !cave[(pos.0 + 1) as usize][(pos.1 + 1) as usize] {
 | 
			
		||||
            pos = (pos.0 + 1, pos.1 + 1)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -114,15 +111,16 @@ fn next_sand_pos(cave: &Vec<Vec<bool>>) -> (u32, u32) {
 | 
			
		|||
 | 
			
		||||
// returns whether the passed coordinates are a valid end position for a sand unit
 | 
			
		||||
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
 | 
			
		||||
        return true
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    // 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]
 | 
			
		||||
        && cave[(pos.0) as usize][(pos.1+1) as usize]
 | 
			
		||||
        && cave[(pos.0+1) as usize][(pos.1+1) as usize] {
 | 
			
		||||
        return true
 | 
			
		||||
    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 + 1) as usize][(pos.1 + 1) as usize]
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    false
 | 
			
		||||
| 
						 | 
				
			
			@ -132,12 +130,10 @@ fn is_end_pos(pos: (u32, u32), cave: &Vec<Vec<bool>>) -> bool {
 | 
			
		|||
fn _print_cave(cave: &Vec<Vec<bool>>) {
 | 
			
		||||
    let mut out: Vec<String> = (0..CAVE_HEIGHT).map(|_| "".to_string()).collect();
 | 
			
		||||
    cave.iter().for_each(|line| {
 | 
			
		||||
        line.iter().enumerate().for_each(|(i, cell)| 
 | 
			
		||||
            match *cell {
 | 
			
		||||
                true => out[i] += "#",
 | 
			
		||||
                false => out[i] += "."
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        line.iter().enumerate().for_each(|(i, cell)| match *cell {
 | 
			
		||||
            true => out[i] += "#",
 | 
			
		||||
            false => out[i] += ".",
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    out.iter().for_each(|s| println!("{s}"));
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								src/days/d15.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/days/d15.rs
									
									
									
									
									
										Normal 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");
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
pub mod days;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    days::d14::solve()
 | 
			
		||||
    days::d15::solve()
 | 
			
		||||
    //_all_days()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,4 +32,8 @@ fn _all_days() {
 | 
			
		|||
    days::d12::solve();
 | 
			
		||||
    println!("\nDay 13");
 | 
			
		||||
    days::d13::solve();
 | 
			
		||||
    println!("\nDay 14");
 | 
			
		||||
    days::d14::solve();
 | 
			
		||||
    println!("\nDay 15");
 | 
			
		||||
    days::d14::solve();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue