From 933afbfa89c29d9a2373c8db7367c47237ab7ad4 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Tue, 10 Dec 2024 23:16:17 +0100 Subject: [PATCH] - Use of advent_of_code_common crate - Replace HashMap and HashSet by FxHashMap and FxHashSet (better performances) --- .gitmodules | 3 + Cargo.toml | 13 ++- advent_of_code_common | 1 + src/common.rs | 25 ++-- src/day03.rs | 15 ++- src/day06.rs | 8 +- src/day10.rs | 6 +- src/day11.rs | 10 +- src/day12.rs | 8 +- src/day14.rs | 14 +-- src/day15.rs | 13 +-- src/day17.rs | 6 +- src/day18.rs | 13 ++- src/days.rs | 191 ++++++++++++++++++++++++++++++ src/main.rs | 265 +++++------------------------------------- 15 files changed, 299 insertions(+), 292 deletions(-) create mode 100644 .gitmodules create mode 160000 advent_of_code_common create mode 100644 src/days.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4413612 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "advent_of_code_common"] + path = advent_of_code_common + url = ssh://gitolite3@gburri.org:9851/advent_of_code_common.git diff --git a/Cargo.toml b/Cargo.toml index 410796d..db0f76e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,17 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -itertools = "0.10" +advent_of_code_common = { path = "advent_of_code_common" } + +itertools = "0.13" threadpool = "1.8" regex = "1" num = "0.4" -num_enum = "0.5" \ No newline at end of file +num_enum = "0.7" +rustc-hash = "2.1" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +debug = true # Needed by 'cargo flamegraph' when profiling. diff --git a/advent_of_code_common b/advent_of_code_common new file mode 160000 index 0000000..b9fa090 --- /dev/null +++ b/advent_of_code_common @@ -0,0 +1 @@ +Subproject commit b9fa0908044042af2ca3dd66281b58afd289b4e4 diff --git a/src/common.rs b/src/common.rs index ab6774b..c706ad7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,13 +1,18 @@ -use std::{fs, path::Path, str::FromStr}; +use std::{ + io::{read_to_string, BufRead}, + str::FromStr, +}; -pub fn read_list_of_numbers(file: P, sep: &str) -> Vec +pub fn read_list_of_numbers(reader: &mut dyn BufRead, sep: &str) -> Vec where - P: AsRef, T: FromStr, - T::Err: std::fmt::Debug - + T::Err: std::fmt::Debug, { - fs::read_to_string(file).unwrap().split(sep).map(|line| line.trim().parse::().unwrap()).collect() + read_to_string(reader) + .unwrap() + .split(sep) + .map(|line| line.trim().parse::().unwrap()) + .collect() } pub fn layer_to_printable_string(layer: &[u8], width: usize) -> String { @@ -15,15 +20,17 @@ pub fn layer_to_printable_string(layer: &[u8], width: usize) -> String { let mut i = 0; loop { - for _ in 0 .. width { + for _ in 0..width { if layer[i] == 0 { result += " "; } else { result += "█"; } i += 1; - if i >= layer.len() { return result } + if i >= layer.len() { + return result; + } } result += "\n"; } -} \ No newline at end of file +} diff --git a/src/day03.rs b/src/day03.rs index f6f16b8..a2cb697 100644 --- a/src/day03.rs +++ b/src/day03.rs @@ -1,7 +1,6 @@ -use std::{ - collections::{HashMap, HashSet}, - iter::{FromIterator, Iterator}, -}; +use std::iter::{FromIterator, Iterator}; + +use rustc_hash::{FxHashMap, FxHashSet}; pub fn split_movements(movements: &str) -> Vec<&str> { movements.split(',').collect() @@ -43,15 +42,15 @@ fn positions(wire: &[&str]) -> Vec<(i32, i32)> { } pub fn manhattan_distance_from_cross_to_port(wire1: &[&str], wire2: &[&str]) -> i32 { - let positions_wire1: HashSet<(i32, i32)> = HashSet::from_iter(positions(wire1)); - let positions_wire2: HashSet<(i32, i32)> = HashSet::from_iter(positions(wire2)); - let cross: HashSet<_> = positions_wire1.intersection(&positions_wire2).collect(); + let positions_wire1: FxHashSet<(i32, i32)> = FxHashSet::from_iter(positions(wire1)); + let positions_wire2: FxHashSet<(i32, i32)> = FxHashSet::from_iter(positions(wire2)); + let cross: FxHashSet<_> = positions_wire1.intersection(&positions_wire2).collect(); cross.iter().map(|(x, y)| x.abs() + y.abs()).min().unwrap() } pub fn first_cross_sum_of_lengths(wire1: &[&str], wire2: &[&str]) -> usize { let positions_wire1 = positions(wire1); - let positions_wire1_indexed: HashMap<&(i32, i32), usize> = HashMap::from_iter( + let positions_wire1_indexed: FxHashMap<&(i32, i32), usize> = FxHashMap::from_iter( positions_wire1 .iter() .enumerate() diff --git a/src/day06.rs b/src/day06.rs index 77ae402..e4a02d1 100644 --- a/src/day06.rs +++ b/src/day06.rs @@ -1,10 +1,12 @@ -use std::{cmp, collections::HashMap}; +use std::cmp; + +use rustc_hash::FxHashMap; // All planets indexing their parent (planet -> parent). -type Orbits = HashMap; +type Orbits = FxHashMap; pub fn build_orbits(orbits_str: &[&str]) -> Orbits { - let mut orbits = Orbits::new(); + let mut orbits = Orbits::default(); for orbit in orbits_str { let planets: Vec<&str> = orbit.trim().split(')').collect(); orbits.insert(String::from(planets[1]), String::from(planets[0])); diff --git a/src/day10.rs b/src/day10.rs index 799b0a8..3539e46 100644 --- a/src/day10.rs +++ b/src/day10.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use rustc_hash::{FxHashMap, FxHashSet}; pub fn read_map(raw: &str) -> Vec<(i32, i32)> { let lines: Vec<&str> = raw.lines().map(|l| l.trim()).collect(); @@ -28,7 +28,7 @@ pub fn find_best_location(map: &[(i32, i32)]) -> (usize, (i32, i32)) { let mut best_nb_observable_asteroid = 0; let (mut best_x, mut best_y) = (0, 0); for (x1, y1) in map { - let mut angles = HashSet::::new(); + let mut angles = FxHashSet::::default(); for (x2, y2) in map { angles.insert(angle(*x1, *y1, *x2, *y2)); } @@ -50,7 +50,7 @@ pub fn location_nth_vaporized_asteroid( n: usize, ) -> (i32, i32) { // Angle -> [(position, distance)]. - let mut asteroids = HashMap::::new(); + let mut asteroids = FxHashMap::::default(); let (x1, y1) = pos; for (x2, y2) in map { diff --git a/src/day11.rs b/src/day11.rs index 822e218..6da63be 100644 --- a/src/day11.rs +++ b/src/day11.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use rustc_hash::FxHashMap; use super::intcode; @@ -11,7 +11,7 @@ struct Robot { next_command: NextCommand, current_pos: (i32, i32), current_dir: i32, // 0: up, 1: right, 2: down, 3: left. - panels: HashMap<(i32, i32), i64>, + panels: FxHashMap<(i32, i32), i64>, } impl Robot { @@ -20,7 +20,7 @@ impl Robot { next_command: NextCommand::Paint, current_pos: (0, 0), current_dir: 0, - panels: HashMap::new(), + panels: FxHashMap::default(), } } } @@ -53,7 +53,7 @@ impl intcode::IO for Robot { } } -pub fn run_robot(code: &[i64], initial_value: i64) -> HashMap<(i32, i32), i64> { +pub fn run_robot(code: &[i64], initial_value: i64) -> FxHashMap<(i32, i32), i64> { let mut robot = Robot::new(); if initial_value != 0 { robot.panels.insert((0, 0), initial_value); @@ -63,7 +63,7 @@ pub fn run_robot(code: &[i64], initial_value: i64) -> HashMap<(i32, i32), i64> { robot.panels } -pub fn panels_to_layer(panels: &HashMap<(i32, i32), i64>) -> (Vec, usize) { +pub fn panels_to_layer(panels: &FxHashMap<(i32, i32), i64>) -> (Vec, usize) { let coordinates: Vec<&(i32, i32)> = panels.keys().collect(); let min_x = coordinates.iter().min_by_key(|(x, _)| x).unwrap().0; let max_x = coordinates.iter().max_by_key(|(x, _)| x).unwrap().0; diff --git a/src/day12.rs b/src/day12.rs index 34aefac..17bdedb 100644 --- a/src/day12.rs +++ b/src/day12.rs @@ -9,11 +9,9 @@ pub struct Vector3D { impl AddAssign for Vector3D { fn add_assign(&mut self, other: Self) { - *self = Self { - x: self.x + other.x, - y: self.y + other.y, - z: self.z + other.z, - }; + self.x += other.x; + self.y += other.y; + self.z += other.z; } } diff --git a/src/day14.rs b/src/day14.rs index e921cbd..313216a 100644 --- a/src/day14.rs +++ b/src/day14.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use rustc_hash::FxHashMap; #[derive(Debug)] pub struct Chemical { @@ -6,7 +6,7 @@ pub struct Chemical { name: String, } -type Reactions = HashMap)>; +type Reactions = FxHashMap)>; fn parse_chemical(input: &str) -> Chemical { let quantity_and_name: Vec<&str> = input.trim().split(' ').collect(); @@ -17,7 +17,7 @@ fn parse_chemical(input: &str) -> Chemical { } pub fn parse(input: &str) -> Reactions { - let mut result = Reactions::new(); + let mut result = Reactions::default(); for line in input.lines() { let reaction: Vec<&str> = line.split("=>").collect(); let input_chemicals: Vec = reaction[0].split(',').map(parse_chemical).collect(); @@ -31,19 +31,19 @@ pub fn parse(input: &str) -> Reactions { } pub fn ore_needed_per_fuel(reactions: &Reactions) -> i64 { - let mut remainders = HashMap::new(); + let mut remainders = FxHashMap::default(); ore_needed(reactions, 1, &mut remainders) } fn ore_needed( reactions: &Reactions, fuel_quantity: i64, - remainders: &mut HashMap, + remainders: &mut FxHashMap, ) -> i64 { fn needed( reactions: &Reactions, chemicals: &[Chemical], - remainders: &mut HashMap, + remainders: &mut FxHashMap, ) -> i64 { chemicals.iter().fold(0, |sum, chemical| { let quantity_needed = match remainders.get(&chemical.name) { @@ -111,7 +111,7 @@ fn ore_needed( pub fn fuel_produced(reactions: &Reactions, ore: i64, ore_per_fuel: i64) -> i64 { let mut ore_available = ore; let mut fuel_produced = 0; - let mut remainders = HashMap::new(); + let mut remainders = FxHashMap::default(); loop { let fuel = 1.max(ore_available / ore_per_fuel); // Approximate the fuel we can produce. diff --git a/src/day15.rs b/src/day15.rs index b2791e6..df45120 100644 --- a/src/day15.rs +++ b/src/day15.rs @@ -1,7 +1,6 @@ -use std::{ - collections::{HashMap, HashSet}, - iter::FromIterator, -}; +use std::iter::FromIterator; + +use rustc_hash::{FxHashMap, FxHashSet}; use super::intcode; @@ -15,7 +14,7 @@ enum LocationState { #[derive(Clone)] pub struct DroidTrackingSystem { - board: HashMap<(i32, i32), LocationState>, + board: FxHashMap<(i32, i32), LocationState>, current_path: Vec<(i32, i32)>, oxygen_location: (i32, i32), steps_to_oxygen: i32, @@ -25,7 +24,7 @@ pub struct DroidTrackingSystem { impl DroidTrackingSystem { fn new() -> Self { DroidTrackingSystem { - board: HashMap::from_iter(vec![((0, 0), LocationState::Visited)].into_iter()), + board: FxHashMap::from_iter(vec![((0, 0), LocationState::Visited)].into_iter()), current_path: vec![(0, 0)], oxygen_location: (0, 0), steps_to_oxygen: 0, @@ -126,7 +125,7 @@ pub fn nb_of_movement_to_reach_oxygen(code: &[i64]) -> (i32, DroidTrackingSystem pub fn time_to_flood_the_area(dts: &DroidTrackingSystem) -> i32 { let mut dts = dts.clone(); // To be mutable. dts.current_path = vec![dts.oxygen_location]; - let mut visited: HashSet<(i32, i32)> = HashSet::from_iter(dts.current_path.iter().copied()); + let mut visited: FxHashSet<(i32, i32)> = FxHashSet::from_iter(dts.current_path.iter().copied()); let mut max_length = 0; 'main: while !dts.current_path.is_empty() { diff --git a/src/day17.rs b/src/day17.rs index bdad2bb..08b5825 100644 --- a/src/day17.rs +++ b/src/day17.rs @@ -1,4 +1,6 @@ -use std::{collections::HashSet, convert::TryFrom, ops::Range}; +use std::{convert::TryFrom, ops::Range}; + +use rustc_hash::FxHashSet; use itertools::Itertools; @@ -93,7 +95,7 @@ impl RobotTrackingSystem { fn run_through(&mut self) { let (mut x, mut y) = self.start_position; let mut dir = self.start_dir; - let mut visited_locations = HashSet::<(i32, i32)>::new(); + let mut visited_locations = FxHashSet::<(i32, i32)>::default(); visited_locations.insert((x, y)); let mut last_mov = Movement::Left; diff --git a/src/day18.rs b/src/day18.rs index 3bd7819..f43b105 100644 --- a/src/day18.rs +++ b/src/day18.rs @@ -1,7 +1,8 @@ -use itertools::Itertools; -use std::collections::HashSet; use std::rc::Rc; +use itertools::Itertools; +use rustc_hash::FxHashSet; + #[derive(Debug)] pub struct Vault { tunnels: Vec>, @@ -101,7 +102,7 @@ mod v1 { pub fn nb_steps_to_collect_all_key(vault: &Vault) -> u32 { fn find_keys(from: (i32, i32), parent: Rc, vault: &Vault) -> Vec> { let mut to_visit = vec![(from, 1)]; - let mut visited_positions: HashSet<(i32, i32)> = HashSet::new(); + let mut visited_positions: FxHashSet<(i32, i32)> = FxHashSet::default(); let mut reachable_keys = Vec::>::new(); if cfg!(debug_assertions) { @@ -181,7 +182,7 @@ mod v2 { #[derive(Debug)] struct Path { to_visit: Vec<(i32, i32)>, - visited: HashSet<(i32, i32)>, + visited: FxHashSet<(i32, i32)>, keys: Vec, } @@ -189,7 +190,7 @@ mod v2 { pub fn new(initial_position: (i32, i32)) -> Self { Path { to_visit: vec![initial_position], - visited: HashSet::new(), + visited: FxHashSet::default(), keys: Vec::new(), } } @@ -246,7 +247,7 @@ mod v2 { let mut new_path = Path { to_visit: vec![adjacent], - visited: HashSet::new(), + visited: FxHashSet::default(), keys: path.keys.clone(), }; new_path.keys.push(c); diff --git a/src/days.rs b/src/days.rs new file mode 100644 index 0000000..82515b1 --- /dev/null +++ b/src/days.rs @@ -0,0 +1,191 @@ +use std::io::{read_to_string, BufRead}; + +use crate::*; + +pub fn day01(reader: &mut dyn BufRead) -> String { + let masses = common::read_list_of_numbers(reader, "\n"); + format!( + "part1: {}, part2: {}", + day01::sum_mass_to_fuel(&masses), + day01::sum_mass_to_fuel_2(&masses) + ) +} + +pub fn day02(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers(reader, ","); + format!( + "part1: {}, part2: {}", + day02::execute_op_code_with_state_fixed(&mut Vec::from(&code[..])), + day02::find_noun_and_verb(&code) + ) +} + +pub fn day03(reader: &mut dyn BufRead) -> String { + let file_content = read_to_string(reader).unwrap(); + let movements: Vec<&str> = file_content.lines().collect(); + format!( + "part1: {}, part2: {}", + day03::manhattan_distance_from_cross_to_port( + &day03::split_movements(&movements[0]), + &day03::split_movements(&movements[1]) + ), + day03::first_cross_sum_of_lengths( + &day03::split_movements(&movements[0]), + &day03::split_movements(&movements[1]) + ) + ) +} + +pub fn day04(reader: &mut dyn BufRead) -> String { + let raw = read_to_string(reader).unwrap(); + let (min, max) = day04::parse_range(&raw); + format!( + "part1: {:?}, part2: {}", + day04::nb_passwords_part1(min, max), + day04::nb_passwords_part2(min, max) + ) +} + +pub fn day05(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers(reader, ","); + format!( + "part1: {:?}, part2: {:?}", + intcode::execute_op_code(&code, &[1]), + intcode::execute_op_code(&code, &[5]) + ) +} + +pub fn day06(reader: &mut dyn BufRead) -> String { + let file_content = read_to_string(reader).unwrap(); + let lines: Vec<&str> = file_content.lines().collect(); + let orbits = day06::build_orbits(&lines); + format!( + "part1: {}, part2: {}", + day06::total_direct_and_indirect_orbits(&orbits), + day06::nb_orbital_transfers(&orbits, "SAN", "YOU") + ) +} + +pub fn day07(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers(reader, ","); + + format!( + "part1: {}, part2: {}", + day07::find_largest_last_thruster_signal(&code), + day07::find_largest_last_thruster_signal_with_feedback_loop(&code) + ) +} + +pub fn day08(reader: &mut dyn BufRead) -> String { + let img = read_to_string(reader).unwrap(); + + let raw = day08::read_from_string(&img); + let layers = day08::decode_image(&raw, 25, 6); + + let layer = day08::layer_with_fewer_0(&layers[..]); + let merged = day08::merge_layers(&layers[..]); + + format!( + "part1: {}, part2:\n{}", + day08::one_digits_times_two_digits(layer), + common::layer_to_printable_string(&merged, 25) + ) +} + +pub fn day09(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers::(reader, ","); + + format!( + "part1: {:?}, part2: {:?}", + intcode::execute_op_code(&code, &[1]), + intcode::execute_op_code(&code, &[2]) + ) +} + +pub fn day10(reader: &mut dyn BufRead) -> String { + let map = day10::read_map(&read_to_string(reader).unwrap()); + let (n, location) = day10::find_best_location(&map); + let (x, y) = day10::location_nth_vaporized_asteroid(location, &map, 200); + format!("part1: {}, part2: {}", n, x * 100 + y) +} + +pub fn day11(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers::(reader, ","); + let panels = day11::run_robot(&code, 1); + let (layer, width) = day11::panels_to_layer(&panels); + + format!( + "part1: {:?}, part2:\n{}", + day11::run_robot(&code, 0).len(), + common::layer_to_printable_string(&layer, width) + ) +} + +pub fn day12(reader: &mut dyn BufRead) -> String { + let coordinates = day12::parse_positions(&read_to_string(reader).unwrap()); + format!( + "part1: {}, part2: {}", + day12::final_energy(&coordinates, 1000), + day12::find_same_state(&coordinates) + ) +} + +pub fn day13(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers::(reader, ","); + let mut modified_code = Vec::from(&code[..]); + modified_code[0] = 2; + format!( + "part1: {}, part2: {}", + day13::count_nb_block(&code), + day13::final_score(&modified_code) + ) +} + +pub fn day14(reader: &mut dyn BufRead) -> String { + let reactions = day14::parse(&read_to_string(reader).unwrap()); + + let ore_per_fuel = day14::ore_needed_per_fuel(&reactions); + format!( + "part1: {}, part2: {}", + ore_per_fuel, + day14::fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel) + ) +} + +pub fn day15(reader: &mut dyn BufRead) -> String { + let code = common::read_list_of_numbers(reader, ","); + let (n, dts) = day15::nb_of_movement_to_reach_oxygen(&code); + format!( + "part1: {}, part2: {}", + n, + day15::time_to_flood_the_area(&dts) + ) +} + +pub fn day16(reader: &mut dyn BufRead) -> String { + let signal_raw = read_to_string(reader).unwrap(); + let signal = day16::parse(&signal_raw); + let output_part_1 = day16::fft(&signal, &[0, 1, 0, -1], 100, 0, 8, 1); + // let output_part_2 = day16::part2(&signal); + format!( + "part1: {}, part2: {}", + day16::digits_as_string(&output_part_1), + "" // day16::digits_as_string(&output_part_2) + ) +} + +pub fn day17(reader: &mut dyn BufRead) -> String { + let mut code = common::read_list_of_numbers(reader, ","); + let intersections = day17::scaffold_intersections(&code); + code[0] = 2; + let dust = day17::collected_dust(&code); + format!("part1: {}, part2: {}", intersections, dust) +} + +pub fn day18(reader: &mut dyn BufRead) -> String { + let vault_raw = read_to_string(reader).unwrap(); + let vault = day18::Vault::parse(&vault_raw); + let nb_steps = day18::nb_steps_to_collect_all_key(&vault); + + format!("part1: {}, part2: {}", nb_steps, "") +} diff --git a/src/main.rs b/src/main.rs index e23f773..cb3f314 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -use std::env; -use std::fs; -use std::time::Instant; +use std::io::BufRead; + +use advent_of_code_common; mod common; mod day01; @@ -19,243 +19,38 @@ mod day15; mod day16; mod day17; mod day18; +mod days; mod intcode; -fn day01() -> String { - let masses = common::read_list_of_numbers("data/day01.input", "\n"); - format!( - "part1: {}, part2: {}", - day01::sum_mass_to_fuel(&masses), - day01::sum_mass_to_fuel_2(&masses) - ) -} - -fn day02() -> String { - let code = common::read_list_of_numbers("data/day02.input", ","); - format!( - "part1: {}, part2: {}", - day02::execute_op_code_with_state_fixed(&mut Vec::from(&code[..])), - day02::find_noun_and_verb(&code) - ) -} - -fn day03() -> String { - let file_content = fs::read_to_string("data/day03.input").unwrap(); - let movements: Vec<&str> = file_content.lines().collect(); - format!( - "part1: {}, part2: {}", - day03::manhattan_distance_from_cross_to_port( - &day03::split_movements(&movements[0]), - &day03::split_movements(&movements[1]) - ), - day03::first_cross_sum_of_lengths( - &day03::split_movements(&movements[0]), - &day03::split_movements(&movements[1]) - ) - ) -} - -fn day04() -> String { - let raw = fs::read_to_string("data/day04.input").unwrap(); - let (min, max) = day04::parse_range(&raw); - format!( - "part1: {:?}, part2: {}", - day04::nb_passwords_part1(min, max), - day04::nb_passwords_part2(min, max) - ) -} - -fn day05() -> String { - let code = common::read_list_of_numbers("data/day05.input", ","); - format!( - "part1: {:?}, part2: {:?}", - intcode::execute_op_code(&code, &[1]), - intcode::execute_op_code(&code, &[5]) - ) -} - -fn day06() -> String { - let file_content = fs::read_to_string("data/day06.input").unwrap(); - let lines: Vec<&str> = file_content.lines().collect(); - let orbits = day06::build_orbits(&lines); - format!( - "part1: {}, part2: {}", - day06::total_direct_and_indirect_orbits(&orbits), - day06::nb_orbital_transfers(&orbits, "SAN", "YOU") - ) -} - -fn day07() -> String { - let code = common::read_list_of_numbers("data/day07.input", ","); - - format!( - "part1: {}, part2: {}", - day07::find_largest_last_thruster_signal(&code), - day07::find_largest_last_thruster_signal_with_feedback_loop(&code) - ) -} - -fn day08() -> String { - let img = fs::read_to_string("data/day08.input").unwrap(); - - let raw = day08::read_from_string(&img); - let layers = day08::decode_image(&raw, 25, 6); - - let layer = day08::layer_with_fewer_0(&layers[..]); - let merged = day08::merge_layers(&layers[..]); - - format!( - "part1: {}, part2:\n{}", - day08::one_digits_times_two_digits(layer), - common::layer_to_printable_string(&merged, 25) - ) -} - -fn day09() -> String { - let code = common::read_list_of_numbers::<&str, i64>("data/day09.input", ","); - - format!( - "part1: {:?}, part2: {:?}", - intcode::execute_op_code(&code, &[1]), - intcode::execute_op_code(&code, &[2]) - ) -} - -fn day10() -> String { - let map = day10::read_map(&fs::read_to_string("data/day10.input").unwrap()); - let (n, location) = day10::find_best_location(&map); - let (x, y) = day10::location_nth_vaporized_asteroid(location, &map, 200); - format!("part1: {}, part2: {}", n, x * 100 + y) -} - -fn day11() -> String { - let code = common::read_list_of_numbers::<&str, i64>("data/day11.input", ","); - let panels = day11::run_robot(&code, 1); - let (layer, width) = day11::panels_to_layer(&panels); - - format!( - "part1: {:?}, part2:\n{}", - day11::run_robot(&code, 0).len(), - common::layer_to_printable_string(&layer, width) - ) -} - -fn day12() -> String { - let coordinates = day12::parse_positions(&fs::read_to_string("data/day12.input").unwrap()); - format!( - "part1: {}, part2: {}", - day12::final_energy(&coordinates, 1000), - day12::find_same_state(&coordinates) - ) -} - -fn day13() -> String { - let code = common::read_list_of_numbers::<&str, i64>("data/day13.input", ","); - let mut modified_code = Vec::from(&code[..]); - modified_code[0] = 2; - format!( - "part1: {}, part2: {}", - day13::count_nb_block(&code), - day13::final_score(&modified_code) - ) -} - -fn day14() -> String { - let reactions = day14::parse(&fs::read_to_string("data/day14.input").unwrap()); - - let ore_per_fuel = day14::ore_needed_per_fuel(&reactions); - format!( - "part1: {}, part2: {}", - ore_per_fuel, - day14::fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel) - ) -} - -fn day15() -> String { - let code = common::read_list_of_numbers("data/day15.input", ","); - let (n, dts) = day15::nb_of_movement_to_reach_oxygen(&code); - format!( - "part1: {}, part2: {}", - n, - day15::time_to_flood_the_area(&dts) - ) -} - -fn day16() -> String { - let signal_raw = fs::read_to_string("data/day16.input").unwrap(); - let signal = day16::parse(&signal_raw); - let output_part_1 = day16::fft(&signal, &[0, 1, 0, -1], 100, 0, 8, 1); - // let output_part_2 = day16::part2(&signal); - format!( - "part1: {}, part2: {}", - day16::digits_as_string(&output_part_1), - /*day16::digits_as_string(&output_part_2)*/ "" - ) -} - -fn day17() -> String { - let mut code = common::read_list_of_numbers("data/day17.input", ","); - let intersections = day17::scaffold_intersections(&code); - code[0] = 2; - let dust = day17::collected_dust(&code); - format!("part1: {}, part2: {}", intersections, dust) -} - -fn day18() -> String { - let vault_raw = fs::read_to_string("data/day18.input").unwrap(); - let vault = day18::Vault::parse(&vault_raw); - let nb_steps = day18::nb_steps_to_collect_all_key(&vault); - - format!("part1: {}, part2: {}", nb_steps, "") -} - -fn format_micros(t: u128) -> String { - if t < 10_000 { - format!("{} μs", t) - } else if t < 10_000_000u128 { - format!("{} ms", t / 1_000u128) - } else { - format!("{} s", t / 1_000_000u128) - } -} - -fn do_day(days: &[fn() -> String], day: usize) { - let now = Instant::now(); - println!( - "Result of day {:02}: {} (time: {})", - day, - days[day - 1](), - format_micros(now.elapsed().as_micros()) - ); -} - fn main() { println!("https://adventofcode.com/2019"); - let days: Vec String> = vec![ - day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13, - day14, day15, day16, day17, day18, + let days: Vec String> = vec![ + days::day01, + days::day02, + days::day03, + days::day04, + days::day05, + days::day06, + days::day07, + days::day08, + days::day09, + days::day10, + days::day11, + days::day12, + days::day13, + days::day14, + days::day15, + days::day16, + days::day17, + days::day18, + // days::day19, + // days::day20, + // days::day21, + // days::day22, + // days::day23, + // days::day24, ]; - let args: Vec = env::args().skip(1).collect(); - - // No argument -> execute all day problems. - if args.is_empty() { - let now = Instant::now(); - for i in 1..=days.len() { - do_day(&days, i) - } - println!( - "Time to execute all days: {}", - format_micros(now.elapsed().as_micros()) - ); - } else { - for arg in args { - match arg.parse::() { - Ok(day) if day >= 1 && day <= days.len() => do_day(&days, day), - Ok(day) => println!("Unknown day: {}", day), - Err(error) => println!("Unable to parse day number: \"{}\", error: {}", arg, error), - } - } - } + advent_of_code_common::run(days); } -- 2.45.2