diff --git a/src/day02.rs b/src/day02.rs index 7908085..e1ef9ae 100644 --- a/src/day02.rs +++ b/src/day02.rs @@ -1,115 +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 -} +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 index 30964b9..4178e15 100644 --- a/src/day03.rs +++ b/src/day03.rs @@ -1,91 +1,82 @@ -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 -} +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], mut 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]; + } + pos=pos.wrapping_sub(1); + if zero.len() == one.len() { + match mode { + Mode::MostCommon => tree_filter(&one, pos, mode), + Mode::LeastCommon => tree_filter(&zero, pos, mode), + } + } else { + let mut srt = vec![zero, one]; + srt.sort_by_key(|v| v.len()); + match mode { + Mode::MostCommon => tree_filter(&srt[1], pos, mode), + Mode::LeastCommon => tree_filter(&srt[0], pos, 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)] // 1032597 +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 +} \ No newline at end of file diff --git a/src/day04.rs b/src/day04.rs index 5649526..e1783c5 100644 --- a/src/day04.rs +++ b/src/day04.rs @@ -1,92 +1,147 @@ -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(); -} +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 index 558a052..a3b469f 100644 --- a/src/day05.rs +++ b/src/day05.rs @@ -1,106 +1,110 @@ -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 +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.px < self.line.x.1 { + return None; + } + if self.sy > 0 && self.py > self.line.y.1 { + return None; + } + if self.sy < 0 && self.py < self.line.y.1 { + return None; + } + self.px += self.sx; + self.py += self.sy; + Some(ret) + } +} + +type Data = Vec; + +#[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(); +} diff --git a/src/day06.rs b/src/day06.rs index aec4af9..dea1916 100644 --- a/src/day06.rs +++ b/src/day06.rs @@ -1,33 +1,31 @@ -use aoc_runner_derive::{aoc, aoc_generator}; - -type Data = [usize;9]; - -#[aoc_generator(day06)] -pub fn input_generator(input: &str) -> [usize;9] { - let mut state: [usize;9] = [0;9]; - let input = input.trim().split(',').map(|v| v.parse::().unwrap()); - for v in input { - state[v]+=1; - } - state -} - - -fn simulate(input: &Data,n: usize) -> usize { - let mut state=*input; - for i in 0..n { - state[(7+i)%9]+=state[i%9]; - } - state.iter().sum() - -} - -#[aoc(day06, part1)] // 353274 -pub fn solve_part1(input: &Data) -> usize { - simulate(input,80) -} - -#[aoc(day06, part2)] // 1609314870967 -pub fn solve_part2(input: &Data) -> usize { - simulate(input,256) -} +use aoc_runner_derive::{aoc, aoc_generator}; + +type Data = [usize; 9]; + +#[aoc_generator(day06)] +pub fn input_generator(input: &str) -> [usize; 9] { + let mut state: [usize; 9] = [0; 9]; + let input = input.trim().split(',').map(|v| v.parse::().unwrap()); + for v in input { + state[v] += 1; + } + state +} + +fn simulate(input: &Data, n: usize) -> usize { + let mut state = *input; + for i in 0..n { + state[(7 + i) % 9] += state[i % 9]; + } + state.iter().sum() +} + +#[aoc(day06, part1)] // 353274 +pub fn solve_part1(input: &Data) -> usize { + simulate(input, 80) +} + +#[aoc(day06, part2)] // 1609314870967 +pub fn solve_part2(input: &Data) -> usize { + simulate(input, 256) +} diff --git a/src/day07.rs b/src/day07.rs index ed57742..3bc3bc5 100644 --- a/src/day07.rs +++ b/src/day07.rs @@ -1,33 +1,38 @@ -use aoc_runner_derive::{aoc, aoc_generator}; - -type Data = Vec; - -#[aoc_generator(day07)] -pub fn input_generator(input: &str) -> Data { - let mut input: Vec<_> = input.split(',').map(|v| v.parse().unwrap()).collect(); - input.sort_unstable(); - input -} - -#[aoc(day07, part1)] // 336040 -pub fn solve_part1(input: &Data) -> i64 { - let start = *input.first().unwrap(); - let end = *input.last().unwrap(); - (start..=end).map(|n| { - input.iter().map(|v| { - (v-n).abs() - }).sum() - }).min().unwrap() -} - -#[aoc(day07, part2)] // 94813675 -pub fn solve_part2(input: &Data) -> i64 { - let start = *input.first().unwrap(); - let end = *input.last().unwrap(); - (start..=end).map(|n| { - input.iter().map(|v| { - let diff=(v-n).abs(); - (diff*(diff+1))>>1 // Gauss - }).sum() - }).min().unwrap() -} +use aoc_runner_derive::{aoc, aoc_generator}; + +type Data = Vec; + +#[aoc_generator(day07)] +pub fn input_generator(input: &str) -> Data { + let mut input: Vec<_> = input.split(',').map(|v| v.parse().unwrap()).collect(); + input.sort_unstable(); + input +} + +#[aoc(day07, part1)] // 336040 +pub fn solve_part1(input: &Data) -> i64 { + let start = *input.first().unwrap(); + let end = *input.last().unwrap(); + (start..=end) + .map(|n| input.iter().map(|v| (v - n).abs()).sum()) + .min() + .unwrap() +} + +#[aoc(day07, part2)] // 94813675 +pub fn solve_part2(input: &Data) -> i64 { + let start = *input.first().unwrap(); + let end = *input.last().unwrap(); + (start..=end) + .map(|n| { + input + .iter() + .map(|v| { + let diff = (v - n).abs(); + (diff * (diff + 1)) >> 1 // Gauss + }) + .sum() + }) + .min() + .unwrap() +} diff --git a/src/day08.rs b/src/day08.rs new file mode 100644 index 0000000..7ef2aac --- /dev/null +++ b/src/day08.rs @@ -0,0 +1,93 @@ +use std::collections::{BTreeSet, HashMap, HashSet}; + +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::Itertools; + +type Data = HashMap, Vec>; + +#[aoc_generator(day08)] +pub fn input_generator(input: &str) -> Data { + // let input = + // "acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf"; + let mut ret = HashMap::new(); + for line in input.lines() { + let mut line = line.split(" | ").map(|v| { + v.split(' ') + .map(|v| v.chars().sorted().collect::()) + .collect::>() + }); + ret.insert(line.next().unwrap(), line.next().unwrap()); + } + ret +} + +fn resolve_overlaps(digits: &HashMap, HashSet>) -> HashMap, u8> { + todo!() +} + +fn unshuffle(input: &[String], output: &[String]) -> usize { + let mut results: HashMap, u8> = HashMap::new(); + // segments -> candidate digits + let mut digits: HashMap, HashSet> = HashMap::new(); + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 digits + // 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 segments + // println!("Unshuffling: {:?} -> {:?}", input, output); + // LHS is sub-pattern of RHS + let overlap: HashMap> = HashMap::from([ + (0,vec![8]), + (1,vec![3,4,7,8,9]), + (2,vec![8]), + ]); + for val in input { + let candidates: Vec = match val.len() { + 2 => vec![1], + 3 => vec![7], + 4 => vec![4], + 5 => vec![2, 5, 3], + 6 => vec![6, 9], + 7 => vec![8], + _ => unreachable!(), + }; + digits + .entry(val.chars().collect()) + .or_default() + .extend(&candidates); + } + for _ in 0..10 { + // println!("==================="); + // println!("D: {:?}", digits); + // println!("R: {:?}", results); + if results.len() == 10 { + break; + } + for (k, v) in &digits { + if v.len() == 1 { + let c = v.iter().copied().next().unwrap(); + results.insert(k.clone(), c); + } + } + digits.values_mut().for_each(|v| { + for c in results.values() { + v.remove(c); + } + }); + digits = digits.drain().filter(|(_, v)| !v.is_empty()).collect(); + } + return 0; +} + +#[aoc(day08, part1)] // 310 +pub fn solve_part1(input: &Data) -> usize { + input + .values() + .flatten() + .filter(|v| { + [2, 4, 3, 7].contains(&v.len()) + }) + .count() +} + +#[aoc(day08, part2)] +pub fn solve_part2(input: &Data) -> usize { + input.iter().map(|(k, v)| unshuffle(k, v)).sum() +} diff --git a/src/day09.rs b/src/day09.rs new file mode 100644 index 0000000..b626e85 --- /dev/null +++ b/src/day09.rs @@ -0,0 +1,103 @@ +use std::collections::{BTreeSet, VecDeque}; + +use aoc_runner_derive::{aoc, aoc_generator}; + +pub struct Data(Vec>); + +impl Data { + fn shape(&self) -> (usize, usize) { + if !self.0.iter().all(|v| v.len() == self.0[0].len()) { + panic!("Not rectangular!"); + } + (self.0.len(), self.0[0].len()) + } + fn get(&self, x: i64, y: i64) -> Option { + if x < 0 || y < 0 { + return None; + } + self.0 + .get(x as usize) + .map(|v| v.get(y as usize).copied()) + .flatten() + } +} + +#[aoc_generator(day09)] +pub fn input_generator(input: &str) -> Data { + Data( + input + .lines() + .map(|l| { + l.chars() + .map(|c| c.to_digit(10).unwrap().try_into().unwrap()) + .collect() + }) + .collect(), + ) +} + +fn get_low_points(input: &Data) -> Vec<(i64, i64, u8)> { + let mut ret = vec![]; + let (sx, sy) = input.shape(); + let sx = sx as i64; + let sy = sy as i64; + for x in 0..sx { + for y in 0..sy { + let c = input.get(x, y); + if c.is_none() { + continue; + } + let c = c.unwrap(); + let low_point = input + .get(x + 1, y) + .iter() + .chain(input.get(x - 1, y).iter()) + .chain(input.get(x, y + 1).iter()) + .chain(input.get(x, y - 1).iter()) + .all(|v| v > &c); + if low_point { + ret.push((x, y, c)) + } + } + } + ret +} + +#[aoc(day09, part1)] // 468 +pub fn solve_part1(input: &Data) -> usize { + get_low_points(input) + .iter() + .map(|(_, _, v)| (*v as usize) + 1) + .sum() +} + +#[aoc(day09, part2)] +pub fn solve_part2(input: &Data) -> usize { + let mut basins: BTreeSet = BTreeSet::new(); + let mut q = VecDeque::new(); + let mut visited = BTreeSet::<(i64, i64)>::new(); + for (x, y, c) in &get_low_points(input) { + visited.clear(); + q.clear(); + q.push_back((*x, *y, *c)); + while let Some((x, y, c)) = q.pop_front() { + if c == 9 || !visited.insert((x, y)) { + continue; + } + for d in [-1, 1] { + if let Some(v) = input.get(x + d, y) { + if v > c { + q.push_back((x + d, y, v)); + } + } + if let Some(v) = input.get(x, y + d) { + if v > c { + q.push_back((x, y + d, v)); + } + } + } + } + basins.insert(visited.len()); + } + return basins.iter().rev().take(3).product(); +} diff --git a/src/day10.rs b/src/day10.rs new file mode 100644 index 0000000..7895875 --- /dev/null +++ b/src/day10.rs @@ -0,0 +1,66 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +type Data = Vec>; + +#[aoc_generator(day10)] +pub fn input_generator(input: &str) -> Data { + input.lines().map(|l| l.chars().collect()).collect() +} + +pub fn error_score(line: &Vec) -> (usize,Vec) { + let mut score=0; + let mut stack=vec![]; + for c in line { + match c { + '(' => {stack.push(')')}, + '[' => {stack.push(']')}, + '{' => {stack.push('}')}, + '<' => {stack.push('>')}, + ')'|']'|'}'|'>' => { + if let Some(ex) = stack.pop() { + if ex!=*c { + score+=match c { + ')' => 3, + ']' => 57, + '}' => 1197, + '>' => 25137, + c => unreachable!("Unexpected character {:?}!",c) + }; + break; + } + } + }, + c => unreachable!("Unexpected character {:?}!",c) + } + } + (score,stack) +} + +#[aoc(day10, part1)] +pub fn solve_part1(input: &Data) -> usize { + input.iter().map(|v| error_score(v).0).sum() +} + +#[aoc(day10, part2)] +pub fn solve_part2(input: &Data) -> usize { + let mut scores=vec![]; + for line in input { + let mut line_score=0; + let (error_score,mut stack) = error_score(line); + stack.reverse(); + if error_score==0 && !stack.is_empty() { + for c in stack { + line_score*=5; + line_score+=match c { + ')' => 1, + ']' => 2, + '}' => 3, + '>' => 4, + c => unreachable!("Unexpected character {:?}!",c) + } + } + scores.push(line_score); + } + } + scores.sort_unstable(); + scores[scores.len()/2] +} diff --git a/src/lib.rs b/src/lib.rs index eb52f7a..f93ab53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ #![allow(clippy::clippy::needless_return)] #![feature(int_abs_diff)] - use aoc_runner_derive::aoc_lib; pub mod day01; pub mod day02; @@ -9,4 +8,7 @@ pub mod day04; pub mod day05; pub mod day06; pub mod day07; +pub mod day08; +pub mod day09; +pub mod day10; aoc_lib! { year = 2021 }