├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── day6.rs ├── day1.rs ├── day4.rs ├── day2.rs ├── day9.rs ├── day5.rs ├── day3.rs ├── day8.rs └── day7.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | day*_input* 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aoc-2022" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aoc-2022" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [[bin]] 7 | name = "day1" 8 | path = "src/day1.rs" 9 | 10 | [[bin]] 11 | name = "day2" 12 | path = "src/day2.rs" 13 | 14 | [[bin]] 15 | name = "day3" 16 | path = "src/day3.rs" 17 | 18 | [[bin]] 19 | name = "day4" 20 | path = "src/day4.rs" 21 | 22 | [[bin]] 23 | name = "day5" 24 | path = "src/day5.rs" 25 | 26 | [[bin]] 27 | name = "day6" 28 | path = "src/day6.rs" 29 | 30 | [[bin]] 31 | name = "day7" 32 | path = "src/day7.rs" 33 | 34 | [[bin]] 35 | name = "day8" 36 | path = "src/day8.rs" 37 | 38 | [[bin]] 39 | name = "day9" 40 | path = "src/day9.rs" 41 | 42 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 43 | 44 | [dependencies] 45 | -------------------------------------------------------------------------------- /src/day6.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use std::collections::HashSet; 6 | use std::collections::VecDeque; 7 | 8 | const MARKER_LENGTH : usize = 14; 9 | 10 | fn qualifies(v: &VecDeque) -> bool { 11 | v.len() == MARKER_LENGTH 12 | } 13 | 14 | fn unique(v: &VecDeque) -> bool { 15 | let hs: HashSet<&char> = v.into_iter().collect(); 16 | hs.len() == MARKER_LENGTH 17 | } 18 | 19 | fn marker_location(s: String) -> usize { 20 | let mut lookbehind: VecDeque = VecDeque::new(); 21 | for (index, new_char) in s.chars().enumerate() { 22 | lookbehind.push_back(new_char); 23 | if qualifies(&lookbehind) { 24 | if unique(&lookbehind) { 25 | return index + 1; 26 | } else { 27 | lookbehind.pop_front(); 28 | } 29 | } 30 | } 31 | 0 32 | } 33 | 34 | fn process(file: File) { 35 | let lines = BufReader::new(file).lines(); 36 | for line in lines { 37 | if let Ok(content) = line { 38 | let location = marker_location(content); 39 | println!("Marker location is at {}", location); 40 | } 41 | } 42 | } 43 | 44 | fn main() { 45 | let args: Vec = env::args().collect(); 46 | 47 | let filename = args.get(1); 48 | match filename { 49 | None => println!("No filename given, bugger off"), 50 | Some(filename) => { 51 | let path = Path::new(filename); 52 | 53 | match File::open(&path) { 54 | Err(why) => println!("couldn't open file: {}", why), 55 | Ok(file) => process(file), 56 | } 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/day1.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | 6 | fn find_max(calories: Vec) { 7 | let top1_calories = calories.get(0); 8 | let top2_calories = calories.get(1); 9 | let top3_calories = calories.get(2); 10 | match top1_calories { 11 | Some(max_calories) => println!("Elf with max calories has {} calories", max_calories), 12 | None => println!("Uhm, dunno"), 13 | } 14 | 15 | match (top1_calories, top2_calories, top3_calories) { 16 | (Some(top1), Some(top2), Some(top3)) => { 17 | println!("Top 3 have {} in total", top1 + top2 + top3) 18 | } 19 | (_, _, _) => println!("Not enough elves to determine top 3"), 20 | } 21 | } 22 | 23 | fn process(file: File) { 24 | let lines = BufReader::new(file).lines(); 25 | let mut elf_calories: Vec = Vec::new(); 26 | let mut current_calories = 0; 27 | for line in lines { 28 | if let Ok(content) = line { 29 | match content.parse::() { 30 | Err(_) => { 31 | elf_calories.push(current_calories); 32 | current_calories = 0; 33 | } 34 | Ok(num) => { 35 | current_calories = current_calories + num; 36 | } 37 | } 38 | } 39 | } 40 | elf_calories.push(current_calories); 41 | elf_calories.sort(); 42 | elf_calories.reverse(); 43 | find_max(elf_calories); 44 | } 45 | 46 | fn main() { 47 | let args: Vec = env::args().collect(); 48 | 49 | let filename = args.get(1); 50 | match filename { 51 | None => println!("No filename given, bugger off"), 52 | Some(filename) => { 53 | let path = Path::new(filename); 54 | 55 | match File::open(&path) { 56 | Err(why) => println!("couldn't open file: {}", why), 57 | Ok(file) => process(file), 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/day4.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use std::collections::HashSet; 6 | 7 | fn parse_start_end(s: &str) -> (u64, u64) { 8 | let mut splitter = s.splitn(2, '-'); 9 | let start = splitter.next().unwrap(); 10 | let end = splitter.next().unwrap(); 11 | let start_num = start.parse::().unwrap(); 12 | let end_num = end.parse::().unwrap(); 13 | (start_num, end_num) 14 | } 15 | 16 | fn range_to_set((start, end): (u64, u64)) -> HashSet { 17 | (start..=end).into_iter().collect() 18 | } 19 | 20 | fn _are_subsets(left: HashSet, right: HashSet) -> bool { 21 | let left_is_subset = left.is_subset(&right); 22 | let right_is_subset = right.is_subset(&left); 23 | left_is_subset || right_is_subset 24 | } 25 | 26 | fn have_subsets(left: HashSet, right: HashSet) -> bool { 27 | !(left.is_disjoint(&right)) 28 | } 29 | 30 | fn process(file: File) { 31 | let lines = BufReader::new(file).lines(); 32 | let mut total : u64 = 0; 33 | for line in lines { 34 | if let Ok(content) = line { 35 | let mut splitter = content.splitn(2, ','); 36 | let elf1 = splitter.next().unwrap(); 37 | let elf1_range = parse_start_end(elf1); 38 | let elf1_set = range_to_set(elf1_range); 39 | let elf2 = splitter.next().unwrap(); 40 | let elf2_range = parse_start_end(elf2); 41 | let elf2_set = range_to_set(elf2_range); 42 | // let total_overlap = _are_subsets(elf1_set, elf2_set); 43 | let total_overlap = have_subsets(elf1_set, elf2_set); 44 | total += match total_overlap { true => 1, false => 0}; 45 | } 46 | } 47 | println!("Total score is {}", total); 48 | } 49 | 50 | fn main() { 51 | let args: Vec = env::args().collect(); 52 | 53 | let filename = args.get(1); 54 | match filename { 55 | None => println!("No filename given, bugger off"), 56 | Some(filename) => { 57 | let path = Path::new(filename); 58 | 59 | match File::open(&path) { 60 | Err(why) => println!("couldn't open file: {}", why), 61 | Ok(file) => process(file), 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/day2.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | 6 | #[derive(Copy, Clone)] 7 | enum Choice { 8 | Rock, 9 | Paper, 10 | Scissor 11 | } 12 | 13 | enum Outcome { 14 | Lose, 15 | Draw, 16 | Win 17 | } 18 | 19 | fn score(opponent: Choice, me: Choice) -> u64 { 20 | let shape_score = match me { 21 | Choice::Rock => 1, 22 | Choice::Paper => 2, 23 | Choice::Scissor => 3 24 | }; 25 | let outcome_score = match (opponent, me) { 26 | (Choice::Rock, Choice::Paper) | (Choice::Paper, Choice::Scissor) | (Choice::Scissor, Choice::Rock) => 6, 27 | (Choice::Rock, Choice::Rock) | (Choice::Paper, Choice::Paper) | (Choice::Scissor, Choice::Scissor) => 3, 28 | (Choice::Rock, Choice::Scissor) | (Choice::Paper, Choice::Rock) | (Choice::Scissor, Choice::Paper) => 0, 29 | }; 30 | shape_score + outcome_score 31 | } 32 | 33 | fn determine_choice(opponent: Choice, outcome: Outcome) -> Choice { 34 | match (opponent, outcome) { 35 | (Choice::Rock, Outcome::Draw) | (Choice::Paper, Outcome::Lose) | (Choice::Scissor, Outcome::Win) => Choice::Rock, 36 | (Choice::Rock, Outcome::Win) | (Choice::Paper, Outcome::Draw) | (Choice::Scissor, Outcome::Lose) => Choice::Paper, 37 | (Choice::Rock, Outcome::Lose) | (Choice::Paper, Outcome::Win) | (Choice::Scissor, Outcome::Draw) => Choice::Scissor, 38 | } 39 | } 40 | 41 | fn parse_to_choice(s: &str) -> Choice { 42 | match s { 43 | "A" | "X" => Choice::Rock, 44 | "B" | "Y" => Choice::Paper, 45 | "C" | "Z" => Choice::Scissor, 46 | _ => panic!("I'm not paid enough to do this") 47 | } 48 | } 49 | 50 | fn parse_to_outcome(s: &str) -> Outcome { 51 | match s { 52 | "X" => Outcome::Lose, 53 | "Y" => Outcome::Draw, 54 | "Z" => Outcome::Win, 55 | _ => panic!("I'm not paid enough to do this") 56 | } 57 | } 58 | 59 | fn process(file: File) { 60 | let lines = BufReader::new(file).lines(); 61 | let mut total : u64 = 0; 62 | for line in lines { 63 | if let Ok(content) = line { 64 | let mut splitter = content.splitn(2, ' '); 65 | let opponent = splitter.next().unwrap(); 66 | let opponent_choice = parse_to_choice(opponent); 67 | let outcome = splitter.next().unwrap(); 68 | let expected_outcome = parse_to_outcome(outcome); 69 | let my_choice = determine_choice(opponent_choice, expected_outcome); 70 | total = total + score(opponent_choice, my_choice); 71 | } 72 | } 73 | println!("Total score is {}", total); 74 | } 75 | 76 | fn main() { 77 | let args: Vec = env::args().collect(); 78 | 79 | let filename = args.get(1); 80 | match filename { 81 | None => println!("No filename given, bugger off"), 82 | Some(filename) => { 83 | let path = Path::new(filename); 84 | 85 | match File::open(&path) { 86 | Err(why) => println!("couldn't open file: {}", why), 87 | Ok(file) => process(file), 88 | } 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/day9.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use std::collections::HashSet; 6 | 7 | #[derive(Copy, Clone)] 8 | enum Direction { 9 | Up, 10 | Down, 11 | Left, 12 | Right 13 | } 14 | 15 | struct Move { 16 | direction: Direction, 17 | distance: u64 18 | } 19 | 20 | struct Move1(Direction); 21 | 22 | fn parse_direction(s: &str) -> Direction { 23 | if s == "U" { Direction::Up } 24 | else if s == "D" { Direction::Down } 25 | else if s == "L" { Direction::Left } 26 | else if s == "R" { Direction::Right } 27 | else { 28 | panic!("I'm having the worst day"); 29 | } 30 | } 31 | 32 | fn parse_distance(s: &str) -> u64 { 33 | s.parse().unwrap() 34 | } 35 | 36 | type Loc = (i64, i64); 37 | 38 | fn new_tail_pos(tail_pos: Loc, head_pos: Loc) -> Loc { 39 | let (hx, hy) = head_pos; 40 | let (tx, ty) = tail_pos; 41 | 42 | if (hx - tx).abs() <= 1 && (hy - ty).abs() <= 1 { 43 | // stay 44 | tail_pos 45 | } else { 46 | let mut rx = tx; 47 | let mut ry = ty; 48 | if hx > tx { rx += 1 } 49 | if hx < tx { rx -= 1 } 50 | if hy > ty { ry += 1 } 51 | if hy < ty { ry -= 1 } 52 | (rx, ry) 53 | } 54 | } 55 | 56 | fn new_head_pos(head_pos: Loc, dir: &Move1) -> Loc { 57 | let (x, y) = head_pos; 58 | match dir.0 { 59 | Direction::Left => (x-1, y), 60 | Direction::Right => (x+1, y), 61 | Direction::Up => (x, y+1), 62 | Direction::Down => (x, y-1), 63 | } 64 | } 65 | 66 | fn process(file: File) { 67 | let lines = BufReader::new(file).lines(); 68 | let mut moves : Vec = Vec::new(); 69 | for line in lines { 70 | if let Ok(content) = line { 71 | let mut splitter = content.splitn(2, " "); 72 | let direction = parse_direction(splitter.next().unwrap()); 73 | let distance = parse_distance(splitter.next().unwrap()); 74 | let mov = Move { direction, distance }; 75 | moves.push(mov); 76 | } 77 | } 78 | let mut move1s : Vec = Vec::new(); 79 | for mov in &moves { 80 | for _ in 0..(mov.distance) { 81 | move1s.push(Move1(mov.direction)); 82 | } 83 | } 84 | let mut head_pos : Loc = (0, 0); 85 | let mut tail_pos : Loc = (0, 0); 86 | let mut tail_positions : Vec = Vec::new(); 87 | tail_positions.push(tail_pos); 88 | 89 | for mov1 in &move1s { 90 | head_pos = new_head_pos(head_pos, mov1); 91 | tail_pos = new_tail_pos(tail_pos, head_pos); 92 | // println!("Head pos {:?} => Tail pos {:?}", head_pos, tail_pos); 93 | tail_positions.push(tail_pos); 94 | } 95 | 96 | let tail_pos_set : HashSet = HashSet::from_iter(tail_positions.iter().cloned()); 97 | println!("Unique tail positions: {}", tail_pos_set.len()); 98 | 99 | let mut head_rope : Loc = (0, 0); 100 | let mut tail_rope : Vec = (0..9).map(|_| (0, 0)).collect(); 101 | let mut tail_rope_positions : Vec = Vec::new(); 102 | tail_rope_positions.push((0,0)); 103 | for mov1 in &move1s { 104 | head_rope = new_head_pos(head_rope, mov1); 105 | let mut prev = head_rope; 106 | let mut new_tail_rope : Vec = Vec::new(); 107 | for elem in tail_rope { 108 | let new_tp = new_tail_pos(elem, prev); 109 | new_tail_rope.push(new_tp); 110 | prev = new_tp; 111 | } 112 | tail_rope = new_tail_rope; 113 | tail_rope_positions.push(*tail_rope.last().unwrap()); 114 | } 115 | let tail_rope_set : HashSet = HashSet::from_iter(tail_rope_positions.iter().cloned()); 116 | println!("Unique rope positions: {}", tail_rope_set.len()); 117 | } 118 | 119 | fn main() { 120 | let args: Vec = env::args().collect(); 121 | 122 | let filename = args.get(1); 123 | match filename { 124 | None => println!("No filename given, bugger off"), 125 | Some(filename) => { 126 | let path = Path::new(filename); 127 | 128 | match File::open(&path) { 129 | Err(why) => println!("couldn't open file: {}", why), 130 | Ok(file) => process(file), 131 | } 132 | } 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/day5.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | 6 | fn parse_stack_line(l: String) -> Vec> { 7 | let mut collection = Vec::>::new(); 8 | 9 | for chunk in l.chars().collect::>().chunks(4) { 10 | let mut iter = chunk.iter(); 11 | let _ = iter.next(); 12 | let maybe_char = iter.next().unwrap(); 13 | let v = match maybe_char { 14 | ' ' => None, 15 | char => Some(char) 16 | }; 17 | collection.push(v.copied()); 18 | } 19 | collection 20 | } 21 | 22 | struct Move {amount: u64, from: usize, to: usize} 23 | 24 | fn parse_move(l: String) -> Move { 25 | let mut pieces = l.split_whitespace(); 26 | let _move = pieces.next(); 27 | let amount : u64 = pieces.next().unwrap().parse().unwrap(); 28 | let _from = pieces.next(); 29 | let from : usize = pieces.next().unwrap().parse().unwrap(); 30 | let _to = pieces.next(); 31 | let to : usize = pieces.next().unwrap().parse().unwrap(); 32 | 33 | Move { amount, from, to } 34 | } 35 | 36 | fn construct_stacks(stack_lines: Vec>>) -> Vec> { 37 | let mut stacks : Vec> = Vec::new(); 38 | for _ in &stack_lines[0] { 39 | let stack: Vec = Vec::new(); 40 | stacks.push(stack); 41 | } 42 | for line in stack_lines { 43 | for (index, stack_value) in line.iter().enumerate() { 44 | match stack_value { 45 | Some(v) => { 46 | stacks[index].push(*v); 47 | }, 48 | None => () 49 | } 50 | } 51 | } 52 | for stack in stacks.iter_mut() { 53 | stack.reverse(); 54 | } 55 | stacks 56 | } 57 | 58 | fn perform_move(stacks: &mut Vec>, mov: &Move) { 59 | let stack = &mut stacks[mov.from - 1]; 60 | let mut cache : Vec = Vec::new(); 61 | for _ in 0..mov.amount { 62 | let v = stack.pop().unwrap(); 63 | cache.push(v); 64 | } 65 | let part2 = true; 66 | if part2 { 67 | cache.reverse(); 68 | } 69 | // println!("Attempting to move {:?}", cache); 70 | 71 | let stack = &mut stacks[mov.to - 1]; 72 | for v in cache { 73 | stack.push(v); 74 | } 75 | } 76 | 77 | fn peek_tops(stacks: &Vec>) -> Vec { 78 | stacks.iter().map(|stack| 79 | match stack.last() { 80 | None => '?', 81 | Some(c) => *c, 82 | }).collect() 83 | } 84 | 85 | fn peek_tops_id(stacks: &Vec>) -> String { 86 | let tops = peek_tops(stacks); 87 | tops.iter().cloned().collect() 88 | } 89 | 90 | fn process(file: File) { 91 | let lines = BufReader::new(file).lines(); 92 | let mut stack_lines: Vec>> = Vec::new(); 93 | let mut moves : Vec = Vec::new(); 94 | for line in lines { 95 | if let Ok(content) = line { 96 | if content.is_empty() { 97 | continue; 98 | } 99 | else if &content[0..1] == "[" { 100 | let l = parse_stack_line(content); 101 | stack_lines.push(l); 102 | } 103 | else if &content[0..1] == " " { 104 | continue; 105 | } 106 | else { 107 | let m = parse_move(content); 108 | moves.push(m); 109 | } 110 | } 111 | } 112 | let mut stacks = construct_stacks(stack_lines); 113 | // println!("Initial tops: {}", peek_tops_id(&stacks)); 114 | 115 | for mov in moves { 116 | perform_move(&mut stacks, &mov); 117 | // println!("Intermediate tops: {}", peek_tops_id(&stacks)); 118 | } 119 | println!("Final tops: {}", peek_tops_id(&stacks)); 120 | } 121 | 122 | fn main() { 123 | let args: Vec = env::args().collect(); 124 | 125 | let filename = args.get(1); 126 | match filename { 127 | None => println!("No filename given, bugger off"), 128 | Some(filename) => { 129 | let path = Path::new(filename); 130 | 131 | match File::open(&path) { 132 | Err(why) => println!("couldn't open file: {}", why), 133 | Ok(file) => process(file), 134 | } 135 | } 136 | } 137 | } 138 | 139 | -------------------------------------------------------------------------------- /src/day3.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use std::collections::HashSet; 6 | 7 | fn priority(c: char) -> u64 { 8 | match c { 9 | 'a' => 1, 10 | 'b' => 2, 11 | 'c' => 3, 12 | 'd' => 4, 13 | 'e' => 5, 14 | 'f' => 6, 15 | 'g' => 7, 16 | 'h' => 8, 17 | 'i' => 9, 18 | 'j' => 10, 19 | 'k' => 11, 20 | 'l' => 12, 21 | 'm' => 13, 22 | 'n' => 14, 23 | 'o' => 15, 24 | 'p' => 16, 25 | 'q' => 17, 26 | 'r' => 18, 27 | 's' => 19, 28 | 't' => 20, 29 | 'u' => 21, 30 | 'v' => 22, 31 | 'w' => 23, 32 | 'x' => 24, 33 | 'y' => 25, 34 | 'z' => 26, 35 | 'A' => 27, 36 | 'B' => 28, 37 | 'C' => 29, 38 | 'D' => 30, 39 | 'E' => 31, 40 | 'F' => 32, 41 | 'G' => 33, 42 | 'H' => 34, 43 | 'I' => 35, 44 | 'J' => 36, 45 | 'K' => 37, 46 | 'L' => 38, 47 | 'M' => 39, 48 | 'N' => 40, 49 | 'O' => 41, 50 | 'P' => 42, 51 | 'Q' => 43, 52 | 'R' => 44, 53 | 'S' => 45, 54 | 'T' => 46, 55 | 'U' => 47, 56 | 'V' => 48, 57 | 'W' => 49, 58 | 'X' => 50, 59 | 'Y' => 51, 60 | 'Z' => 52, 61 | _ => panic!("That's unamerican and unpartiotic"), 62 | } 63 | } 64 | 65 | fn hashset_from_content(content: Vec) -> HashSet { 66 | HashSet::from_iter(content.iter().cloned()) 67 | } 68 | 69 | struct Group3 { 70 | inner: std::io::Lines> 71 | } 72 | 73 | struct Group3Iter { 74 | inner: Group3 75 | } 76 | 77 | impl Group3 { 78 | fn iter(self) -> Group3Iter { 79 | Group3Iter {inner: self} 80 | } 81 | } 82 | 83 | impl Iterator for Group3Iter { 84 | // type Item = &'a It; 85 | type Item = (HashSet, HashSet, HashSet); 86 | 87 | fn next(&mut self) -> Option { 88 | let a = self.inner.inner.next(); 89 | let b = self.inner.inner.next(); 90 | let c = self.inner.inner.next(); 91 | match (a, b, c) { 92 | (Some(Ok(a)), Some(Ok(b)), Some (Ok(c))) => { 93 | let a_h = hashset_from_content(a.chars().collect()); 94 | let b_h = hashset_from_content(b.chars().collect()); 95 | let c_h = hashset_from_content(c.chars().collect()); 96 | Some((a_h, b_h, c_h)) 97 | } 98 | (_, _, _) => None 99 | } 100 | } 101 | } 102 | 103 | fn group3(file: File) { 104 | let grouped : Group3 = Group3 {inner: BufReader::new(file).lines()}; 105 | // let mut iter = e.iter(); 106 | // iter.next().unwrap() 107 | let mut total : u64 = 0; 108 | for (a, b, c) in grouped.iter() { 109 | let inter = a.intersection(&b); 110 | for common in inter { 111 | match c.contains(&common) { 112 | false => (), 113 | true => { 114 | total += priority(*common); 115 | }, 116 | } 117 | } 118 | } 119 | println!("Total 3 groups: {}", total); 120 | 121 | } 122 | 123 | fn _process(file: File) { 124 | let lines = BufReader::new(file).lines(); 125 | let mut total : u64 = 0; 126 | for line in lines { 127 | if let Ok(content) = line { 128 | let capacity = content.len(); 129 | let part1 : Vec = content[0..(capacity/2)].chars().collect(); 130 | let part2 : Vec = content[(capacity/2)..capacity].chars().collect(); 131 | // let compartment1: HashSet = HashSet::from_iter(part1.iter().cloned()); 132 | let compartment1: HashSet = hashset_from_content(part1); 133 | let compartment2: HashSet = hashset_from_content(part2); 134 | let common = compartment1.intersection(&compartment2); 135 | let mut common_prio : u64 = 0; 136 | for item in common { 137 | let prio = priority(*item); 138 | common_prio = common_prio + prio; 139 | } 140 | total = total + common_prio; 141 | } 142 | } 143 | println!("Total is {}", total); 144 | } 145 | 146 | fn main() { 147 | let args: Vec = env::args().collect(); 148 | 149 | let filename = args.get(1); 150 | match filename { 151 | None => println!("No filename given, bugger off"), 152 | Some(filename) => { 153 | let path = Path::new(filename); 154 | 155 | match File::open(&path) { 156 | Err(why) => println!("couldn't open file: {}", why), 157 | // Ok(file) => _process(file), 158 | Ok(file) => group3(file), 159 | } 160 | } 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /src/day8.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use std::cmp::Ordering; 6 | 7 | fn print_vis(x: &Vec>) { 8 | for line in x { 9 | let s : String = line.iter().map(|v| match v { false => "0", true => "1" }).collect(); 10 | println!("{}", s); 11 | } 12 | } 13 | 14 | fn print(x: &Vec>) { 15 | for line in x { 16 | let s : String = line.iter().map(|v| match v { 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8", 9 => "9", _ => "?"}).collect(); 17 | println!("{}", s); 18 | } 19 | } 20 | 21 | fn horizontal_of(x: usize, y: usize, forest: &Vec>) -> (Vec<&u32>, Vec<&u32>) { 22 | let line = forest.get(x).unwrap(); 23 | let left : Vec<&u32> = line[0..y].iter().rev().collect(); 24 | let right : Vec<&u32> = line[y+1..].iter().collect(); 25 | (left, right) 26 | } 27 | 28 | fn vertical_of(x: usize, y: usize, forest: &Vec>) -> (Vec<&u32>, Vec<&u32>) { 29 | let mut above : Vec<&u32> = Vec::new(); 30 | let mut below : Vec<&u32> = Vec::new(); 31 | for (i, line) in forest.iter().enumerate() { 32 | let value = line.get(y).unwrap(); 33 | match i.cmp(&x) { 34 | Ordering::Less => { 35 | above.push(value); 36 | } 37 | Ordering::Equal => (), 38 | Ordering::Greater => { 39 | below.push(value); 40 | }, 41 | }; 42 | } 43 | above.reverse(); 44 | (above, below) 45 | } 46 | 47 | fn visible_from_direction(tree: u32, direction: &Vec<&u32>) -> bool { 48 | direction.iter().all(|enemy| *enemy < &tree) 49 | } 50 | 51 | fn visible(tree: u32, left: &Vec<&u32>, right: &Vec<&u32>, top: &Vec<&u32>, bottom: &Vec<&u32>) -> bool { 52 | visible_from_direction(tree, left) || visible_from_direction(tree, right) || visible_from_direction(tree, top) || visible_from_direction(tree, bottom) 53 | } 54 | 55 | fn view_distance_from_direction(tree: u32, direction: &Vec<&u32>) -> u64 { 56 | let mut distance : u64 = 0; 57 | for e in direction { 58 | distance += 1; 59 | if *e >= &tree { 60 | break; 61 | } 62 | } 63 | distance 64 | } 65 | 66 | fn calc_vis(forest: &Vec>) -> Vec> { 67 | let mut vis : Vec> = Vec::new(); 68 | for (x, line) in forest.iter().enumerate() { 69 | let mut vis_line : Vec = Vec::new(); 70 | for (y, tree) in line.iter().enumerate() { 71 | let (left, right) = horizontal_of(x, y, forest); 72 | let (top, bottom) = vertical_of(x, y, forest); 73 | let vis = visible(*tree, &left, &right, &top, &bottom); 74 | // println!("x {} y {} tree {} left {:?} right {:?} top {:?} bottom {:?} visible {}", x, y, tree, left, right, top, bottom, vis); 75 | vis_line.push(vis); 76 | } 77 | vis.push(vis_line); 78 | } 79 | vis 80 | } 81 | 82 | fn calc_score(forest: &Vec>) -> Vec> { 83 | let mut vis : Vec> = Vec::new(); 84 | for (x, line) in forest.iter().enumerate() { 85 | let mut vis_line : Vec = Vec::new(); 86 | for (y, tree) in line.iter().enumerate() { 87 | let (left, right) = horizontal_of(x, y, forest); 88 | let (top, bottom) = vertical_of(x, y, forest); 89 | let sleft = view_distance_from_direction(*tree, &left); 90 | let sright = view_distance_from_direction(*tree, &right); 91 | let stop = view_distance_from_direction(*tree, &top); 92 | let sbottom = view_distance_from_direction(*tree, &bottom); 93 | let score = sleft * sright * stop * sbottom; 94 | // println!("x {} y {} tree {} left {:?} right {:?} top {:?} bottom {:?} score ({} * {} * {} * {}) = {}", x, y, tree, left, right, top, bottom, sleft, sright, stop, sbottom, score); 95 | vis_line.push(score); 96 | } 97 | vis.push(vis_line); 98 | } 99 | vis 100 | } 101 | 102 | fn process(file: File) { 103 | let lines = BufReader::new(file).lines(); 104 | let mut forest : Vec> = Vec::new(); 105 | for line in lines { 106 | if let Ok(content) = line { 107 | let tree_line : Vec = content.chars().map(|c| c.to_digit(10).unwrap()).collect(); 108 | forest.push(tree_line); 109 | } 110 | } 111 | print(&forest); 112 | let vis = calc_vis(&forest); 113 | let total : u64 = vis.iter().map(|l| l.iter().map(|e| match e { true => 1, false => 0}).sum::()).sum(); 114 | print_vis(&vis); 115 | println!("Visible trees: {}", total); 116 | let scores = calc_score(&forest); 117 | let max_score : u64 = *scores.iter().map(|l| l.iter().max().unwrap()).max().unwrap(); 118 | println!("Max score: {}", max_score); 119 | } 120 | 121 | fn main() { 122 | let args: Vec = env::args().collect(); 123 | 124 | let filename = args.get(1); 125 | match filename { 126 | None => println!("No filename given, bugger off"), 127 | Some(filename) => { 128 | let path = Path::new(filename); 129 | 130 | match File::open(&path) { 131 | Err(why) => println!("couldn't open file: {}", why), 132 | Ok(file) => process(file), 133 | } 134 | } 135 | } 136 | } 137 | 138 | -------------------------------------------------------------------------------- /src/day7.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::{BufRead, BufReader}; 4 | use std::path::Path; 5 | use core::slice::Iter; 6 | 7 | #[derive(Debug)] 8 | enum Fs { 9 | FileEntry(String, u64), 10 | Dir(String, Vec), 11 | } 12 | 13 | #[derive(Debug)] 14 | enum Line { 15 | Cd(String), 16 | FileEntry(String, u64), 17 | } 18 | 19 | fn parse_command(l: String) -> Option { 20 | if l.starts_with("$ ls") { 21 | None 22 | } else if l.starts_with("$ cd") { 23 | let mut chunks = l.rsplitn(2, " "); 24 | let folder = chunks.next().unwrap().to_string(); 25 | Some(Line::Cd(folder)) 26 | } else if l.starts_with("dir") { 27 | None 28 | } else { 29 | let mut chunks = l.splitn(2, " "); 30 | let size : u64 = chunks.next().unwrap().parse().unwrap(); 31 | let name = chunks.next().unwrap().to_string(); 32 | Some(Line::FileEntry(name, size)) 33 | } 34 | } 35 | 36 | fn fs_from_commands(cmds: Vec) -> Fs { 37 | 38 | fn aux(cwd : String, mut cmds: Iter) -> (Fs, Iter) { 39 | let mut current_entries : Vec = Vec::new(); 40 | 41 | loop { 42 | match cmds.next() { 43 | Some(Line::Cd(dir)) => { 44 | if dir == ".." { 45 | let fs = Fs::Dir(cwd, current_entries); 46 | return (fs, cmds); 47 | } else { 48 | let (fs, cmds_new) = aux(dir.to_string(), cmds); 49 | cmds = cmds_new; 50 | current_entries.push(fs); 51 | } 52 | }, 53 | Some(Line::FileEntry(name, size)) => { 54 | let fs = Fs::FileEntry(name.to_string(), *size); 55 | current_entries.push(fs); 56 | } 57 | 58 | None => { 59 | break; 60 | }, 61 | } 62 | } 63 | let fs = Fs::Dir(cwd, current_entries); 64 | (fs, cmds) 65 | } 66 | 67 | let (fs, _) = aux("foo".to_string(), cmds.iter()); 68 | match fs { 69 | Fs::Dir(_, mut entries) => { 70 | entries.pop().unwrap() 71 | }, 72 | Fs::FileEntry(_, _) => panic!("broken"), 73 | } 74 | } 75 | 76 | fn fs_size(fs: &Fs) -> u64 { 77 | match fs { 78 | Fs::FileEntry(_, s) => *s, 79 | Fs::Dir(_, entries) => { 80 | entries.iter().map(|e| fs_size(e)).sum() 81 | } 82 | } 83 | } 84 | 85 | fn find_at_most(size: u64, fs: &Fs) -> Vec<&Fs> { 86 | let mut found : Vec<&Fs> = Vec::new(); 87 | match fs { 88 | Fs::FileEntry(_, _) => (), 89 | Fs::Dir(_, entries) => { 90 | if fs_size(fs) <= size { 91 | found.push(fs); 92 | } 93 | for e in entries { 94 | for find in find_at_most(size, e) { 95 | found.push(find) 96 | } 97 | } 98 | } 99 | } 100 | found 101 | } 102 | 103 | fn find_at_least(size: u64, fs: &Fs) -> Vec<&Fs> { 104 | let mut found : Vec<&Fs> = Vec::new(); 105 | match fs { 106 | Fs::FileEntry(_, _) => (), 107 | Fs::Dir(_, entries) => { 108 | if fs_size(fs) >= size { 109 | found.push(fs); 110 | } 111 | for e in entries { 112 | for find in find_at_least(size, e) { 113 | found.push(find) 114 | } 115 | } 116 | } 117 | } 118 | found 119 | } 120 | 121 | fn process(file: File) { 122 | let lines = BufReader::new(file).lines(); 123 | let mut commands : Vec = Vec::new(); 124 | for line in lines { 125 | if let Ok(content) = line { 126 | let cmd = parse_command(content); 127 | match cmd { 128 | None => (), 129 | Some(v) => commands.push(v), 130 | } 131 | } 132 | } 133 | let fs = fs_from_commands(commands); 134 | println!("Entries: {:?}", &fs); 135 | println!("Size of all: {}", fs_size(&fs)); 136 | let at_most : u64 = 100000; 137 | let small_fs = find_at_most(at_most, &fs); 138 | let total_small : u64 = small_fs.iter().map(|e| fs_size(e)).sum(); 139 | println!("Total size of dirs of at most {} size: {}", at_most, total_small); 140 | 141 | let total : u64 = 70000000; 142 | let free = total - fs_size(&fs); 143 | let free_required : u64 = 30000000; 144 | let need_to_free = free_required - free; 145 | println!("Need to free {}", need_to_free); 146 | let mut larger_dirs = find_at_least(need_to_free, &fs); 147 | println!("Larger dirs {:?}", larger_dirs); 148 | larger_dirs.sort_by(|a, b| fs_size(b).cmp(&fs_size(a))); 149 | let smallest_fitting = larger_dirs.pop().unwrap(); 150 | println!("Delete {:?}, size {}", smallest_fitting, fs_size(smallest_fitting)); 151 | } 152 | 153 | fn main() { 154 | let args: Vec = env::args().collect(); 155 | 156 | let filename = args.get(1); 157 | match filename { 158 | None => println!("No filename given, bugger off"), 159 | Some(filename) => { 160 | let path = Path::new(filename); 161 | 162 | match File::open(&path) { 163 | Err(why) => println!("couldn't open file: {}", why), 164 | Ok(file) => process(file), 165 | } 166 | } 167 | } 168 | } 169 | 170 | --------------------------------------------------------------------------------