diff --git a/.gitea/workflows/build_and_run.yml b/.gitea/workflows/build_and_run.yml index 96dd0ff..24c815b 100644 --- a/.gitea/workflows/build_and_run.yml +++ b/.gitea/workflows/build_and_run.yml @@ -11,7 +11,7 @@ jobs: name: Challenge for day strategy: matrix: - day_number: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + day_number: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] runs-on: rust-bookworm steps: - name: Check out repository code diff --git a/day14/Cargo.toml b/day14/Cargo.toml new file mode 100644 index 0000000..69b9772 --- /dev/null +++ b/day14/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day14" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day14/src/main.rs b/day14/src/main.rs new file mode 100644 index 0000000..aff542e --- /dev/null +++ b/day14/src/main.rs @@ -0,0 +1,113 @@ +use std::{env, fs}; + +#[derive(Debug, Clone)] +struct Robot { + position: (i32, i32), + direction: (i32, i32), +} + +impl Robot { + fn advance(&mut self, steps: i32, board_height: i32, board_width: i32) { + self.position.0 = + (self.position.0 + steps * (board_height + self.direction.0)) % board_height; + self.position.1 = + (self.position.1 + steps * (board_width + self.direction.1)) % board_width; + } +} + +fn read_input(path: &str) -> String { + fs::read_to_string(path).expect("Cannot read file.") +} + +fn parse_input(input: &str) -> Vec { + let mut robots = Vec::new(); + for line in input.lines().filter(|line| !line.is_empty()) { + let halves = line.split_once(' ').unwrap(); + let p = halves.0[2..].split_once(',').unwrap(); + let v = halves.1[2..].split_once(',').unwrap(); + robots.push(Robot { + position: (p.1.parse().unwrap(), p.0.parse().unwrap()), + direction: (v.1.parse().unwrap(), v.0.parse().unwrap()), + }); + } + + robots +} + +fn is_trunk(map: &Vec>, position: (usize, usize)) -> bool { + for i in 0..=6 { + for j in 0..=3 { + if map[position.0 + i][position.0 + j] == 0 { + return false; + } + } + } + true +} + +fn display_map(map: &Vec>) { + println!("┌{:─<1$}┐", "", map[0].len()); + for line in map { + print!("│"); + for r in line { + print!("{}", if *r == 0 { " " } else { "█" }); + } + println!("│"); + } + println!("└{:─<1$}┘", "", map[0].len()); +} + +fn part_1(robots: &Vec) -> i32 { + let mut robots = robots.clone(); + let (height, width) = (103, 101); + let mut quadrants = vec![0; 4]; + for robot in robots.iter_mut() { + robot.advance(100, height, width); + if robot.position.0 != height / 2 && robot.position.1 != width / 2 { + quadrants[(robot.position.0 / (height / 2 + 1) * 2 + robot.position.1 / (width / 2 + 1)) + as usize] += 1; + } + } + + quadrants.iter().fold(1, |acc, i| acc * i) +} + +fn part_2(robots: &Vec) -> (i32, Vec>) { + let mut robots = robots.clone(); + let (height, width) = (103, 101); + let mut map: Vec> = vec![vec![0; width]; height]; + robots + .iter() + .for_each(|robot| map[robot.position.0 as usize][robot.position.1 as usize] = 1); + let mut step = 1; + loop { + for robot in robots.iter_mut() { + map[robot.position.0 as usize][robot.position.1 as usize] -= 1; + robot.advance(1, height as i32, width as i32); + map[robot.position.0 as usize][robot.position.1 as usize] += 1; + } + + for i in 0..97 { + for j in 0..98 { + if is_trunk(&map, (i, j)) { + return (step, map); + } + } + } + step += 1; + } +} + +fn main() { + let args: Vec = env::args().collect(); + for arg in args.iter().skip(1) { + let input = read_input(&arg); + let robots = parse_input(&input); + let (part_2, map) = part_2(&robots); + println!("[{}]", &arg); + println!("\t[Part 1] => Answer is '{}'.", part_1(&robots)); + println!("\t[Part 2] => Answer is '{}'.", part_2); + println!("\t[BONUS] =>"); + display_map(&map); + } +}