# These are backup files generated by rustfmt
**/*.rs.bk
-data/day08.png
+
+data/day*
\ No newline at end of file
--- /dev/null
+Filename: "dayXX.input"
\ No newline at end of file
}\r
\r
pub fn sum_mass_to_fuel_2(masses: &[i32]) -> i32 {\r
- masses.iter().fold(0, |sum, mass| sum + mass_to_fuel_2(*mass))\r
+ masses\r
+ .iter()\r
+ .fold(0, |sum, mass| sum + mass_to_fuel_2(*mass))\r
}\r
\r
fn mass_to_fuel(mass: i32) -> i32 {\r
let mut current_mass = mass;\r
loop {\r
let fuel = mass_to_fuel(current_mass);\r
- if fuel <= 0 { break }\r
+ if fuel <= 0 {\r
+ break;\r
+ }\r
current_mass = fuel;\r
sum += fuel;\r
}\r
assert_eq!(mass_to_fuel_2(1969), 966);\r
assert_eq!(mass_to_fuel_2(100_756), 50346);\r
}\r
-}
\ No newline at end of file
+}\r
let mut cursor = 0;\r
loop {\r
match code[cursor] {\r
- 1 => code[code[cursor + 3] as usize] = code[code[cursor + 1] as usize] + code[code[cursor + 2] as usize],\r
- 2 => code[code[cursor + 3] as usize] = code[code[cursor + 1] as usize] * code[code[cursor + 2] as usize],\r
+ 1 => {\r
+ code[code[cursor + 3] as usize] =\r
+ code[code[cursor + 1] as usize] + code[code[cursor + 2] as usize]\r
+ }\r
+ 2 => {\r
+ code[code[cursor + 3] as usize] =\r
+ code[code[cursor + 1] as usize] * code[code[cursor + 2] as usize]\r
+ }\r
99 => return code[0],\r
- _ => panic!("Unknown code: {}", code[cursor])\r
+ _ => panic!("Unknown code: {}", code[cursor]),\r
}\r
cursor += 4;\r
}\r
code_copy[1] = noun;\r
code_copy[2] = verb;\r
if execute_op_code(&mut code_copy) == 19_690_720 {\r
- return 100 * noun + verb\r
+ return 100 * noun + verb;\r
}\r
}\r
}\r
execute_op_code(&mut c4);\r
assert_eq!(c4[0], 30);\r
}\r
-}
\ No newline at end of file
+}\r
-use std::{collections::{HashMap, HashSet}, iter::{Iterator, FromIterator}};\r
+use std::{\r
+ collections::{HashMap, HashSet},\r
+ iter::{FromIterator, Iterator},\r
+};\r
\r
pub fn split_movements(movements: &str) -> Vec<&str> {\r
movements.split(',').collect()\r
for mov in wire {\r
let distance = mov[1..].parse::<i32>().unwrap();\r
match mov.chars().nth(0).unwrap() {\r
- 'U' => { for y2 in y+1 ..= y + distance { pos.push((x, y2)); } y += distance },\r
- 'D' => { for y2 in (y - distance .. y).rev() { pos.push((x, y2)); } y -= distance },\r
- 'R' => { for x2 in x+1 ..= x + distance { pos.push((x2, y)); } x += distance },\r
- 'L' | _ => { for x2 in (x - distance .. x).rev() { pos.push((x2, y)); } x -= distance },\r
+ 'U' => {\r
+ for y2 in y + 1..=y + distance {\r
+ pos.push((x, y2));\r
+ }\r
+ y += distance\r
+ }\r
+ 'D' => {\r
+ for y2 in (y - distance..y).rev() {\r
+ pos.push((x, y2));\r
+ }\r
+ y -= distance\r
+ }\r
+ 'R' => {\r
+ for x2 in x + 1..=x + distance {\r
+ pos.push((x2, y));\r
+ }\r
+ x += distance\r
+ }\r
+ 'L' | _ => {\r
+ for x2 in (x - distance..x).rev() {\r
+ pos.push((x2, y));\r
+ }\r
+ x -= distance\r
+ }\r
}\r
}\r
pos\r
\r
pub fn first_cross_sum_of_lengths(wire1: &[&str], wire2: &[&str]) -> usize {\r
let positions_wire1 = positions(wire1);\r
- let positions_wire1_indexed: HashMap<&(i32, i32), usize> = HashMap::from_iter(positions_wire1.iter().enumerate().map(|(i, pos)| (pos, i)).rev());\r
+ let positions_wire1_indexed: HashMap<&(i32, i32), usize> = HashMap::from_iter(\r
+ positions_wire1\r
+ .iter()\r
+ .enumerate()\r
+ .map(|(i, pos)| (pos, i))\r
+ .rev(),\r
+ );\r
\r
positions(wire2)\r
- .iter().enumerate().filter_map(\r
- |(j, pos2)| {\r
- if let Some (i) = positions_wire1_indexed.get(pos2) {\r
- Some (j + i + 2)\r
- } else {\r
- None\r
- }\r
+ .iter()\r
+ .enumerate()\r
+ .filter_map(|(j, pos2)| {\r
+ if let Some(i) = positions_wire1_indexed.get(pos2) {\r
+ Some(j + i + 2)\r
+ } else {\r
+ None\r
}\r
- ).min().unwrap()\r
+ })\r
+ .min()\r
+ .unwrap()\r
}\r
\r
#[cfg(test)]\r
410\r
);\r
}\r
-}
\ No newline at end of file
+}\r
use std::cmp::Ordering;\r
\r
pub fn parse_range(raw: &str) -> (i32, i32) {\r
- let nums: Vec<i32> = raw.trim().split('-').map(|n| n.parse::<i32>().unwrap()).collect();\r
+ let nums: Vec<i32> = raw\r
+ .trim()\r
+ .split('-')\r
+ .map(|n| n.parse::<i32>().unwrap())\r
+ .collect();\r
(nums[0], nums[1])\r
}\r
\r
}\r
\r
pub fn nb_passwords_part1(min: i32, max: i32) -> i32 {\r
- nb_passwords(\r
- min,\r
- max,\r
- &|digits: &Digits| {\r
- for i in 1 .. digits.len() {\r
- if digits[i - 1] == digits[i] { return true; }\r
+ nb_passwords(min, max, &|digits: &Digits| {\r
+ for i in 1..digits.len() {\r
+ if digits[i - 1] == digits[i] {\r
+ return true;\r
}\r
- false\r
}\r
- )\r
+ false\r
+ })\r
}\r
\r
pub fn nb_passwords_part2(min: i32, max: i32) -> i32 {\r
- nb_passwords(\r
- min,\r
- max,\r
- &|digits: &Digits| {\r
- let mut last = digits[0];\r
- let mut n = 1;\r
- for d in &digits[1..] {\r
- if *d == last {\r
- n += 1;\r
- } else {\r
- if n == 2 { return true; }\r
- n = 1;\r
+ nb_passwords(min, max, &|digits: &Digits| {\r
+ let mut last = digits[0];\r
+ let mut n = 1;\r
+ for d in &digits[1..] {\r
+ if *d == last {\r
+ n += 1;\r
+ } else {\r
+ if n == 2 {\r
+ return true;\r
}\r
- last = *d;\r
+ n = 1;\r
}\r
- n == 2\r
+ last = *d;\r
}\r
- )\r
+ n == 2\r
+ })\r
}\r
\r
fn nb_passwords(min: i32, max: i32, valid_password: &dyn Fn(&Digits) -> bool) -> i32 {\r
let l = digits.len();\r
\r
fn set_range(from: usize, to: usize, value: u8, digits: &mut Digits) {\r
- for d in &mut digits[from .. to] { *d = value; }\r
+ for d in &mut digits[from..to] {\r
+ *d = value;\r
+ }\r
}\r
\r
- for i in (1 .. l).rev() {\r
+ for i in (1..l).rev() {\r
if digits[i - 1] < digits[i] {\r
set_range(0, i, digits[i], &mut digits);\r
break;\r
let mut n = 0;\r
\r
loop {\r
- if valid_password(&digits) { n += 1; }\r
+ if valid_password(&digits) {\r
+ n += 1;\r
+ }\r
\r
- for i in 0 .. l {\r
+ for i in 0..l {\r
if i == l - 1 || digits[i + 1] <= digits[i] && digits[i] != 9 {\r
set_range(0, i + 1, digits[i] + 1, &mut digits);\r
break;\r
}\r
}\r
\r
- for i in (0 .. l).rev() {\r
+ for i in (0..l).rev() {\r
match digits[i].cmp(&digits_max[i]) {\r
Ordering::Greater => return n,\r
Ordering::Less => break,\r
- Ordering::Equal => ()\r
+ Ordering::Equal => (),\r
}\r
}\r
}\r
-}
\ No newline at end of file
+}\r
let mut parents = Vec::<&str>::new();
let mut current_planet = planet;
- while let Some (parent) = orbits.get(current_planet) {
+ while let Some(parent) = orbits.get(current_planet) {
parents.insert(0, parent);
current_planet = parent;
}
}
pub fn total_direct_and_indirect_orbits(orbits: &Orbits) -> usize {
- orbits.keys().fold(0, |sum, planet| { sum + parents(orbits, &planet).len() })
+ orbits
+ .keys()
+ .fold(0, |sum, planet| sum + parents(orbits, &planet).len())
}
pub fn nb_orbital_transfers(orbits: &Orbits, loc1: &str, loc2: &str) -> usize {
let parents_loc2 = parents(orbits, loc2);
for i in 0..cmp::min(parents_loc1.len(), parents_loc2.len()) {
if parents_loc1[i] != parents_loc2[i] {
- return parents_loc1.len() + parents_loc2.len() - 2 * i
+ return parents_loc1.len() + parents_loc2.len() - 2 * i;
}
}
0
#[test]
fn part1() {
- let lines: Vec<&str> =
- "COM)B
+ let lines: Vec<&str> = "COM)B
B)C
C)D
D)E
D)I
E)J
J)K
- K)L".lines().collect();
+ K)L"
+ .lines()
+ .collect();
let n = total_direct_and_indirect_orbits(&build_orbits(&lines));
assert_eq!(n, 42);
#[test]
fn part2() {
- let lines: Vec<&str> =
- "COM)B
+ let lines: Vec<&str> = "COM)B
B)C
C)D
D)E
J)K
K)L
K)YOU
- I)SAN".lines().collect();
+ I)SAN"
+ .lines()
+ .collect();
let n = nb_orbital_transfers(&build_orbits(&lines), "SAN", "YOU");
assert_eq!(n, 4);
}
-}
\ No newline at end of file
+}
-use std::sync::{Arc, Barrier, mpsc::{self, Sender, Receiver}, atomic::{AtomicI64, Ordering}};\r
+use std::sync::{\r
+ atomic::{AtomicI64, Ordering},\r
+ mpsc::{self, Receiver, Sender},\r
+ Arc, Barrier,\r
+};\r
\r
use itertools::Itertools;\r
use threadpool::ThreadPool;\r
use super::intcode;\r
\r
fn last_thruster_signal(code: &[i64], phase_setting: &[i64]) -> i64 {\r
- phase_setting.iter().fold(0, |last_output, input| intcode::execute_op_code(&code, &[*input, last_output])[0])\r
+ phase_setting.iter().fold(0, |last_output, input| {\r
+ intcode::execute_op_code(&code, &[*input, last_output])[0]\r
+ })\r
}\r
\r
pub fn find_largest_last_thruster_signal(code: &[i64]) -> i64 {\r
- (0i64 ..= 4i64).permutations(5).map(|phase_setting| last_thruster_signal(&code, &phase_setting)).max().unwrap()\r
+ (0i64..=4i64)\r
+ .permutations(5)\r
+ .map(|phase_setting| last_thruster_signal(&code, &phase_setting))\r
+ .max()\r
+ .unwrap()\r
}\r
\r
struct Stage {\r
input_channel: mpsc::Receiver<i64>,\r
output_channel: mpsc::Sender<i64>,\r
- last_produced_value: i64\r
+ last_produced_value: i64,\r
}\r
\r
impl intcode::IO for Stage {\r
fn read(&mut self) -> i64 {\r
match self.input_channel.recv() {\r
Ok(value) => value,\r
- Err(_) => 0\r
+ Err(_) => 0,\r
}\r
}\r
\r
}\r
}\r
\r
-fn last_thruster_signal_with_feedback_loop(code: &[i64], phase_setting: &[i64], pool: &ThreadPool) -> i64 {\r
+fn last_thruster_signal_with_feedback_loop(\r
+ code: &[i64],\r
+ phase_setting: &[i64],\r
+ pool: &ThreadPool,\r
+) -> i64 {\r
let n = phase_setting.len();\r
\r
let mut senders = Vec::<Sender<i64>>::new();\r
let mut receivers = Vec::<Receiver<i64>>::new();\r
\r
- for (i, (s, r)) in (0 .. n).map(|i| (i, mpsc::channel::<i64>())) {\r
+ for (i, (s, r)) in (0..n).map(|i| (i, mpsc::channel::<i64>())) {\r
// Initial values.\r
s.send(phase_setting[i]).unwrap_or_default();\r
- if i == 0 { s.send(0).unwrap_or_default(); }\r
+ if i == 0 {\r
+ s.send(0).unwrap_or_default();\r
+ }\r
\r
senders.insert(if i == 0 { 0 } else { i - 1 }, s);\r
receivers.push(r);\r
}\r
\r
// Prepare each pair of received and sender for the each stages.\r
- let mut channels: Vec<(Receiver<i64>, Sender<i64>)> = receivers.drain(..).zip(senders.drain(..)).collect();\r
+ let mut channels: Vec<(Receiver<i64>, Sender<i64>)> =\r
+ receivers.drain(..).zip(senders.drain(..)).collect();\r
\r
let result = Arc::new(AtomicI64::new(0));\r
let barrier = Arc::new(Barrier::new(2));\r
let barrier = barrier.clone();\r
let result = result.clone();\r
\r
- pool.execute(\r
- move || {\r
- let mut stage = Stage { input_channel: receiver, output_channel: sender, last_produced_value: 0 };\r
- intcode::execute_op_code_with_custom_io(&code_copy, &mut stage);\r
- if i == 4 {\r
- result.store(stage.last_produced_value, Ordering::Relaxed);\r
- barrier.wait();\r
- }\r
+ pool.execute(move || {\r
+ let mut stage = Stage {\r
+ input_channel: receiver,\r
+ output_channel: sender,\r
+ last_produced_value: 0,\r
+ };\r
+ intcode::execute_op_code_with_custom_io(&code_copy, &mut stage);\r
+ if i == 4 {\r
+ result.store(stage.last_produced_value, Ordering::Relaxed);\r
+ barrier.wait();\r
}\r
- )\r
+ })\r
}\r
\r
barrier.wait();\r
\r
pub fn find_largest_last_thruster_signal_with_feedback_loop(code: &[i64]) -> i64 {\r
let pool = ThreadPool::new(5);\r
- (5i64 ..= 9i64).permutations(5).map(|phase_setting| last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool)).max().unwrap()\r
+ (5i64..=9i64)\r
+ .permutations(5)\r
+ .map(|phase_setting| last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool))\r
+ .max()\r
+ .unwrap()\r
}\r
\r
#[cfg(test)]\r
\r
#[test]\r
fn part1_sample_1() {\r
- let code = vec![3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0];\r
- let phase_setting = [4,3,2,1,0];\r
+ let code = vec![\r
+ 3, 15, 3, 16, 1002, 16, 10, 16, 1, 16, 15, 15, 4, 15, 99, 0, 0,\r
+ ];\r
+ let phase_setting = [4, 3, 2, 1, 0];\r
assert_eq!(last_thruster_signal(&code, &phase_setting), 43210);\r
}\r
\r
#[test]\r
fn part1_sample_2() {\r
- let code = vec![3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0];\r
- let phase_setting = [0,1,2,3,4];\r
+ let code = vec![\r
+ 3, 23, 3, 24, 1002, 24, 10, 24, 1002, 23, -1, 23, 101, 5, 23, 23, 1, 24, 23, 23, 4, 23,\r
+ 99, 0, 0,\r
+ ];\r
+ let phase_setting = [0, 1, 2, 3, 4];\r
assert_eq!(last_thruster_signal(&code, &phase_setting), 54321);\r
}\r
\r
#[test]\r
fn part1_sample_3() {\r
- let code = vec![3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0];\r
- let phase_setting = [1,0,4,3,2];\r
+ let code = vec![\r
+ 3, 31, 3, 32, 1002, 32, 10, 32, 1001, 31, -2, 31, 1007, 31, 0, 33, 1002, 33, 7, 33, 1,\r
+ 33, 31, 31, 1, 32, 31, 31, 4, 31, 99, 0, 0, 0,\r
+ ];\r
+ let phase_setting = [1, 0, 4, 3, 2];\r
assert_eq!(last_thruster_signal(&code, &phase_setting), 65210);\r
}\r
\r
#[test]\r
fn part2_sample_1() {\r
- let code = vec![3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5];\r
- let phase_setting = [9,8,7,6,5];\r
+ let code = vec![\r
+ 3, 26, 1001, 26, -4, 26, 3, 27, 1002, 27, 2, 27, 1, 27, 26, 27, 4, 27, 1001, 28, -1,\r
+ 28, 1005, 28, 6, 99, 0, 0, 5,\r
+ ];\r
+ let phase_setting = [9, 8, 7, 6, 5];\r
let pool = ThreadPool::new(5);\r
- assert_eq!(last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool), 139_629_729);\r
+ assert_eq!(\r
+ last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool),\r
+ 139_629_729\r
+ );\r
}\r
\r
#[test]\r
fn part2_sample_2() {\r
- let code = vec![3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10];\r
- let phase_setting = [9,7,8,5,6];\r
+ let code = vec![\r
+ 3, 52, 1001, 52, -5, 52, 3, 53, 1, 52, 56, 54, 1007, 54, 5, 55, 1005, 55, 26, 1001, 54,\r
+ -5, 54, 1105, 1, 12, 1, 53, 54, 53, 1008, 54, 0, 55, 1001, 55, 1, 55, 2, 53, 55, 53, 4,\r
+ 53, 1001, 56, -1, 56, 1005, 56, 6, 99, 0, 0, 0, 0, 10,\r
+ ];\r
+ let phase_setting = [9, 7, 8, 5, 6];\r
let pool = ThreadPool::new(5);\r
- assert_eq!(last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool), 18_216);\r
+ assert_eq!(\r
+ last_thruster_signal_with_feedback_loop(&code, &phase_setting, &pool),\r
+ 18_216\r
+ );\r
}\r
-}
\ No newline at end of file
+}\r
pub fn read_from_string(raw: &str) -> Vec<u8> {
- raw.chars().map(|c| c.to_digit(10).unwrap() as u8).collect::<Vec<u8>>()
+ raw.chars()
+ .map(|c| c.to_digit(10).unwrap() as u8)
+ .collect::<Vec<u8>>()
}
pub fn decode_image(digits: &[u8], width: usize, height: usize) -> Vec<Vec<u8>> {
let nb_pixel = width * height;
let nb_layers = digits.len() / nb_pixel;
let mut layers: Vec<Vec<u8>> = Vec::new();
- for i in 0 .. nb_layers {
- let layer: Vec<u8> = Vec::from(&digits[i * nb_pixel .. (i+1) * nb_pixel]);
+ for i in 0..nb_layers {
+ let layer: Vec<u8> = Vec::from(&digits[i * nb_pixel..(i + 1) * nb_pixel]);
layers.push(layer);
}
layers
}
fn count(layer: &[u8], value: u8) -> u32 {
- layer.iter().fold(0, |sum, pix| if *pix == value { sum + 1 } else { sum })
+ layer
+ .iter()
+ .fold(0, |sum, pix| if *pix == value { sum + 1 } else { sum })
}
pub fn layer_with_fewer_0(layers: &[Vec<u8>]) -> &Vec<u8> {
let mut result: Vec<u8> = Vec::new();
result.resize(size, 0);
- for i in 0 .. size {
+ for i in 0..size {
for layer in layers {
if layer[i] != 2 {
result[i] = layer[i];
let layer = merge_layers(&layers[..]);
assert_eq!(layer, vec![0, 1, 1, 0]);
}
-}
\ No newline at end of file
+}
pub fn read_map(raw: &str) -> Vec<(i32, i32)> {
let lines: Vec<&str> = raw.lines().map(|l| l.trim()).collect();
let mut map = Vec::<(i32, i32)>::new();
- for x in 0 .. lines[0].len() {
+ for x in 0..lines[0].len() {
for (y, line) in lines.iter().enumerate() {
if line.chars().nth(x) == Some('#') {
map.push((x as i32, y as i32));
fn angle(x1: i32, y1: i32, x2: i32, y2: i32) -> i64 {
// Axis are reverted to match the clockwise laser rotation beginning up.
- let angle_f64 = (2.0 * std::f64::consts::PI - ((x1 - x2) as f64).atan2((y1 - y2) as f64)) % (2.0 * std::f64::consts::PI);
+ let angle_f64 = (2.0 * std::f64::consts::PI - ((x1 - x2) as f64).atan2((y1 - y2) as f64))
+ % (2.0 * std::f64::consts::PI);
(angle_f64 * 1_000_000.0) as i64
}
type PositionsAndDistances = Vec<((i32, i32), i64)>;
-pub fn location_nth_vaporized_asteroid(pos: (i32, i32), map: &[(i32, i32)], n: usize) -> (i32, i32) {
+pub fn location_nth_vaporized_asteroid(
+ pos: (i32, i32),
+ map: &[(i32, i32)],
+ n: usize,
+) -> (i32, i32) {
// Angle -> [(position, distance)].
let mut asteroids = HashMap::<i64, PositionsAndDistances>::new();
let (x1, y1) = pos;
for (x2, y2) in map {
- let angle = angle(x1, y1, *x2 , *y2);
- let dist = squared_distance(x1, y1, *x2 , *y2);
+ let angle = angle(x1, y1, *x2, *y2);
+ let dist = squared_distance(x1, y1, *x2, *y2);
match asteroids.get_mut(&angle) {
- Some (lineup_asteroids) => lineup_asteroids.push(((*x2, *y2), dist)),
- None => { asteroids.insert(angle, vec![((*x2, *y2), dist)]); }
+ Some(lineup_asteroids) => lineup_asteroids.push(((*x2, *y2), dist)),
+ None => {
+ asteroids.insert(angle, vec![((*x2, *y2), dist)]);
+ }
}
}
// Sort everything by angle and by distance.
- let mut sorted_asteroids: Vec<(&i64, &mut PositionsAndDistances)> = asteroids.iter_mut().collect();
+ let mut sorted_asteroids: Vec<(&i64, &mut PositionsAndDistances)> =
+ asteroids.iter_mut().collect();
sorted_asteroids.sort_by(|(a1, _), (a2, _)| a1.cmp(a2));
for (_, lineup_asteroids) in sorted_asteroids.iter_mut() {
lineup_asteroids.sort_by(|(_, l1), (_, l2)| l1.cmp(l2))
loop {
for (_, lineup_asteroids) in sorted_asteroids.iter_mut() {
let ((x, y), _) = lineup_asteroids.remove(0);
- if i == n { return (x, y) }
+ if i == n {
+ return (x, y);
+ }
i += 1;
}
}
#[test]
fn part1_sample_1() {
- let raw_map =
- ".#..#
+ let raw_map = ".#..#
.....
#####
....#
#[test]
fn part1_sample_2() {
- let raw_map =
- "......#.#.
+ let raw_map = "......#.#.
#..#.#....
..#######.
.#.#.###..
#[test]
fn part1_sampl3() {
- let raw_map =
- "#.#...#.#.
+ let raw_map = "#.#...#.#.
.###....#.
.#....#...
##.#.#.#.#
#[test]
fn part1_sample_4() {
- let raw_map =
- ".#..#..###
+ let raw_map = ".#..#..###
####.###.#
....###.#.
..###.##.#
#[test]
fn part1_sample_5() {
- let raw_map =
- ".#..##.###...#######
+ let raw_map = ".#..##.###...#######
##.############..##.
.#.######.########.#
.###.#######.####.#.
assert_eq!(find_best_location(&map).0, 210);
}
-
#[test]
fn part2_sample_1() {
- let raw_map =
- ".#....#####...#..
+ let raw_map = ".#....#####...#..
##...##.#####..##
##...#...#.#####.
..#.....X...###..
#[test]
fn part2_sample_2() {
- let raw_map =
- ".#..##.###...#######
+ let raw_map = ".#..##.###...#######
##.############..##.
.#.######.########.#
.###.#######.####.#.
let pos_200th = location_nth_vaporized_asteroid(pos, &map, 200);
assert_eq!(pos_200th, (8, 2));
}
-}
\ No newline at end of file
+}
\r
enum NextCommand {\r
Paint,\r
- Turn\r
+ Turn,\r
}\r
\r
struct Robot {\r
next_command: NextCommand,\r
current_pos: (i32, i32),\r
current_dir: i32, // 0: up, 1: right, 2: down, 3: left.\r
- panels: HashMap<(i32, i32), i64>\r
+ panels: HashMap<(i32, i32), i64>,\r
}\r
\r
impl Robot {\r
next_command: NextCommand::Paint,\r
current_pos: (0, 0),\r
current_dir: 0,\r
- panels: HashMap::new()\r
+ panels: HashMap::new(),\r
}\r
}\r
}\r
}\r
\r
fn write(&mut self, value: i64) {\r
- self.next_command =\r
- match self.next_command {\r
- NextCommand::Paint => { self.panels.insert(self.current_pos, value); NextCommand::Turn },\r
- NextCommand::Turn => {\r
- self.current_dir = (self.current_dir + if value == 0 /* Turn left. */ { 3 } else /* Turn right. */ { 1 }) % 4;\r
- let (x, y) = self.current_pos;\r
- self.current_pos =\r
- match self.current_dir {\r
- 0 => (x , y + 1),\r
- 1 => (x + 1, y ),\r
- 2 => (x , y - 1),\r
- 3 | _ => (x - 1, y )\r
- };\r
- NextCommand::Paint\r
- }\r
+ self.next_command = match self.next_command {\r
+ NextCommand::Paint => {\r
+ self.panels.insert(self.current_pos, value);\r
+ NextCommand::Turn\r
}\r
+ NextCommand::Turn => {\r
+ self.current_dir = (self.current_dir\r
+ + if value == 0 /* Turn left. */ { 3 } else /* Turn right. */ { 1 })\r
+ % 4;\r
+ let (x, y) = self.current_pos;\r
+ self.current_pos = match self.current_dir {\r
+ 0 => (x, y + 1),\r
+ 1 => (x + 1, y),\r
+ 2 => (x, y - 1),\r
+ 3 | _ => (x - 1, y),\r
+ };\r
+ NextCommand::Paint\r
+ }\r
+ }\r
}\r
}\r
\r
let mut layer = Vec::new();\r
layer.resize(width * height, 0);\r
\r
- for x in min_x ..= max_x {\r
- for y in min_y ..= max_y {\r
+ for x in min_x..=max_x {\r
+ for y in min_y..=max_y {\r
let pos = (x - min_x) + ((height as i32 - y + min_y - 1) * width as i32); // Y axis is down.\r
layer[pos as usize] = *panels.get(&(x, y)).unwrap_or(&0) as u8;\r
}\r
\r
#[cfg(test)]\r
mod tests {\r
- use super::*;\r
use super::intcode::IO;\r
+ use super::*;\r
\r
#[test]\r
fn part1() {\r
\r
assert_eq!(robot.panels.len(), 6);\r
}\r
-}
\ No newline at end of file
+}\r
pub struct Vector3D {
x: i32,
y: i32,
- z: i32
+ z: i32,
}
impl AddAssign for Vector3D {
*self = Self {
x: self.x + other.x,
y: self.y + other.y,
- z: self.z + other.z
+ z: self.z + other.z,
};
}
}
#[derive(Debug, Copy, Clone)]
pub struct Moon {
position: Vector3D,
- velocity: Vector3D
+ velocity: Vector3D,
}
impl Moon {
fn total_energy(&self) -> i32 {
- (self.position.x.abs() + self.position.y.abs() + self.position.z.abs()) *
- (self.velocity.x.abs() + self.velocity.y.abs() + self.velocity.z.abs())
+ (self.position.x.abs() + self.position.y.abs() + self.position.z.abs())
+ * (self.velocity.x.abs() + self.velocity.y.abs() + self.velocity.z.abs())
}
}
let moons_copy = moons.clone();
for m1 in moons.iter_mut() {
for m2 in &moons_copy {
- m1.velocity.x += match m2.position.x.cmp(&m1.position.x) { Ordering::Greater => 1, Ordering::Less => -1, Ordering::Equal => 0 };
- m1.velocity.y += match m2.position.y.cmp(&m1.position.y) { Ordering::Greater => 1, Ordering::Less => -1, Ordering::Equal => 0 };
- m1.velocity.z += match m2.position.z.cmp(&m1.position.z) { Ordering::Greater => 1, Ordering::Less => -1, Ordering::Equal => 0 };
+ m1.velocity.x += match m2.position.x.cmp(&m1.position.x) {
+ Ordering::Greater => 1,
+ Ordering::Less => -1,
+ Ordering::Equal => 0,
+ };
+ m1.velocity.y += match m2.position.y.cmp(&m1.position.y) {
+ Ordering::Greater => 1,
+ Ordering::Less => -1,
+ Ordering::Equal => 0,
+ };
+ m1.velocity.z += match m2.position.z.cmp(&m1.position.z) {
+ Ordering::Greater => 1,
+ Ordering::Less => -1,
+ Ordering::Equal => 0,
+ };
}
}
}
fn create_moons(moon_positions: &[Vector3D]) -> Vec<Moon> {
- moon_positions.iter().map(|position| Moon { position: *position, velocity: Vector3D { x: 0, y: 0, z: 0 } }).collect()
+ moon_positions
+ .iter()
+ .map(|position| Moon {
+ position: *position,
+ velocity: Vector3D { x: 0, y: 0, z: 0 },
+ })
+ .collect()
}
pub fn final_energy(moon_positions: &[Vector3D], steps: u32) -> i32 {
let mut moons: Vec<Moon> = create_moons(moon_positions);
- for _ in 0 .. steps {
+ for _ in 0..steps {
next_step(&mut moons);
}
- moons.iter().fold(0, |energy, moon| energy + moon.total_energy())
+ moons
+ .iter()
+ .fold(0, |energy, moon| energy + moon.total_energy())
}
pub fn find_same_state(moon_positions: &[Vector3D]) -> i64 {
next_step(&mut moons);
i += 1;
- if nb_cycles.x == 0 && initial_state.iter().zip(&moons).all(
- |(m1, m2)| m1.position.x == m2.position.x && m1.velocity.x == m2.velocity.x
- ) { nb_cycles.x = i; }
+ if nb_cycles.x == 0
+ && initial_state
+ .iter()
+ .zip(&moons)
+ .all(|(m1, m2)| m1.position.x == m2.position.x && m1.velocity.x == m2.velocity.x)
+ {
+ nb_cycles.x = i;
+ }
- if nb_cycles.y == 0 && initial_state.iter().zip(&moons).all(
- |(m1, m2)| m1.position.y == m2.position.y && m1.velocity.y == m2.velocity.y
- ) { nb_cycles.y = i; }
+ if nb_cycles.y == 0
+ && initial_state
+ .iter()
+ .zip(&moons)
+ .all(|(m1, m2)| m1.position.y == m2.position.y && m1.velocity.y == m2.velocity.y)
+ {
+ nb_cycles.y = i;
+ }
- if nb_cycles.z == 0 && initial_state.iter().zip(&moons).all(
- |(m1, m2)| m1.position.z == m2.position.z && m1.velocity.z == m2.velocity.z
- ) { nb_cycles.z = i; }
+ if nb_cycles.z == 0
+ && initial_state
+ .iter()
+ .zip(&moons)
+ .all(|(m1, m2)| m1.position.z == m2.position.z && m1.velocity.z == m2.velocity.z)
+ {
+ nb_cycles.z = i;
+ }
if nb_cycles.x != 0 && nb_cycles.y != 0 && nb_cycles.z != 0 {
- return (nb_cycles.x as i64).lcm(&(nb_cycles.y as i64)).lcm(&(nb_cycles.z as i64))
+ return (nb_cycles.x as i64)
+ .lcm(&(nb_cycles.y as i64))
+ .lcm(&(nb_cycles.z as i64));
}
}
}
pub fn parse_positions(input: &str) -> Vec<Vector3D> {
use regex::Regex;
- fn build_pattern(var: &str) -> Regex { Regex::new(&format!(r".*{}\W*?=\W*?(-?.*?\d+).*", var)).unwrap() }
+ fn build_pattern(var: &str) -> Regex {
+ Regex::new(&format!(r".*{}\W*?=\W*?(-?.*?\d+).*", var)).unwrap()
+ }
let rex = build_pattern("x");
let rey = build_pattern("y");
let rez = build_pattern("z");
input
.lines()
- .map(|l|
- Vector3D {
- x: rex.captures(l).unwrap()[1].parse().unwrap(),
- y: rey.captures(l).unwrap()[1].parse().unwrap(),
- z: rez.captures(l).unwrap()[1].parse().unwrap()
- }
- )
+ .map(|l| Vector3D {
+ x: rex.captures(l).unwrap()[1].parse().unwrap(),
+ y: rey.captures(l).unwrap()[1].parse().unwrap(),
+ z: rez.captures(l).unwrap()[1].parse().unwrap(),
+ })
.collect()
}
#[test]
fn part1() {
- let input =
- "<x=-1, y=0, z=2>
+ let input = "<x=-1, y=0, z=2>
<x=2, y=-10, z=-7>
<x=4, y=-8, z=8>
<x=3, y=5, z=-1>";
#[test]
fn part2() {
- let input =
- "<x=-8, y=-10, z=0>
+ let input = "<x=-8, y=-10, z=0>
<x=5, y=5, z=10>
<x=2, y=-7, z=3>
<x=9, y=-8, z=-3>";
let coordinates = parse_positions(input);
assert_eq!(find_same_state(&coordinates), 4_686_774_924);
}
-}
\ No newline at end of file
+}
pub fn count_nb_block(code: &[i64]) -> i32 {
let output = intcode::execute_op_code(code, &[]);
- output.iter().chunks(3).into_iter().map(
- |tile_with_pos| {
+ output
+ .iter()
+ .chunks(3)
+ .into_iter()
+ .map(|tile_with_pos| {
let tile_with_pos: Vec<&i64> = tile_with_pos.collect();
let tile = Tile::try_from(*tile_with_pos[2] as u8).unwrap();
- if tile == Tile::Block { 1 } else { 0 }
- }
- ).sum()
+ if tile == Tile::Block {
+ 1
+ } else {
+ 0
+ }
+ })
+ .sum()
}
struct State {
} else if tile == Tile::Paddle {
self.paddle_position_x = self.buffer[0];
}
- self.joystick =
- match self.paddle_position_x.cmp(&self.ball_position_x) {
- Ordering::Greater => -1,
- Ordering::Less => 1,
- Ordering::Equal => 0
- };
+ self.joystick = match self.paddle_position_x.cmp(&self.ball_position_x) {
+ Ordering::Greater => -1,
+ Ordering::Less => 1,
+ Ordering::Equal => 0,
+ };
}
self.buffer.clear();
}
}
pub fn final_score(code: &[i64]) -> i64 {
- let mut state = State { score: 0, joystick: 0, paddle_position_x: 0, ball_position_x: 0, buffer: Vec::new() };
+ let mut state = State {
+ score: 0,
+ joystick: 0,
+ paddle_position_x: 0,
+ ball_position_x: 0,
+ buffer: Vec::new(),
+ };
intcode::execute_op_code_with_custom_io(&code, &mut state);
state.score
}
let reaction: Vec<&str> = line.split("=>").collect();
let input_chemicals: Vec<Chemical> = reaction[0].split(',').map(parse_chemical).collect();
let output_chemical = parse_chemical(reaction[1]);
- result.insert(output_chemical.name, (output_chemical.quantity, input_chemicals));
+ result.insert(
+ output_chemical.name,
+ (output_chemical.quantity, input_chemicals),
+ );
}
result
}
ore_needed(reactions, 1, &mut remainders)
}
-fn ore_needed(reactions: &Reactions, fuel_quantity: i64, remainders: &mut HashMap<String, i64>) -> i64 {
-
- fn needed(reactions: &Reactions, chemicals: &[Chemical], remainders: &mut HashMap<String, i64>) -> i64 {
+fn ore_needed(
+ reactions: &Reactions,
+ fuel_quantity: i64,
+ remainders: &mut HashMap<String, i64>,
+) -> i64 {
+ fn needed(
+ reactions: &Reactions,
+ chemicals: &[Chemical],
+ remainders: &mut HashMap<String, i64>,
+ ) -> i64 {
chemicals.iter().fold(0, |sum, chemical| {
- let quantity_needed =
- match remainders.get(&chemical.name) {
- Some(quantity) => {
- let remainder = quantity - chemical.quantity;
- if remainder < 0 {
- remainders.remove(&chemical.name);
- remainder.abs()
- } else {
- remainders.insert(chemical.name.clone(), remainder);
- 0
- }
- },
- None => chemical.quantity
- };
-
- sum +
- if chemical.name == "ORE" {
- quantity_needed
- } else {
- match reactions.get(&chemical.name) {
- Some((quantity_produced, chemicals_needed)) => {
- let n = (quantity_needed / quantity_produced) + (if quantity_needed % quantity_produced == 0 { 0 } else { 1 });
- let rem = n * quantity_produced - quantity_needed;
- match remainders.get(&chemical.name) {
- Some(&q) => { remainders.insert(chemical.name.clone(), q + rem); },
- None => { remainders.insert(chemical.name.clone(), rem); }
+ let quantity_needed = match remainders.get(&chemical.name) {
+ Some(quantity) => {
+ let remainder = quantity - chemical.quantity;
+ if remainder < 0 {
+ remainders.remove(&chemical.name);
+ remainder.abs()
+ } else {
+ remainders.insert(chemical.name.clone(), remainder);
+ 0
+ }
+ }
+ None => chemical.quantity,
+ };
+
+ sum + if chemical.name == "ORE" {
+ quantity_needed
+ } else {
+ match reactions.get(&chemical.name) {
+ Some((quantity_produced, chemicals_needed)) => {
+ let n = (quantity_needed / quantity_produced)
+ + (if quantity_needed % quantity_produced == 0 {
+ 0
+ } else {
+ 1
+ });
+ let rem = n * quantity_produced - quantity_needed;
+ match remainders.get(&chemical.name) {
+ Some(&q) => {
+ remainders.insert(chemical.name.clone(), q + rem);
+ }
+ None => {
+ remainders.insert(chemical.name.clone(), rem);
}
- needed(reactions, &chemicals_needed.iter().map(|c| Chemical { quantity: n * c.quantity, name: c.name.clone() }).collect::<Vec<Chemical>>(), remainders)
- },
- None => panic!("Unable to find reaction to create {}", chemical.name)
+ }
+ needed(
+ reactions,
+ &chemicals_needed
+ .iter()
+ .map(|c| Chemical {
+ quantity: n * c.quantity,
+ name: c.name.clone(),
+ })
+ .collect::<Vec<Chemical>>(),
+ remainders,
+ )
}
+ None => panic!("Unable to find reaction to create {}", chemical.name),
}
+ }
})
}
- needed(reactions, &[Chemical { quantity: fuel_quantity, name: String::from("FUEL") }], remainders)
+ needed(
+ reactions,
+ &[Chemical {
+ quantity: fuel_quantity,
+ name: String::from("FUEL"),
+ }],
+ remainders,
+ )
}
pub fn fuel_produced(reactions: &Reactions, ore: i64, ore_per_fuel: i64) -> i64 {
ore_available -= ore_needed(reactions, fuel, &mut remainders);
if ore_available <= 0 {
- return fuel_produced
+ return fuel_produced;
}
fuel_produced += fuel;
#[test]
fn part1_sample_1() {
- let input =
- "10 ORE => 10 A
+ let input = "10 ORE => 10 A
1 ORE => 1 B
7 A, 1 B => 1 C
7 A, 1 C => 1 D
#[test]
fn part1_sample_2() {
- let input =
- "9 ORE => 2 A
+ let input = "9 ORE => 2 A
8 ORE => 3 B
7 ORE => 5 C
3 A, 4 B => 1 AB
#[test]
fn part1_sample_3() {
- let input =
- "157 ORE => 5 NZVS
+ let input = "157 ORE => 5 NZVS
165 ORE => 6 DCFZ
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
#[test]
fn part1_sample_4() {
- let input =
- "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
+ let input = "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
17 NVRVD, 3 JNWZP => 8 VPVL
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
22 VJHF, 37 MNCFX => 5 FWMGM
#[test]
fn part1_sample_5() {
- let input =
- "171 ORE => 8 CNZTR
+ let input = "171 ORE => 8 CNZTR
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
114 ORE => 4 BHXH
14 VRPVC => 6 BMBT
#[test]
fn part2_sample_1() {
- let input =
- "157 ORE => 5 NZVS
+ let input = "157 ORE => 5 NZVS
165 ORE => 6 DCFZ
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT";
let reactions = parse(input);
let ore_per_fuel = ore_needed_per_fuel(&reactions);
- assert_eq!(fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel), 82_892_753);
+ assert_eq!(
+ fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel),
+ 82_892_753
+ );
}
#[test]
fn part2_sample_2() {
- let input =
- "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
+ let input = "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
17 NVRVD, 3 JNWZP => 8 VPVL
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
22 VJHF, 37 MNCFX => 5 FWMGM
176 ORE => 6 VJHF";
let reactions = parse(input);
let ore_per_fuel = ore_needed_per_fuel(&reactions);
- assert_eq!(fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel), 5_586_022);
+ assert_eq!(
+ fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel),
+ 5_586_022
+ );
}
#[test]
fn part2_sample_3() {
- let input =
- "171 ORE => 8 CNZTR
+ let input = "171 ORE => 8 CNZTR
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
114 ORE => 4 BHXH
14 VRPVC => 6 BMBT
5 BHXH, 4 VRPVC => 5 LTCX";
let reactions = parse(input);
let ore_per_fuel = ore_needed_per_fuel(&reactions);
- assert_eq!(fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel), 460_664);
+ assert_eq!(
+ fuel_produced(&reactions, 1_000_000_000_000, ore_per_fuel),
+ 460_664
+ );
}
-}
\ No newline at end of file
+}
-use std::{collections::{HashMap, HashSet}, iter::FromIterator};\r
+use std::{\r
+ collections::{HashMap, HashSet},\r
+ iter::FromIterator,\r
+};\r
\r
use super::intcode;\r
\r
current_path: vec![(0, 0)],\r
oxygen_location: (0, 0),\r
steps_to_oxygen: 0,\r
- all_locations_explored: false\r
+ all_locations_explored: false,\r
}\r
}\r
\r
- fn current_position(&self) -> (i32, i32) { *self.current_path.last().unwrap() }\r
+ fn current_position(&self) -> (i32, i32) {\r
+ *self.current_path.last().unwrap()\r
+ }\r
\r
fn positions_around(&self) -> Vec<(i64, (i32, i32))> {\r
let (x, y) = self.current_position();\r
- vec![(1, (x, y + 1)), (2, (x, y - 1)), (3, (x - 1, y)), (4, (x + 1, y))]\r
+ vec![\r
+ (1, (x, y + 1)),\r
+ (2, (x, y - 1)),\r
+ (3, (x - 1, y)),\r
+ (4, (x + 1, y)),\r
+ ]\r
}\r
\r
fn get_state(&self, position: (i32, i32)) -> LocationState {\r
match self.board.get(&position) {\r
Some(state) => *state,\r
- None => LocationState::Unknown\r
+ None => LocationState::Unknown,\r
}\r
}\r
\r
for (mov, pos) in self.positions_around() {\r
if self.get_state(pos) == LocationState::Unknown {\r
self.current_path.push(pos);\r
- return mov\r
+ return mov;\r
}\r
}\r
\r
if self.get_state(pos) == LocationState::Visited {\r
self.set_state(self.current_position(), LocationState::DeadEnd);\r
self.current_path.pop();\r
- return mov\r
+ return mov;\r
}\r
}\r
\r
1\r
}\r
\r
- // 0: droid hit a wall, 1: droid moved one step, 2: droid moved one step and has found the oxygen system.\r
+ // 0: droid hit a wall\r
+ // 1: droid moved one step\r
+ // 2: droid moved one step and has found the oxygen system.\r
fn reply_from_droid(&mut self, status: i64) {\r
if status == 0 {\r
self.set_state(self.current_position(), LocationState::Wall);\r
} else if status == 1 || status == 2 {\r
self.set_state(self.current_position(), LocationState::Visited);\r
\r
- // We need to explore all positions even if we find the oxygen to compute the time (see 'time_to_flood_the_area') in part 2.\r
+ // We need to explore all positions even if we find the oxygen to compute the time\r
+ // (see 'time_to_flood_the_area') in part 2.\r
if status == 2 {\r
self.steps_to_oxygen = self.current_path.len() as i32 - 1;\r
self.oxygen_location = self.current_position();\r
}\r
\r
max_length - 1\r
-}
\ No newline at end of file
+}\r
use std::iter::FromIterator;\r
\r
pub fn parse(input: &str) -> Vec<i32> {\r
- input.chars().map(|c| c.to_digit(10).unwrap() as i32).collect()\r
+ input\r
+ .chars()\r
+ .map(|c| c.to_digit(10).unwrap() as i32)\r
+ .collect()\r
}\r
\r
-pub fn fft(signal: &[i32], pattern: &[i32], nb_phases: i32, offset: usize, length: usize, nb_signal_repeated: usize) -> Vec<i32> {\r
-\r
+pub fn fft(\r
+ signal: &[i32],\r
+ pattern: &[i32],\r
+ nb_phases: i32,\r
+ offset: usize,\r
+ length: usize,\r
+ nb_signal_repeated: usize,\r
+) -> Vec<i32> {\r
let l = signal.len();\r
let pattern_l = pattern.len();\r
\r
let mut output = Vec::from_iter(signal.iter().cycle().take(l * nb_signal_repeated).copied());\r
\r
- for _ in 0 .. nb_phases {\r
+ for _ in 0..nb_phases {\r
let cloned_output = output.clone();\r
- for i in 0 .. output.len() {\r
- output[i] =\r
- cloned_output.iter().enumerate().fold(\r
- 0,\r
- |sum, (j, value)| {\r
- sum + value * pattern[(j + 1) / (i + 1) % pattern_l]\r
- }\r
- ).abs() % 10;\r
+ for i in 0..output.len() {\r
+ output[i] = cloned_output\r
+ .iter()\r
+ .enumerate()\r
+ .fold(0, |sum, (j, value)| {\r
+ sum + value * pattern[(j + 1) / (i + 1) % pattern_l]\r
+ })\r
+ .abs()\r
+ % 10;\r
}\r
}\r
\r
- Vec::from(&output[offset .. offset + length])\r
+ Vec::from(&output[offset..offset + length])\r
}\r
\r
pub fn digits_as_string(signal: &[i32]) -> String {\r
- signal.iter().fold(String::new(), |result, digit| result + &digit.to_string())\r
+ signal\r
+ .iter()\r
+ .fold(String::new(), |result, digit| result + &digit.to_string())\r
}\r
\r
// Part 2 is from 'https://github.com/mkeeter/advent-of-code/blob/master/2019/16/src/main.rs'.\r
let output = fft(&signal, &[0, 1, 0, -1], 100, 0, 8, 1);\r
assert_eq!(digits_as_string(&output), "52432133");\r
}\r
-}
\ No newline at end of file
+}\r
use super::intcode;\r
\r
#[derive(PartialEq, Eq, Copy, Clone, Debug)]\r
-enum Direction { Up, Left, Down, Right }\r
+enum Direction {\r
+ Up,\r
+ Left,\r
+ Down,\r
+ Right,\r
+}\r
\r
impl TryFrom<char> for Direction {\r
type Error = ();\r
'<' => Ok(Direction::Left),\r
'v' => Ok(Direction::Down),\r
'>' => Ok(Direction::Right),\r
- _ => Err(())\r
+ _ => Err(()),\r
}\r
}\r
}\r
\r
#[derive(PartialEq, Eq, Copy, Clone, Debug)]\r
-enum Movement { Left, Right }\r
+enum Movement {\r
+ Left,\r
+ Right,\r
+}\r
\r
#[derive(PartialEq, Eq, Copy, Clone, Debug)]\r
-struct MovementCommand { mov: Movement, steps: u32 }\r
+struct MovementCommand {\r
+ mov: Movement,\r
+ steps: u32,\r
+}\r
\r
struct RobotTrackingSystem {\r
board: Vec<Vec<char>>,\r
current_x = 0;\r
} else {\r
let c = (*c as u8) as char;\r
- if let Ok(dir) = Direction::try_from(c) {\r
+ if let Ok(dir) = Direction::try_from(c) {\r
rts.start_position = (current_x, rts.board.len() as i32);\r
rts.start_dir = dir\r
}\r
let mut steps = 0;\r
\r
'main: loop {\r
- let positions = [(Direction::Up, (x, y - 1)), (Direction::Left, (x - 1, y)), (Direction::Right, (x + 1, y)), (Direction::Down, (x, y + 1))];\r
+ let positions = [\r
+ (Direction::Up, (x, y - 1)),\r
+ (Direction::Left, (x - 1, y)),\r
+ (Direction::Right, (x + 1, y)),\r
+ (Direction::Down, (x, y + 1)),\r
+ ];\r
\r
let next_position = positions.iter().find(|(d, _)| *d == dir).unwrap().1;\r
\r
}\r
\r
if steps != 0 {\r
- self.dir_commands.push(MovementCommand { mov: last_mov, steps });\r
+ self.dir_commands.push(MovementCommand {\r
+ mov: last_mov,\r
+ steps,\r
+ });\r
steps = 0;\r
}\r
\r
for (d, p) in &positions {\r
if self.get(p.0, p.1) == Some('#') && !visited_locations.contains(p) {\r
-\r
- last_mov =\r
- match (dir, *d) {\r
- (Direction::Up, Direction::Right) | (Direction::Right, Direction::Down) | (Direction::Down, Direction::Left) | (Direction::Left, Direction::Up) => Movement::Right,\r
- (Direction::Up, Direction::Left) | (Direction::Left, Direction::Down) | (Direction::Down, Direction::Right) | (Direction::Right, Direction::Up) => Movement::Left,\r
- _ => panic!("Unable to find a movement from {:?} to {:?}", dir, *d)\r
- };\r
+ last_mov = match (dir, *d) {\r
+ (Direction::Up, Direction::Right)\r
+ | (Direction::Right, Direction::Down)\r
+ | (Direction::Down, Direction::Left)\r
+ | (Direction::Left, Direction::Up) => Movement::Right,\r
+ (Direction::Up, Direction::Left)\r
+ | (Direction::Left, Direction::Down)\r
+ | (Direction::Down, Direction::Right)\r
+ | (Direction::Right, Direction::Up) => Movement::Left,\r
+ _ => panic!("Unable to find a movement from {:?} to {:?}", dir, *d),\r
+ };\r
\r
visited_locations.insert(*p);\r
steps += 1;\r
}\r
\r
struct CommandSequences {\r
- commands: Vec<(usize, Range<usize>)> // Each range is associated with a sequence number (first tuple value).\r
+ // Each range is associated with a sequence number (first tuple value).\r
+ commands: Vec<(usize, Range<usize>)>,\r
}\r
\r
-fn is_overlapping<T : PartialOrd>(r1: &Range<T>, r2: &Range<T>) -> bool {\r
+fn is_overlapping<T: PartialOrd>(r1: &Range<T>, r2: &Range<T>) -> bool {\r
r1.start < r2.start && r1.end > r2.start || r2.start < r1.start && r2.end > r1.start\r
}\r
\r
impl CommandSequences {\r
fn new() -> Self {\r
CommandSequences {\r
- commands: Vec::new()\r
+ commands: Vec::new(),\r
}\r
}\r
\r
let len_min = 3;\r
let len_max = 6;\r
\r
- for l1 in len_min ..= len_max {\r
- for l2 in len_min ..= len_max {\r
- for l3 in len_min ..= len_max {\r
+ for l1 in len_min..=len_max {\r
+ for l2 in len_min..=len_max {\r
+ for l3 in len_min..=len_max {\r
self.commands.clear();\r
let mut position: usize = 0;\r
- for seq_num in 0 .. 3 {\r
- let l = match seq_num { 0 => l1, 1 => l2, _ => l3 };\r
- let range = position .. position + l;\r
+ for seq_num in 0..3 {\r
+ let l = match seq_num {\r
+ 0 => l1,\r
+ 1 => l2,\r
+ _ => l3,\r
+ };\r
+ let range = position..position + l;\r
self.commands.push((seq_num, range.clone()));\r
// Try to find the sequence elsewhere in 'movements'.\r
let mut position2 = position + l;\r
while position2 <= movements.len() - l {\r
- let range2 = position2 .. position2 + l;\r
- if !self.commands.iter().any(|(_, r)| is_overlapping(&r, &range2)) && movements.get(range.clone()) == movements.get(range2.clone()) {\r
+ let range2 = position2..position2 + l;\r
+ if !self\r
+ .commands\r
+ .iter()\r
+ .any(|(_, r)| is_overlapping(&r, &range2))\r
+ && movements.get(range.clone()) == movements.get(range2.clone())\r
+ {\r
self.commands.push((seq_num, range2));\r
position2 += l;\r
} else {\r
}\r
\r
// Check if all movements are included into a sequence.\r
- if self.commands.iter().fold(0, |sum, (_, range)| sum + range.len()) == movements.len() {\r
+ if self\r
+ .commands\r
+ .iter()\r
+ .fold(0, |sum, (_, range)| sum + range.len())\r
+ == movements.len()\r
+ {\r
return;\r
}\r
}\r
-\r
}\r
}\r
}\r
}\r
\r
-struct Part1 { output: Vec<i64>, }\r
+struct Part1 {\r
+ output: Vec<i64>,\r
+}\r
\r
-impl Part1 { fn new() -> Self { Part1 { output: Vec::<i64>::new() } }}\r
+impl Part1 {\r
+ fn new() -> Self {\r
+ Part1 {\r
+ output: Vec::<i64>::new(),\r
+ }\r
+ }\r
+}\r
\r
struct Part2 {\r
output: Vec<i64>,\r
dust_collected: i64,\r
}\r
\r
-impl Part2 { fn new() -> Self { Part2 { output: Vec::<i64>::new(), rts: None, commands_sequences: CommandSequences::new(), input: Vec::new(), input_position: 0, dust_collected: 0 } } }\r
+impl Part2 {\r
+ fn new() -> Self {\r
+ Part2 {\r
+ output: Vec::<i64>::new(),\r
+ rts: None,\r
+ commands_sequences: CommandSequences::new(),\r
+ input: Vec::new(),\r
+ input_position: 0,\r
+ dust_collected: 0,\r
+ }\r
+ }\r
+}\r
\r
impl intcode::IO for Part1 {\r
// Read instructions\r
- fn read(&mut self) -> i64 { 0 }\r
+ fn read(&mut self) -> i64 {\r
+ 0\r
+ }\r
\r
// Send to the output channel.\r
fn write(&mut self, value: i64) {\r
fn read(&mut self) -> i64 {\r
if self.rts.is_none() {\r
self.rts = Some(RobotTrackingSystem::from(&self.output));\r
- self.commands_sequences.find_sequences(&self.rts.as_ref().unwrap().dir_commands);\r
+ self.commands_sequences\r
+ .find_sequences(&self.rts.as_ref().unwrap().dir_commands);\r
\r
// 1: add the movements sequences: "A,B,C,A\n" // Max: 10 sequence calls.\r
- for (i, (seq_num, _)) in self.commands_sequences.commands.iter().sorted_by(|(_, r1), (_, r2)| r1.start.cmp(&r2.start)).enumerate() {\r
- if i > 0 { self.input.push(44); }\r
+ for (i, (seq_num, _)) in self\r
+ .commands_sequences\r
+ .commands\r
+ .iter()\r
+ .sorted_by(|(_, r1), (_, r2)| r1.start.cmp(&r2.start))\r
+ .enumerate()\r
+ {\r
+ if i > 0 {\r
+ self.input.push(44);\r
+ }\r
self.input.push(*seq_num as i64 + 65);\r
}\r
self.input.push(10);\r
\r
// 2: Add the sequence A, B and C: "R,8,L,2,R,1\n", Max: ~6 movements.\r
- for seq_num in 0 .. 3 {\r
- let (_, sequence) = self.commands_sequences.commands.iter().find(|(s, _)| *s == seq_num).unwrap();\r
- for (i, movement_command) in self.rts.as_ref().unwrap().dir_commands.get(sequence.clone()).unwrap().iter().enumerate() {\r
-\r
- if i > 0 { self.input.push(44); }\r
- if movement_command.mov == Movement::Left { self.input.push(76); } else { self.input.push(82); }\r
+ for seq_num in 0..3 {\r
+ let (_, sequence) = self\r
+ .commands_sequences\r
+ .commands\r
+ .iter()\r
+ .find(|(s, _)| *s == seq_num)\r
+ .unwrap();\r
+ for (i, movement_command) in self\r
+ .rts\r
+ .as_ref()\r
+ .unwrap()\r
+ .dir_commands\r
+ .get(sequence.clone())\r
+ .unwrap()\r
+ .iter()\r
+ .enumerate()\r
+ {\r
+ if i > 0 {\r
+ self.input.push(44);\r
+ }\r
+ if movement_command.mov == Movement::Left {\r
+ self.input.push(76);\r
+ } else {\r
+ self.input.push(82);\r
+ }\r
self.input.push(44);\r
for c in movement_command.steps.to_string().as_bytes() {\r
self.input.push(*c as i64);\r
let mut part1 = Part1::new();\r
intcode::execute_op_code_with_custom_io(code, &mut part1);\r
let rts = RobotTrackingSystem::from(&part1.output);\r
- rts.crossings.iter().fold(0, |sum, crossing| sum + crossing.0 * crossing.1)\r
+ rts.crossings\r
+ .iter()\r
+ .fold(0, |sum, crossing| sum + crossing.0 * crossing.1)\r
}\r
\r
pub fn collected_dust(code: &[i64]) -> i64 {\r
let mut part2 = Part2::new();\r
intcode::execute_op_code_with_custom_io(code, &mut part2);\r
part2.dust_collected\r
-}
\ No newline at end of file
+}\r
let mut entrance = (0, 0);
for (row, line) in input.lines().enumerate() {
tunnels.push(line.trim().chars().collect::<Vec<char>>());
- if let Some((col, _)) = tunnels.last().unwrap().iter().find_position(|c| c == &&START_SYMBOL) {
+ if let Some((col, _)) = tunnels
+ .last()
+ .unwrap()
+ .iter()
+ .find_position(|c| c == &&START_SYMBOL)
+ {
entrance = (row as i32, col as i32);
}
}
}
struct NodeIterator {
- current: Option<Rc<Node>>
+ current: Option<Rc<Node>>,
}
impl NodeIterator {
- fn from(node: Rc<Node>) -> NodeIterator { NodeIterator { current: Some(node) } }
+ fn from(node: Rc<Node>) -> NodeIterator {
+ NodeIterator {
+ current: Some(node),
+ }
+ }
}
impl Iterator for NodeIterator {
type Item = Rc<Node>;
fn next(&mut self) -> Option<Rc<Node>> {
let next = self.current.as_ref().map(|n| Rc::clone(n));
- self.current =
- match self.current.as_ref() {
- Some(n) => n.parent.as_ref().map(|n| Rc::clone(n)),
- None => None
- };
+ self.current = match self.current.as_ref() {
+ Some(n) => n.parent.as_ref().map(|n| Rc::clone(n)),
+ None => None,
+ };
next
}
}
impl Node {
fn new(parent: Option<Rc<Node>>, length_to_parent: u32, key: char) -> Self {
- Node { parent, length_to_parent, key }
+ Node {
+ parent,
+ length_to_parent,
+ key,
+ }
}
}
-
fn iter(node: Rc<Node>) -> NodeIterator {
NodeIterator::from(node)
}
- fn nb_of_keys(node: Rc<Node>) -> u32 { iter(node).count() as u32 - 1 }
+ fn nb_of_keys(node: Rc<Node>) -> u32 {
+ iter(node).count() as u32 - 1
+ }
- fn length(node: Rc<Node>) -> u32 { iter(node).fold(0, |sum, node| sum + node.length_to_parent) }
+ fn length(node: Rc<Node>) -> u32 {
+ iter(node).fold(0, |sum, node| sum + node.length_to_parent)
+ }
fn can_open(node: Rc<Node>, door: char) -> bool {
let key_needed = door.to_ascii_lowercase();
#[allow(dead_code)]
pub fn nb_steps_to_collect_all_key(vault: &Vault) -> u32 {
- fn find_keys(from : (i32, i32), parent: Rc<Node>, vault: &Vault) -> Vec<Rc<Node>> {
+ fn find_keys(from: (i32, i32), parent: Rc<Node>, vault: &Vault) -> Vec<Rc<Node>> {
let mut to_visit = vec![(from, 1)];
let mut visited_positions: HashSet<(i32, i32)> = HashSet::new();
let mut reachable_keys = Vec::<Rc<Node>>::new();
}
while let Some((pos, steps)) = to_visit.pop() {
-
- if cfg!(debug_assertions) { println!("Pos to visit: {:?}", pos); }
+ if cfg!(debug_assertions) {
+ println!("Pos to visit: {:?}", pos);
+ }
visited_positions.insert(pos);
for pos_d in &[(-1, 0), (0, 1), (1, 0), (0, -1)] {
let adjacent = (pos.0 + pos_d.0, pos.1 + pos_d.1);
- if cfg!(debug_assertions) { println!("Adjacent: {:?}", adjacent); }
+ if cfg!(debug_assertions) {
+ println!("Adjacent: {:?}", adjacent);
+ }
if !visited_positions.contains(&adjacent) {
match vault.tunnels[adjacent.0 as usize][adjacent.1 as usize] {
// Simple floor or a door or a owned key.
- c if c == FLOOR_SYMBOL || c == START_SYMBOL || c.is_ascii_uppercase() && can_open(Rc::clone(&parent), c) || c.is_ascii_lowercase() && has_key(Rc::clone(&parent), c) => {
- if cfg!(debug_assertions) { println!("-> To visit"); }
+ c if c == FLOOR_SYMBOL
+ || c == START_SYMBOL
+ || c.is_ascii_uppercase() && can_open(Rc::clone(&parent), c)
+ || c.is_ascii_lowercase() && has_key(Rc::clone(&parent), c) =>
+ {
+ if cfg!(debug_assertions) {
+ println!("-> To visit");
+ }
to_visit.push((adjacent, steps + 1));
- },
- c if c.is_ascii_lowercase() => { // A non-owned key.
- if cfg!(debug_assertions) { println!("-> A new key! {:?}", c); }
+ }
+ c if c.is_ascii_lowercase() => {
+ // A non-owned key.
+ if cfg!(debug_assertions) {
+ println!("-> A new key! {:?}", c);
+ }
visited_positions.insert(adjacent);
let node = Rc::new(Node::new(Some(Rc::clone(&parent)), steps, c));
reachable_keys.append(&mut find_keys(adjacent, node, vault));
- },
- _ => if cfg!(debug_assertions) { println!("-> WALL") },
+ }
+ _ => {
+ if cfg!(debug_assertions) {
+ println!("-> WALL")
+ }
+ }
}
}
}
let root = Rc::new(Node::new(None, 0, START_SYMBOL));
let nodes = find_keys(vault.entrance, root, vault);
- nodes.iter().map(|n| (length(Rc::clone(n)), nb_of_keys(Rc::clone(n)))).sorted_by(|(l1, n1), (l2, n2)| n1.cmp(&n2).then(l1.cmp(&l2))).next().unwrap().0
+ nodes
+ .iter()
+ .map(|n| (length(Rc::clone(n)), nb_of_keys(Rc::clone(n))))
+ .sorted_by(|(l1, n1), (l2, n2)| n1.cmp(&n2).then(l1.cmp(&l2)))
+ .next()
+ .unwrap()
+ .0
}
}
struct Path {
to_visit: Vec<(i32, i32)>,
visited: HashSet<(i32, i32)>,
- keys: Vec<char>
+ keys: Vec<char>,
}
impl Path {
pub fn new(initial_position: (i32, i32)) -> Self {
- Path { to_visit: vec![initial_position], visited: HashSet::new(), keys: Vec::new() }
+ Path {
+ to_visit: vec![initial_position],
+ visited: HashSet::new(),
+ keys: Vec::new(),
+ }
}
}
pub fn nb_steps_to_collect_all_key(vault: &Vault) -> u32 {
- let nb_of_keys: usize = vault.tunnels.iter().map(|line| line.iter().fold(0, |acc, c| if c.is_ascii_lowercase() { acc + 1 } else { acc })).sum();
-
- if cfg!(debug_assertions) { println!("nb_of_keys = {}", nb_of_keys); }
+ let nb_of_keys: usize = vault
+ .tunnels
+ .iter()
+ .map(|line| {
+ line.iter().fold(
+ 0,
+ |acc, c| if c.is_ascii_lowercase() { acc + 1 } else { acc },
+ )
+ })
+ .sum();
+
+ if cfg!(debug_assertions) {
+ println!("nb_of_keys = {}", nb_of_keys);
+ }
let mut paths = vec![Path::new(vault.entrance)];
step += 1;
let mut new_paths: Vec<Path> = Vec::new();
- if cfg!(debug_assertions) { println!("----------------------------\n{:?}", paths); }
+ if cfg!(debug_assertions) {
+ println!("----------------------------\n{:?}", paths);
+ }
- for i in (0 .. paths.len()).rev() {
+ for i in (0..paths.len()).rev() {
let path = &mut paths[i];
let to_visit = path.to_visit.clone();
let c = vault.tunnels[adjacent.0 as usize][adjacent.1 as usize];
if c == WALL_SYMBOL {
- }
- else if c.is_ascii_lowercase() && !path.keys.contains(&c) {
+ } else if c.is_ascii_lowercase() && !path.keys.contains(&c) {
if path.keys.len() + 1 == nb_of_keys {
return step;
}
- let mut new_path = Path { to_visit: vec![adjacent], visited: HashSet::new(), keys: path.keys.clone() };
+ let mut new_path = Path {
+ to_visit: vec![adjacent],
+ visited: HashSet::new(),
+ keys: path.keys.clone(),
+ };
new_path.keys.push(c);
new_paths.push(new_path);
}
// Simple floor or a door or a owned key.
- else if c == FLOOR_SYMBOL || c == START_SYMBOL || c.is_ascii_lowercase() || c.is_ascii_uppercase() && path.keys.contains(&c.to_ascii_lowercase()) {
+ else if c == FLOOR_SYMBOL
+ || c == START_SYMBOL
+ || c.is_ascii_lowercase()
+ || c.is_ascii_uppercase()
+ && path.keys.contains(&c.to_ascii_lowercase())
+ {
path.to_visit.push(adjacent);
}
}
#[test]
fn part1_sample1() {
- let input =
- "#########
- #b.A.@.a#
- #########";
+ let input = "#########
+#b.A.@.a#
+#########";
let vault = Vault::parse(input);
dbg!(&vault);
- if cfg!(debug_assertions) { println!("===== Version 1 =====") }
+ if cfg!(debug_assertions) {
+ println!("===== Version 1 =====")
+ }
let steps_v1 = v1::nb_steps_to_collect_all_key(&vault);
- if cfg!(debug_assertions) { println!("===== Version 2 =====") }
+ if cfg!(debug_assertions) {
+ println!("===== Version 2 =====")
+ }
let steps_v2 = v2::nb_steps_to_collect_all_key(&vault);
assert_eq!(steps_v1, steps_v2);
#[test]
fn part1_sample2() {
- let input =
- "########################
- #f.D.E.e.C.b.A.@.a.B.c.#
- ######################.#
- #d.....................#
- ########################";
+ let input = "########################
+#f.D.E.e.C.b.A.@.a.B.c.#
+######################.#
+#d.....................#
+########################";
let vault = Vault::parse(input);
#[test]
fn part1_sample3() {
- let input =
- "########################
- #...............b.C.D.f#
- #.######################
- #.....@.a.B.c.d.A.e.F.g#
- ########################";
+ let input = "########################
+#...............b.C.D.f#
+#.######################
+#.....@.a.B.c.d.A.e.F.g#
+########################";
let vault = Vault::parse(input);
#[test]
fn part1_sample4() {
- let input =
- "#################
- #i.G..c...e..H.p#
- ########.########
- #j.A..b...f..D.o#
- ########@########
- #k.E..a...g..B.n#
- ########.########
- #l.F..d...h..C.m#
- #################";
+ let input = "#################
+#i.G..c...e..H.p#
+########.########
+#j.A..b...f..D.o#
+########@########
+#k.E..a...g..B.n#
+########.########
+#l.F..d...h..C.m#
+#################";
let vault = Vault::parse(input);
#[test]
fn part1_sample4b() {
- let input =
- "#################
- #j.A..b...a..D.o#
- ########@########
- #k.E..e...d..B.n#
- #################";
+ let input = "#################
+#j.A..b...a..D.o#
+########@########
+#k.E..e...d..B.n#
+#################";
let vault = Vault::parse(input);
#[test]
fn part1_sample5() {
- let input =
- "########################
- #@..............ac.GI.b#
- ###d#e#f################
- ###A#B#C################
- ###g#h#i################
- ########################";
+ let input = "########################
+#@..............ac.GI.b#
+###d#e#f################
+###A#B#C################
+###g#h#i################
+########################";
let vault = Vault::parse(input);
println!("Steps: {}", steps_v1);
}
-}
\ No newline at end of file
+}
enum Mode {\r
Position,\r
Immediate,\r
- Relative\r
+ Relative,\r
}\r
\r
pub trait IO {\r
fn read(&mut self) -> i64;\r
fn write(&mut self, value: i64);\r
- fn halt(&self) -> bool { false }\r
- fn finished(&mut self) { }\r
+ fn halt(&self) -> bool {\r
+ false\r
+ }\r
+ fn finished(&mut self) {}\r
}\r
\r
struct Buffer {\r
output: Vec<i64>,\r
- input: Vec<i64>\r
+ input: Vec<i64>,\r
}\r
\r
impl Buffer {\r
fn from(input: &[i64]) -> Self {\r
Buffer {\r
output: Vec::new(),\r
- input: Vec::from(input)\r
+ input: Vec::from(input),\r
}\r
}\r
}\r
\r
// 'true' -> immediate mode, 'false' -> position mode.\r
fn read_op_and_modes(mut code: i64) -> (i64, [Mode; 3]) {\r
- let mut modes: [Mode; 3] = [ Mode::Position, Mode::Position, Mode::Position ];\r
+ let mut modes: [Mode; 3] = [Mode::Position, Mode::Position, Mode::Position];\r
\r
for i in (2..=4).rev() {\r
let power = 10i64.pow(i);\r
let mut relative_base = 0;\r
\r
fn read(position: usize, code: &[i64], mode: Mode, relative_base: i64) -> i64 {\r
- if position >= code.len() { return 0 }\r
+ if position >= code.len() {\r
+ return 0;\r
+ }\r
\r
match mode {\r
- Mode::Position => if code[position] as usize >= code.len() { 0 } else { code[code[position] as usize] },\r
+ Mode::Position => {\r
+ if code[position] as usize >= code.len() {\r
+ 0\r
+ } else {\r
+ code[code[position] as usize]\r
+ }\r
+ }\r
Mode::Immediate => code[position],\r
- Mode::Relative => if (code[position] + relative_base) as usize >= code.len() { 0 } else { code[(code[position] + relative_base) as usize] }\r
+ Mode::Relative => {\r
+ if (code[position] + relative_base) as usize >= code.len() {\r
+ 0\r
+ } else {\r
+ code[(code[position] + relative_base) as usize]\r
+ }\r
+ }\r
}\r
}\r
\r
fn write(position: usize, value: i64, code: &mut Vec<i64>, mode: Mode, relative_base: i64) {\r
- let ref_position =\r
- match mode {\r
- Mode::Position => code[position] as usize,\r
- Mode::Immediate => panic!("Can't write un immediate mode"),\r
- Mode::Relative => (code[position] + relative_base) as usize\r
- };\r
+ let ref_position = match mode {\r
+ Mode::Position => code[position] as usize,\r
+ Mode::Immediate => panic!("Can't write un immediate mode"),\r
+ Mode::Relative => (code[position] + relative_base) as usize,\r
+ };\r
\r
if ref_position >= code.len() {\r
code.resize(ref_position + 1, 0);\r
code[ref_position] = value;\r
}\r
\r
- fn jump_if(cond: bool, cursor: usize, code: &[i64], modes: [Mode; 3], relative_base: i64) -> usize {\r
+ fn jump_if(\r
+ cond: bool,\r
+ cursor: usize,\r
+ code: &[i64],\r
+ modes: [Mode; 3],\r
+ relative_base: i64,\r
+ ) -> usize {\r
let value = read(cursor + 1, &code, modes[0], relative_base);\r
if cond == (value != 0) {\r
read(cursor + 2, &code, modes[1], relative_base) as usize\r
}\r
\r
loop {\r
- if io.halt() { break; }\r
+ if io.halt() {\r
+ break;\r
+ }\r
\r
let (op, modes) = read_op_and_modes(code[cursor]);\r
\r
match op {\r
// Sum.\r
1 => {\r
- write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) + read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
+ write(\r
+ cursor + 3,\r
+ read(cursor + 1, &code, modes[0], relative_base)\r
+ + read(cursor + 2, &code, modes[1], relative_base),\r
+ &mut code,\r
+ modes[2],\r
+ relative_base,\r
+ );\r
cursor += 4;\r
- },\r
+ }\r
\r
// Multiply.\r
2 => {\r
- write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) * read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
+ write(\r
+ cursor + 3,\r
+ read(cursor + 1, &code, modes[0], relative_base)\r
+ * read(cursor + 2, &code, modes[1], relative_base),\r
+ &mut code,\r
+ modes[2],\r
+ relative_base,\r
+ );\r
cursor += 4;\r
- },\r
+ }\r
\r
// Input.\r
3 => {\r
\r
// Less than.\r
7 => {\r
- write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) < read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
+ write(\r
+ cursor + 3,\r
+ if read(cursor + 1, &code, modes[0], relative_base)\r
+ < read(cursor + 2, &code, modes[1], relative_base)\r
+ {\r
+ 1\r
+ } else {\r
+ 0\r
+ },\r
+ &mut code,\r
+ modes[2],\r
+ relative_base,\r
+ );\r
cursor += 4;\r
- },\r
+ }\r
\r
// Equals.\r
8 => {\r
- write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) == read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
+ write(\r
+ cursor + 3,\r
+ if read(cursor + 1, &code, modes[0], relative_base)\r
+ == read(cursor + 2, &code, modes[1], relative_base)\r
+ {\r
+ 1\r
+ } else {\r
+ 0\r
+ },\r
+ &mut code,\r
+ modes[2],\r
+ relative_base,\r
+ );\r
cursor += 4;\r
- },\r
+ }\r
\r
// Change relative base.\r
9 => {\r
\r
99 => break,\r
\r
- _ => panic!("Unknown code: {}", code[cursor])\r
+ _ => panic!("Unknown code: {}", code[cursor]),\r
}\r
}\r
\r
\r
#[test]\r
fn part2() {\r
- let c = [3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99];\r
+ let c = [\r
+ 3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0,\r
+ 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4,\r
+ 20, 1105, 1, 46, 98, 99,\r
+ ];\r
\r
let r1 = execute_op_code(&c, &[7]);\r
assert_eq!(r1[0], 999);\r
\r
#[test]\r
fn copy_of_itself() {\r
- let c = [109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99];\r
+ let c = [\r
+ 109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,\r
+ ];\r
let r = execute_op_code(&c, &Vec::new());\r
assert_eq!(r, c);\r
}\r
\r
#[test]\r
fn output_big_number() {\r
- let c = [1102,34_915_192,34_915_192,7,4,7,99,0];\r
+ let c = [1102, 34_915_192, 34_915_192, 7, 4, 7, 99, 0];\r
let r = execute_op_code(&c, &Vec::new());\r
assert_eq!(r[0], 1_219_070_632_396_864);\r
}\r
\r
#[test]\r
fn input_big_number() {\r
- let c = [104,1_125_899_906_842_624,99];\r
+ let c = [104, 1_125_899_906_842_624, 99];\r
let r = execute_op_code(&c, &Vec::new());\r
assert_eq!(r[0], 1_125_899_906_842_624);\r
}\r
-}
\ No newline at end of file
+}\r
use std::time::Instant;
mod common;
-mod intcode;
mod day01;
mod day02;
mod day03;
mod day16;
mod day17;
mod day18;
+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))
+ 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))
+ format!(
+ "part1: {}, part2: {}",
+ day02::execute_op_code_with_state_fixed(&mut Vec::from(&code[..])),
+ day02::find_noun_and_verb(&code)
+ )
}
fn day03() -> String {
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]))
+ 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))
+ 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]))
+ 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"))
+ 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))
+ format!(
+ "part1: {}, part2: {}",
+ day07::find_largest_last_thruster_signal(&code),
+ day07::find_largest_last_thruster_signal_with_feedback_loop(&code)
+ )
}
fn day08() -> String {
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))
+ 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]))
+ format!(
+ "part1: {:?}, part2: {:?}",
+ intcode::execute_op_code(&code, &[1]),
+ intcode::execute_op_code(&code, &[2])
+ )
}
fn day10() -> String {
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))
+ 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))
+ 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))
+ 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))
+ 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))
+ format!(
+ "part1: {}, part2: {}",
+ n,
+ day15::time_to_flood_the_area(&dts)
+ )
}
fn day16() -> String {
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)*/ "<skipped: take too long ~ 1 min>")
+ format!(
+ "part1: {}, part2: {}",
+ day16::digits_as_string(&output_part_1),
+ /*day16::digits_as_string(&output_part_2)*/ "<skipped: take too long ~ 1 min>"
+ )
}
fn day17() -> String {
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()));
+ 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<fn() -> String> = vec!(
- day01,
- day02,
- day03,
- day04,
- day05,
- day06,
- day07,
- day08,
- day09,
- day10,
- day11,
- day12,
- day13,
- day14,
- day15,
- day16,
- day17,
- day18,
- );
+ let days: Vec<fn() -> String> = vec![
+ day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
+ day14, day15, day16, day17, day18,
+ ];
let args: Vec<String> = 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() {
+ for i in 1..=days.len() {
do_day(&days, i)
}
- println!("Time to execute all days: {}", format_micros(now.elapsed().as_micros()));
+ println!(
+ "Time to execute all days: {}",
+ format_micros(now.elapsed().as_micros())
+ );
} else {
for arg in args {
match arg.parse::<usize>() {
- 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)
+ 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),
}
}
}