diff --git a/.gitignore b/.gitignore index 8ffd9f4..c06f89f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,11 @@ # will have compiled files and executables debug/ target/ - +.history/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk - +/input \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b3ef8a1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "aoc_2021" +version = "0.1.0" +authors = ["Daniel Seiller "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aoc-runner = "0.3.0" +aoc-runner-derive = "0.3.0" +itertools = "0.10.1" diff --git a/src/day01.rs b/src/day01.rs new file mode 100644 index 0000000..aafce0b --- /dev/null +++ b/src/day01.rs @@ -0,0 +1,25 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +#[aoc_generator(day1)] +pub fn input_generator(input: &str) -> Vec { + input + .lines() + .map(|l| l.trim().parse()) + .collect::, _>>() + .unwrap() +} + +#[aoc(day1, part1)] +pub fn solve_part1(input: &[usize]) -> usize { + return input.windows(2).filter(|v| v[1] > v[0]).count(); +} +#[aoc(day1, part2)] +pub fn solve_part2(input: &[usize]) -> usize { + input + .windows(3) + .map(|w| w.iter().sum()) + .collect::>() + .as_slice() + .windows(2) + .filter(|v| v[1] > v[0]) + .count() +} diff --git a/src/day02.rs b/src/day02.rs new file mode 100644 index 0000000..7908085 --- /dev/null +++ b/src/day02.rs @@ -0,0 +1,115 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use std::{error::Error, str::FromStr}; + +#[derive(Debug, Copy, Clone)] +enum Direction { + Forward, + Down, + Up, +} +#[derive(Debug, Copy, Clone)] +pub struct Instruction { + direction: Direction, + amount: usize, +} + +#[derive(Debug, Copy, Clone, Default)] +pub struct Submarine{ + depth: i64, + pos: i64, + aim: i64 +} + +impl Submarine { + fn new() -> Self { + Default::default() + } + fn run_p1(&mut self, inst: &Instruction) { + let d = inst.direction; + let a = inst.amount as i64; + match d { + Direction::Forward => { + self.pos += a; + } + Direction::Down => { + self.depth += a; + } + Direction::Up => { + self.depth -= a; + } + }; + } + fn run_p2(&mut self, inst: &Instruction) { + let d = inst.direction; + let a = inst.amount as i64; + match d { + Direction::Forward => { + self.pos += a; + self.depth += self.aim*a; + } + Direction::Down => { + self.aim += a; + } + Direction::Up => { + self.aim -= a; + } + }; + } +} + +impl FromStr for Instruction { + type Err = Box; + + fn from_str(s: &str) -> Result { + let mut s = s.split_ascii_whitespace(); + let inst = s.next().unwrap(); + let amount: usize = s.next().unwrap().parse().unwrap(); + let ret = match inst { + "forward" => Self { + direction: Direction::Forward, + amount, + }, + "up" => Self { + direction: Direction::Up, + amount, + }, + "down" => Self { + direction: Direction::Down, + amount, + }, + other => { + panic!("Invalid instruction: {}", other) + } + }; + Ok(ret) + } +} + +pub type Data = Vec; + +#[aoc_generator(day02)] +pub fn input_generator(input: &str) -> Data { + input + .lines() + .map(Instruction::from_str) + .collect::, _>>() + .unwrap() +} + +#[aoc(day02, part1)] +pub fn solve_part1(input: &Data) -> usize { + let mut sm = Submarine::new(); + for inst in input { + sm.run_p1(inst); + } + (sm.pos * sm.depth) as usize +} + +#[aoc(day02, part2)] +pub fn solve_part2(input: &Data) -> usize { + let mut sm = Submarine::new(); + for inst in input { + sm.run_p2(inst); + } + (sm.pos * sm.depth) as usize +} diff --git a/src/day03.rs b/src/day03.rs new file mode 100644 index 0000000..30964b9 --- /dev/null +++ b/src/day03.rs @@ -0,0 +1,91 @@ +use aoc_runner_derive::{aoc, aoc_generator}; + +type Data = Vec; + +fn make_histogram(input: &[u16]) -> Vec<(usize, i64)> { + let counts: &mut [Option] = &mut [None; 64]; + input.iter().for_each(|val| { + for (n, count) in counts.iter_mut().enumerate().take(12) { + let v = count.get_or_insert(0); + if ((val >> n) & 1) == 1 { + *v += 1; + } else { + *v -= 1; + } + } + }); + counts.reverse(); + counts + .iter() + .enumerate() + .filter_map(|(a, b)| b.map(|b| (a, b))) + .collect::>() +} + +#[aoc_generator(day03)] +pub fn input_generator(input: &str) -> Vec { + input + .lines() + .map(|l| u16::from_str_radix(l, 2).unwrap()) + .collect() +} + + +#[derive(Debug)] +enum Mode { + MostCommon, + LeastCommon, +} + +fn tree_filter(data: &[u16], pos: usize, mode: Mode) -> u16 { + let (zero, one) = data + .iter() + .partition::, _>(|&v| ((v >> pos) & 1) == 0); + if data.is_empty() { + panic!("Uh Oh!"); + } + if data.len() == 1 { + return data[0]; + } + if zero.len() == one.len() { + match mode { + Mode::MostCommon => tree_filter(&one, pos - 1, mode), + Mode::LeastCommon => tree_filter(&zero, pos - 1, mode), + } + } else { + let mut srt = vec![zero, one]; + srt.sort_by_key(|v| v.len()); + match mode { + Mode::MostCommon => tree_filter(&srt[1], pos - 1, mode), + Mode::LeastCommon => tree_filter(&srt[0], pos - 1, mode), + } + } +} + + +const ASCII_ZERO: u8 = 0x30; + +#[aoc(day03, part1)] // 1997414 +pub fn solve_part1(input: &Data) -> usize { + let counts = make_histogram(input); + let (gamma, epsilon): (String, String) = counts + .iter() + .map(|(_, v)| { + ( + (ASCII_ZERO + (*v >= 0) as u8) as char, + (ASCII_ZERO + (*v < 0) as u8) as char, + ) + }) + .unzip(); + let gamma = usize::from_str_radix(&gamma, 2).unwrap(); + let epsilon = usize::from_str_radix(&epsilon, 2).unwrap(); + gamma * epsilon +} + +#[aoc(day03, part2)] +pub fn solve_part2(input: &[u16]) -> usize { + // let input: Vec = input.iter().for_each(|v| v[0]).collect(); + let a = tree_filter(input, 11, Mode::MostCommon) as usize; + let b = tree_filter(input, 11, Mode::LeastCommon) as usize; + a * b +} diff --git a/src/day04.rs b/src/day04.rs new file mode 100644 index 0000000..5649526 --- /dev/null +++ b/src/day04.rs @@ -0,0 +1,92 @@ +use aoc_runner_derive::{aoc, aoc_generator}; + +#[derive(Debug,Clone)] +pub struct Data { + pub numbers: Vec, + pub boards: Vec<[[(u8,bool); 5]; 5]>, +} + +#[aoc_generator(day04)] +pub fn input_generator(input: &str) -> Data { + let mut lines = input.lines(); + let mut boards = vec![]; + let numbers = lines + .next() + .unwrap() + .split(',') + .map(|s| s.parse()) + .collect::, _>>() + .unwrap(); + let mut row = 0; + let mut board = [[(0u8,false); 5]; 5]; + for line in lines { + if line.is_empty() { + continue; + } + let line = line + .split_ascii_whitespace() + .map(|s| s.parse()) + .collect::, _>>() + .unwrap(); + line.iter().enumerate().for_each(|(i, v)| { + board[row][i] = (*v,false); + }); + row = (row + 1) % 5; + if row == 0 { + boards.push(board); + board = [[(0u8,false); 5]; 5]; + } + } + Data { numbers, boards } +} + +#[aoc(day04, part1)] +pub fn solve_part1(input: &Data) -> usize { + let Data {numbers,mut boards} =input.clone(); + for number in numbers.iter() { + for board in &mut boards { + for row in board.iter_mut() { + for (n,b) in row { + if n==number { + *b=true; + } + } + } + let win=(0..5).map(|v| { + [board[v][0],board[v][1],board[v][2],board[v][3],board[v][4]].iter().all(|v| v.1)| + [board[0][v],board[1][v],board[2][v],board[3][v],board[4][v]].iter().all(|v| v.1) + }).any(|v| v); + if win { + return board.iter().flatten().filter_map(|(v,b)| (!*b).then(|| *v as usize)).sum::()*(*number as usize) + } + } + } + unreachable!() +} + +#[aoc(day04, part2)] +pub fn solve_part2(input: &Data) -> usize { + let mut ret=None; + let Data {numbers,mut boards} =input.clone(); + let mut board_wins: Vec = vec![false;boards.len()]; + for number in numbers.iter() { + for (board_n,board) in boards.iter_mut().enumerate() { + for row in board.iter_mut() { + for (n,b) in row { + if n==number { + *b=true; + } + } + } + let win=(0..5).map(|v| { + [board[v][0],board[v][1],board[v][2],board[v][3],board[v][4]].iter().all(|v| v.1)| + [board[0][v],board[1][v],board[2][v],board[3][v],board[4][v]].iter().all(|v| v.1) + }).any(|v| v); + if win && !board_wins[board_n] { + ret=Some(board.iter().flatten().filter(|(_,b)| !*b).map(|(v,_)| *v as usize).sum::()*(*number as usize)); + board_wins[board_n]=true; + } + } + } + return ret.unwrap(); +} diff --git a/src/day05.rs b/src/day05.rs new file mode 100644 index 0000000..558a052 --- /dev/null +++ b/src/day05.rs @@ -0,0 +1,106 @@ +use aoc_runner_derive::{aoc, aoc_generator}; + +#[derive(Debug)] +pub struct Line { + x: (i64, i64), + y: (i64, i64), +} + +impl Line { + fn iter(&self) -> LineIterator { + let ret= LineIterator { + line: self, + px: self.x.0, + py: self.y.0, + sx: match self.x.0.cmp(&self.x.1) { + std::cmp::Ordering::Less => 1, + std::cmp::Ordering::Equal => 0, + std::cmp::Ordering::Greater => -1, + }, + sy: match self.y.0.cmp(&self.y.1) { + std::cmp::Ordering::Less => 1, + std::cmp::Ordering::Equal => 0, + std::cmp::Ordering::Greater => -1, + }, + }; + assert!(ret.sx!=0||ret.sy!=0); + ret + } +} +#[derive(Debug)] +struct LineIterator<'a> { + line: &'a Line, + px: i64, + py: i64, + sx: i64, + sy: i64, +} + +impl<'a> Iterator for LineIterator<'a> { + type Item = (i64, i64); + + fn next(&mut self) -> Option { + let ret = (self.px,self.py); + if self.sx>0 && self.px>self.line.x.1 { + return None; + } + if self.sx<0 && self.px0 && self.py>self.line.y.1 { + return None; + } + if self.sy<0 && self.py; + +#[aoc_generator(day05)] +pub fn input_generator(input: &str) -> Data { + input + .lines() + .map(|line| { + let parts= line.split(" -> ").collect::>(); + let start = parts[0] + .split(',') + .map(|v| v.parse().unwrap()) + .collect::>(); + let end = parts[1] + .split(',') + .map(|v| v.parse().unwrap()) + .collect::>(); + Line { + x: (start[0], end[0]), + y: (start[1], end[1]), + } + }) + .collect() +} + +#[aoc(day05, part1)] +pub fn solve_part1(input: &Data) -> usize { + let mut grid = vec![vec![0u8; 1000]; 1000]; + for (x,y) in input.iter().filter(|l| l.x.0==l.x.1||l.y.0==l.y.1).flat_map(|v| v.iter()) { + let x: usize=x.try_into().unwrap(); + let y: usize=y.try_into().unwrap(); + grid[x][y] += 1; + } + return grid.iter().flatten().filter(|&v| *v > 1).count(); +} + +#[aoc(day05, part2)] +pub fn solve_part2(input: &Data) -> usize { + let mut grid = vec![vec![0u8; 1000]; 1000]; + for (x,y) in input.iter().flat_map(|v| v.iter()) { + let x: usize=x.try_into().unwrap(); + let y: usize=y.try_into().unwrap(); + grid[x][y] += 1; + } + return grid.iter().flatten().filter(|&v| *v > 1).count(); +} \ No newline at end of file diff --git a/src/day06.rs b/src/day06.rs new file mode 100644 index 0000000..130716d --- /dev/null +++ b/src/day06.rs @@ -0,0 +1,32 @@ +use aoc_runner_derive::{aoc, aoc_generator}; + +type Data = Vec; + +#[aoc_generator(day06)] +pub fn input_generator(input: &str) -> Data { + input.trim().split(',').map(|v| v.parse().unwrap()).collect() +} + + +fn simulate(input: &Data,n: usize) -> usize { + let mut state: [usize;9] = [0;9]; + for v in input { + state[*v as usize]+=1; + } + for _ in 0..n { + state[7]+=state[0]; + state.rotate_left(1); + } + state.iter().sum() + +} + +#[aoc(day06, part1)] +pub fn solve_part1(input: &Data) -> usize { + simulate(input,80) +} + +#[aoc(day06, part2)] +pub fn solve_part2(input: &Data) -> usize { + simulate(input,256) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..233721f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(clippy::clippy::needless_return)] +use aoc_runner_derive::aoc_lib; +pub mod day01; +pub mod day02; +pub mod day03; +pub mod day04; +pub mod day05; +pub mod day06; +aoc_lib! { year = 2021 } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..428818a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,2 @@ +use aoc_runner_derive::aoc_main; +aoc_main! { lib = aoc_2021 } diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..507ca0c --- /dev/null +++ b/src/template.rs @@ -0,0 +1,18 @@ +use aoc_runner_derive::{aoc, aoc_generator}; + +type Data = (); + +#[aoc_generator(dayXX)] +pub fn input_generator(input: &str) -> Data { + todo!(); +} + +#[aoc(dayXX, part1)] +pub fn solve_part1(input: &Data) -> usize { + todo!(); +} + +#[aoc(dayXX, part2)] +pub fn solve_part2(input: &Data) -> usize { + todo!() +}