days 7-10
							parent
							
								
									474ad0a248
								
							
						
					
					
						commit
						db450943a0
					
				| @ -0,0 +1,16 @@ | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "day07" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "rustc-hash", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rustc-hash" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | ||||
| @ -0,0 +1,9 @@ | ||||
| [package] | ||||
| name = "day07" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| rustc-hash = "1.1.0" | ||||
| @ -0,0 +1,134 @@ | ||||
| use rustc_hash::FxHashMap; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| const TOTAL_SPACE: usize = 70_000_000; | ||||
| const REQUIRED_SPACE: usize = 30_000_000; | ||||
| 
 | ||||
| fn main() { | ||||
|     let s = std::fs::read_to_string("/dev/stdin").unwrap(); | ||||
|     let mut commands = s.split("$ "); | ||||
|     commands.next(); // chuck out first empty string
 | ||||
|     let mut pwd: Option<String> = None; | ||||
|     let mut file_tree: FxHashMap<String, Vec<(String, Option<usize>)>> = FxHashMap::default(); | ||||
|     let mut dir_totals: FxHashMap<String, usize> = FxHashMap::default(); | ||||
| 
 | ||||
|     for command in commands { | ||||
|         let lines = command.lines().collect::<Vec<&str>>(); | ||||
|         let cmd = lines.first().unwrap(); | ||||
|         let args = cmd.split(' ').collect::<Vec<&str>>(); | ||||
|         let cmd = args.first().unwrap(); | ||||
|         let args = args.get(1..).unwrap(); | ||||
| 
 | ||||
|         match *cmd { | ||||
|             "cd" => cd(&mut pwd, args), | ||||
|             "ls" => ls( | ||||
|                 &pwd, | ||||
|                 lines.get(1..).unwrap(), | ||||
|                 &mut file_tree, | ||||
|                 &mut dir_totals, | ||||
|             ), | ||||
|             invalid => panic!("unexpected command: {:?}", invalid), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for directory in file_tree.iter() { | ||||
|         let mut total = 0; | ||||
|         let dir_str = Path::new(&directory.0); | ||||
| 
 | ||||
|         if dir_str.file_name().is_some() | ||||
|             && dir_totals.contains_key(&dir_str.to_str().unwrap().to_string()) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         for item in directory.1.iter() { | ||||
|             if let Some(file_size) = item.1 { | ||||
|                 total += file_size; | ||||
|             } | ||||
|         } | ||||
|         dir_totals.insert(directory.0.to_string(), total); | ||||
|     } | ||||
| 
 | ||||
|     let mut dirs = file_tree.iter().collect::<Vec<_>>(); | ||||
|     dirs.sort_by(|a, b| { | ||||
|         b.0.split('/') | ||||
|             .count() | ||||
|             .cmp(&a.0.split('/').count()) | ||||
|             .then(b.0.len().cmp(&a.0.len())) | ||||
|     }); | ||||
|     for dir in dirs.iter() { | ||||
|         for sub_dir in dir.1.iter().filter(|dir| dir.1.is_none()) { | ||||
|             let balls = (dir.0.to_owned() + &sub_dir.0.replace("dir ", "/")).replace("//", "/"); | ||||
| 
 | ||||
|             dir_totals.insert( | ||||
|                 dir.0.to_owned(), | ||||
|                 *dir_totals.get(&dir.0.to_owned()).unwrap() + *dir_totals.get(&balls).unwrap(), | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let sum = dir_totals | ||||
|         .iter() | ||||
|         .filter(|dir| dir.1 < &100000) | ||||
|         .fold(0, |total, dir| total + dir.1); | ||||
| 
 | ||||
|     let free_space = TOTAL_SPACE - dir_totals.get("/").unwrap(); | ||||
|     let minimum_required = REQUIRED_SPACE - free_space; | ||||
| 
 | ||||
|     let mut deletable: Vec<(&String, &usize)> = dir_totals | ||||
|         .iter() | ||||
|         .filter(|dir| dir.1 >= &minimum_required) | ||||
|         .collect(); | ||||
|     deletable.sort_by(|a, b| a.1.cmp(b.1)); | ||||
|     println!("P1: {} P2: {}", sum, deletable.first().unwrap().1); | ||||
| } | ||||
| 
 | ||||
| fn cd(pwd: &mut Option<String>, args: &[&str]) { | ||||
|     let path_str = String::new(); | ||||
|     let path = pwd.as_ref().unwrap_or(&path_str); | ||||
|     let dir = args.first().expect("cd requries an arg").to_string(); | ||||
|     if dir == ".." { | ||||
|         let mut split_path = path.split('/').collect::<Vec<&str>>(); | ||||
|         split_path.pop(); | ||||
|         if split_path.len() == 1 { | ||||
|             split_path.push(""); | ||||
|         } | ||||
|         *pwd = Some(split_path.join("/")); | ||||
|     } else if !path.is_empty() && path != "/" { | ||||
|         *pwd = Some(path.to_owned() + "/" + &dir); | ||||
|     } else { | ||||
|         *pwd = Some(path.to_owned() + &dir); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn ls( | ||||
|     pwd: &Option<String>, | ||||
|     lines: &[&str], | ||||
|     file_tree: &mut FxHashMap<String, Vec<(String, Option<usize>)>>, | ||||
|     dir_totals: &mut FxHashMap<String, usize>, | ||||
| ) { | ||||
|     let mut contents: Vec<(String, Option<usize>)> = Vec::new(); | ||||
|     let mut contains_dirs = false; // if no inner dirs, work out total here
 | ||||
| 
 | ||||
|     for line in lines { | ||||
|         if line.starts_with("dir ") { | ||||
|             contents.push((line.to_string(), None)); | ||||
|             contains_dirs = true; | ||||
|             continue; | ||||
|         } | ||||
|         let file_data = line.split_once(' ').unwrap(); | ||||
|         let (file_size, file_name) = ( | ||||
|             file_data.0.parse::<usize>().unwrap(), | ||||
|             file_data.1.to_string(), | ||||
|         ); | ||||
|         contents.push((file_name, Some(file_size))); | ||||
|     } | ||||
|     if !contains_dirs { | ||||
|         let mut total = 0; | ||||
|         for (_, size) in contents.iter() { | ||||
|             total += size.unwrap(); | ||||
|         } | ||||
|         dir_totals.insert(pwd.as_ref().unwrap().to_string(), total); | ||||
|     } | ||||
|     file_tree.insert(pwd.as_ref().unwrap().to_string(), contents); | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "day09" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "rustc-hash", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rustc-hash" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | ||||
| @ -0,0 +1,9 @@ | ||||
| [package] | ||||
| name = "day09" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| rustc-hash = "1.1.0" | ||||
| @ -0,0 +1,73 @@ | ||||
| use rustc_hash::FxHashSet; | ||||
| use std::cmp::Ordering; | ||||
| use std::io::{self, BufRead}; | ||||
| 
 | ||||
| fn main() { | ||||
|     let lines = io::stdin().lock().lines().map(|l| l.unwrap()); | ||||
| 
 | ||||
|     let mut head = (0, 0); | ||||
|     let mut knots: Vec<(isize, isize)> = vec![(0, 0); 9]; | ||||
|     let mut visited_p1: FxHashSet<(isize, isize)> = FxHashSet::default(); | ||||
|     let mut visited_p2: FxHashSet<(isize, isize)> = FxHashSet::default(); | ||||
| 
 | ||||
|     visited_p1.insert((0, 0)); | ||||
|     visited_p2.insert((0, 0)); | ||||
| 
 | ||||
|     for line in lines { | ||||
|         let (dir, len) = line.split_once(' ').unwrap(); | ||||
|         let position = (dir, len.parse::<isize>().unwrap()); | ||||
|         let mut current; | ||||
| 
 | ||||
|         for _ in 0..position.1 { | ||||
|             step_head(&mut head, position.0); | ||||
|             current = head; | ||||
| 
 | ||||
|             for i in 0..9 { | ||||
|                 let knot = knots.get_mut(i).unwrap(); | ||||
|                 follow(i, current, knot, &mut visited_p1, &mut visited_p2); | ||||
|                 current = *knot; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     println!("P1: {}, P2: {}", visited_p1.len(), visited_p2.len()); | ||||
| } | ||||
| 
 | ||||
| fn step_head(head: &mut (isize, isize), dir: &str) { | ||||
|     match dir { | ||||
|         "L" => head.1 -= 1, | ||||
|         "R" => head.1 += 1, | ||||
|         "U" => head.0 -= 1, | ||||
|         "D" => head.0 += 1, | ||||
|         invalid => panic!("invalid direction '{}'", invalid), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn follow( | ||||
|     idx: usize, | ||||
|     head: (isize, isize), | ||||
|     tail: &mut (isize, isize), | ||||
|     visited_p1: &mut FxHashSet<(isize, isize)>, | ||||
|     visited_p2: &mut FxHashSet<(isize, isize)>, | ||||
| ) { | ||||
|     let diffx = (tail.0 - head.0).abs(); | ||||
|     let diffy = (tail.1 - head.1).abs(); | ||||
|     if (diffx == 1 || diffx == 0) && (diffy == 1 || diffy == 0) { | ||||
|         return; | ||||
|     } | ||||
|     match tail.0.cmp(&head.0) { | ||||
|         Ordering::Greater => tail.0 -= 1, | ||||
|         Ordering::Less => tail.0 += 1, | ||||
|         _ => (), | ||||
|     } | ||||
|     match tail.1.cmp(&head.1) { | ||||
|         Ordering::Greater => tail.1 -= 1, | ||||
|         Ordering::Less => tail.1 += 1, | ||||
|         _ => (), | ||||
|     } | ||||
|     if idx == 0 { | ||||
|         visited_p1.insert(*tail); | ||||
|     } | ||||
|     if idx == 8 { | ||||
|         visited_p2.insert(*tail); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,7 @@ | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "day10" | ||||
| version = "0.1.0" | ||||
| @ -0,0 +1,8 @@ | ||||
| [package] | ||||
| name = "day10" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| @ -0,0 +1,83 @@ | ||||
| use std::collections::VecDeque; | ||||
| use std::io::{self, BufRead, Write}; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| struct Operation { | ||||
|     opcode: String, | ||||
|     arg: Option<isize>, | ||||
|     cycles: usize, | ||||
| } | ||||
| 
 | ||||
| const SIGNAL_TICK_COUNT: usize = 220; | ||||
| const DRAW_CRT: usize = 240; | ||||
| 
 | ||||
| fn main() { | ||||
|     let lines = io::stdin().lock().lines().map(|l| l.unwrap()); | ||||
| 
 | ||||
|     let mut program: Vec<Operation> = vec![]; | ||||
|     let mut queue: VecDeque<&Operation> = VecDeque::new(); | ||||
| 
 | ||||
|     for line in lines { | ||||
|         let cmd = line.split(' ').collect::<Vec<&str>>(); | ||||
|         let op = cmd.first().unwrap(); | ||||
|         let mut arg: Option<isize> = None; | ||||
| 
 | ||||
|         if let Some(num) = cmd.get(1) { | ||||
|             arg = Some(num.parse::<isize>().unwrap()); | ||||
|         } | ||||
|         let cycles = match op { | ||||
|             &"noop" => 1, | ||||
|             &"addx" => 2, | ||||
|             invalid => panic!("invalid opcode {}", invalid), | ||||
|         }; | ||||
|         program.push(Operation { | ||||
|             opcode: op.to_string(), | ||||
|             arg, | ||||
|             cycles, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // init counters, program and queue
 | ||||
|     let mut x = 1; | ||||
|     let mut current_op = program.first().unwrap(); | ||||
|     let mut cycles_remaining_for_current = current_op.cycles; | ||||
|     let mut signal_sum = 0; | ||||
|     let mut screen = [[false; 40]; 6]; | ||||
| 
 | ||||
|     for (screen_idx, i) in (1..DRAW_CRT + 1).enumerate() { | ||||
|         if cycles_remaining_for_current == 0 { | ||||
|             if current_op.opcode == "addx" { | ||||
|                 x += current_op.arg.unwrap(); | ||||
|             } | ||||
|             current_op = queue.pop_front().unwrap(); | ||||
|             cycles_remaining_for_current = current_op.cycles; | ||||
|         } | ||||
|         let cmd = program.get(i % program.len()).unwrap(); | ||||
|         queue.push_back(cmd); | ||||
|         cycles_remaining_for_current -= 1; | ||||
|         match i { | ||||
|             20 | 60 | 100 | 140 | 180 | 220 => signal_sum += x * i as isize, | ||||
|             _ => (), | ||||
|         } | ||||
| 
 | ||||
|         let (scrx, scry): (usize, usize) = (screen_idx / 40, screen_idx % 40); | ||||
|         screen[scrx][scry] = x == screen_idx as isize % 40 | ||||
|             || x - 1 == screen_idx as isize % 40 | ||||
|             || x + 1 == screen_idx as isize % 40; | ||||
| 
 | ||||
|         if i == SIGNAL_TICK_COUNT { | ||||
|             println!("{}", signal_sum); | ||||
|         } | ||||
|     } | ||||
|     draw_screen(&screen); | ||||
| } | ||||
| 
 | ||||
| fn draw_screen(screen: &[[bool; 40]; 6]) { | ||||
|     let mut lock = io::stdout().lock(); | ||||
|     for y in 0..6 { | ||||
|         for x in 0..40 { | ||||
|             write!(lock, "{}", if screen[y][x] { "#" } else { "." }).unwrap() | ||||
|         } | ||||
|         writeln!(lock).unwrap(); | ||||
|     } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue