Day 8.1, 9 and 10, plus formatting and optimization

This commit is contained in:
Daniel S. 2021-12-10 10:34:30 +01:00
parent 54700e121b
commit 21fcc07f3c
10 changed files with 788 additions and 471 deletions

View file

@ -1,115 +1,115 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
use std::{error::Error, str::FromStr}; use std::{error::Error, str::FromStr};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum Direction { enum Direction {
Forward, Forward,
Down, Down,
Up, Up,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Instruction { pub struct Instruction {
direction: Direction, direction: Direction,
amount: usize, amount: usize,
} }
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default)]
pub struct Submarine{ pub struct Submarine {
depth: i64, depth: i64,
pos: i64, pos: i64,
aim: i64 aim: i64,
} }
impl Submarine { impl Submarine {
fn new() -> Self { fn new() -> Self {
Default::default() Default::default()
} }
fn run_p1(&mut self, inst: &Instruction) { fn run_p1(&mut self, inst: &Instruction) {
let d = inst.direction; let d = inst.direction;
let a = inst.amount as i64; let a = inst.amount as i64;
match d { match d {
Direction::Forward => { Direction::Forward => {
self.pos += a; self.pos += a;
} }
Direction::Down => { Direction::Down => {
self.depth += a; self.depth += a;
} }
Direction::Up => { Direction::Up => {
self.depth -= a; self.depth -= a;
} }
}; };
} }
fn run_p2(&mut self, inst: &Instruction) { fn run_p2(&mut self, inst: &Instruction) {
let d = inst.direction; let d = inst.direction;
let a = inst.amount as i64; let a = inst.amount as i64;
match d { match d {
Direction::Forward => { Direction::Forward => {
self.pos += a; self.pos += a;
self.depth += self.aim*a; self.depth += self.aim * a;
} }
Direction::Down => { Direction::Down => {
self.aim += a; self.aim += a;
} }
Direction::Up => { Direction::Up => {
self.aim -= a; self.aim -= a;
} }
}; };
} }
} }
impl FromStr for Instruction { impl FromStr for Instruction {
type Err = Box<dyn Error>; type Err = Box<dyn Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut s = s.split_ascii_whitespace(); let mut s = s.split_ascii_whitespace();
let inst = s.next().unwrap(); let inst = s.next().unwrap();
let amount: usize = s.next().unwrap().parse().unwrap(); let amount: usize = s.next().unwrap().parse().unwrap();
let ret = match inst { let ret = match inst {
"forward" => Self { "forward" => Self {
direction: Direction::Forward, direction: Direction::Forward,
amount, amount,
}, },
"up" => Self { "up" => Self {
direction: Direction::Up, direction: Direction::Up,
amount, amount,
}, },
"down" => Self { "down" => Self {
direction: Direction::Down, direction: Direction::Down,
amount, amount,
}, },
other => { other => {
panic!("Invalid instruction: {}", other) panic!("Invalid instruction: {}", other)
} }
}; };
Ok(ret) Ok(ret)
} }
} }
pub type Data = Vec<Instruction>; pub type Data = Vec<Instruction>;
#[aoc_generator(day02)] #[aoc_generator(day02)]
pub fn input_generator(input: &str) -> Data { pub fn input_generator(input: &str) -> Data {
input input
.lines() .lines()
.map(Instruction::from_str) .map(Instruction::from_str)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.unwrap() .unwrap()
} }
#[aoc(day02, part1)] #[aoc(day02, part1)]
pub fn solve_part1(input: &Data) -> usize { pub fn solve_part1(input: &Data) -> usize {
let mut sm = Submarine::new(); let mut sm = Submarine::new();
for inst in input { for inst in input {
sm.run_p1(inst); sm.run_p1(inst);
} }
(sm.pos * sm.depth) as usize (sm.pos * sm.depth) as usize
} }
#[aoc(day02, part2)] #[aoc(day02, part2)]
pub fn solve_part2(input: &Data) -> usize { pub fn solve_part2(input: &Data) -> usize {
let mut sm = Submarine::new(); let mut sm = Submarine::new();
for inst in input { for inst in input {
sm.run_p2(inst); sm.run_p2(inst);
} }
(sm.pos * sm.depth) as usize (sm.pos * sm.depth) as usize
} }

View file

@ -1,91 +1,82 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
type Data = Vec<u16>;
type Data = Vec<u16>; fn make_histogram(input: &[u16]) -> Vec<(usize, i64)> {
let counts: &mut [Option<i64>] = &mut [None; 64];
fn make_histogram(input: &[u16]) -> Vec<(usize, i64)> { input.iter().for_each(|val| {
let counts: &mut [Option<i64>] = &mut [None; 64]; for (n, count) in counts.iter_mut().enumerate().take(12) {
input.iter().for_each(|val| { let v = count.get_or_insert(0);
for (n, count) in counts.iter_mut().enumerate().take(12) { if ((val >> n) & 1) == 1 {
let v = count.get_or_insert(0); *v += 1;
if ((val >> n) & 1) == 1 { } else {
*v += 1; *v -= 1;
} else { }
*v -= 1; }
} });
} counts.reverse();
}); counts
counts.reverse(); .iter()
counts .enumerate()
.iter() .filter_map(|(a, b)| b.map(|b| (a, b)))
.enumerate() .collect::<Vec<_>>()
.filter_map(|(a, b)| b.map(|b| (a, b))) }
.collect::<Vec<_>>() #[aoc_generator(day03)]
} pub fn input_generator(input: &str) -> Vec<u16> {
input
#[aoc_generator(day03)] .lines()
pub fn input_generator(input: &str) -> Vec<u16> { .map(|l| u16::from_str_radix(l, 2).unwrap())
input .collect()
.lines() }
.map(|l| u16::from_str_radix(l, 2).unwrap()) #[derive(Debug)]
.collect() enum Mode {
} MostCommon,
LeastCommon,
}
#[derive(Debug)] fn tree_filter(data: &[u16], mut pos: usize, mode: Mode) -> u16 {
enum Mode { let (zero, one) = data
MostCommon, .iter()
LeastCommon, .partition::<Vec<u16>, _>(|&v| ((v >> pos) & 1) == 0);
} if data.is_empty() {
panic!("Uh Oh!");
fn tree_filter(data: &[u16], pos: usize, mode: Mode) -> u16 { }
let (zero, one) = data if data.len() == 1 {
.iter() return data[0];
.partition::<Vec<u16>, _>(|&v| ((v >> pos) & 1) == 0); }
if data.is_empty() { pos=pos.wrapping_sub(1);
panic!("Uh Oh!"); if zero.len() == one.len() {
} match mode {
if data.len() == 1 { Mode::MostCommon => tree_filter(&one, pos, mode),
return data[0]; Mode::LeastCommon => tree_filter(&zero, pos, mode),
} }
if zero.len() == one.len() { } else {
match mode { let mut srt = vec![zero, one];
Mode::MostCommon => tree_filter(&one, pos - 1, mode), srt.sort_by_key(|v| v.len());
Mode::LeastCommon => tree_filter(&zero, pos - 1, mode), match mode {
} Mode::MostCommon => tree_filter(&srt[1], pos, mode),
} else { Mode::LeastCommon => tree_filter(&srt[0], pos, mode),
let mut srt = vec![zero, one]; }
srt.sort_by_key(|v| v.len()); }
match mode { }
Mode::MostCommon => tree_filter(&srt[1], pos - 1, mode), const ASCII_ZERO: u8 = 0x30;
Mode::LeastCommon => tree_filter(&srt[0], pos - 1, mode), #[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)| {
const ASCII_ZERO: u8 = 0x30; (
(ASCII_ZERO + (*v >= 0) as u8) as char,
#[aoc(day03, part1)] // 1997414 (ASCII_ZERO + (*v < 0) as u8) as char,
pub fn solve_part1(input: &Data) -> usize { )
let counts = make_histogram(input); })
let (gamma, epsilon): (String, String) = counts .unzip();
.iter() let gamma = usize::from_str_radix(&gamma, 2).unwrap();
.map(|(_, v)| { let epsilon = usize::from_str_radix(&epsilon, 2).unwrap();
( gamma * epsilon
(ASCII_ZERO + (*v >= 0) as u8) as char, }
(ASCII_ZERO + (*v < 0) as u8) as char, #[aoc(day03, part2)] // 1032597
) pub fn solve_part2(input: &[u16]) -> usize {
}) // let input: Vec<bool> = input.iter().for_each(|v| v[0]).collect();
.unzip(); let a = tree_filter(input, 11, Mode::MostCommon) as usize;
let gamma = usize::from_str_radix(&gamma, 2).unwrap(); let b = tree_filter(input, 11, Mode::LeastCommon) as usize;
let epsilon = usize::from_str_radix(&epsilon, 2).unwrap(); a * b
gamma * epsilon }
}
#[aoc(day03, part2)]
pub fn solve_part2(input: &[u16]) -> usize {
// let input: Vec<bool> = 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
}

View file

@ -1,92 +1,147 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub struct Data { pub struct Data {
pub numbers: Vec<u8>, pub numbers: Vec<u8>,
pub boards: Vec<[[(u8,bool); 5]; 5]>, pub boards: Vec<[[(u8, bool); 5]; 5]>,
} }
#[aoc_generator(day04)] #[aoc_generator(day04)]
pub fn input_generator(input: &str) -> Data { pub fn input_generator(input: &str) -> Data {
let mut lines = input.lines(); let mut lines = input.lines();
let mut boards = vec![]; let mut boards = vec![];
let numbers = lines let numbers = lines
.next() .next()
.unwrap() .unwrap()
.split(',') .split(',')
.map(|s| s.parse()) .map(|s| s.parse())
.collect::<Result<Vec<u8>, _>>() .collect::<Result<Vec<u8>, _>>()
.unwrap(); .unwrap();
let mut row = 0; let mut row = 0;
let mut board = [[(0u8,false); 5]; 5]; let mut board = [[(0u8, false); 5]; 5];
for line in lines { for line in lines {
if line.is_empty() { if line.is_empty() {
continue; continue;
} }
let line = line let line = line
.split_ascii_whitespace() .split_ascii_whitespace()
.map(|s| s.parse()) .map(|s| s.parse())
.collect::<Result<Vec<u8>, _>>() .collect::<Result<Vec<u8>, _>>()
.unwrap(); .unwrap();
line.iter().enumerate().for_each(|(i, v)| { line.iter().enumerate().for_each(|(i, v)| {
board[row][i] = (*v,false); board[row][i] = (*v, false);
}); });
row = (row + 1) % 5; row = (row + 1) % 5;
if row == 0 { if row == 0 {
boards.push(board); boards.push(board);
board = [[(0u8,false); 5]; 5]; board = [[(0u8, false); 5]; 5];
} }
} }
Data { numbers, boards } Data { numbers, boards }
} }
#[aoc(day04, part1)] #[aoc(day04, part1)]
pub fn solve_part1(input: &Data) -> usize { pub fn solve_part1(input: &Data) -> usize {
let Data {numbers,mut boards} =input.clone(); let Data {
for number in numbers.iter() { numbers,
for board in &mut boards { mut boards,
for row in board.iter_mut() { } = input.clone();
for (n,b) in row { for number in numbers.iter() {
if n==number { for board in &mut boards {
*b=true; 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); let win = (0..5)
if win { .map(|v| {
return board.iter().flatten().filter_map(|(v,b)| (!*b).then(|| *v as usize)).sum::<usize>()*(*number as usize) [
} board[v][0],
} board[v][1],
} board[v][2],
unreachable!() board[v][3],
} board[v][4],
]
#[aoc(day04, part2)] .iter()
pub fn solve_part2(input: &Data) -> usize { .all(|v| v.1)
let mut ret=None; | [
let Data {numbers,mut boards} =input.clone(); board[0][v],
let mut board_wins: Vec<bool> = vec![false;boards.len()]; board[1][v],
for number in numbers.iter() { board[2][v],
for (board_n,board) in boards.iter_mut().enumerate() { board[3][v],
for row in board.iter_mut() { board[4][v],
for (n,b) in row { ]
if n==number { .iter()
*b=true; .all(|v| v.1)
} })
} .any(|v| v);
} if win {
let win=(0..5).map(|v| { return board
[board[v][0],board[v][1],board[v][2],board[v][3],board[v][4]].iter().all(|v| v.1)| .iter()
[board[0][v],board[1][v],board[2][v],board[3][v],board[4][v]].iter().all(|v| v.1) .flatten()
}).any(|v| v); .filter_map(|(v, b)| (!*b).then(|| *v as usize))
if win && !board_wins[board_n] { .sum::<usize>()
ret=Some(board.iter().flatten().filter(|(_,b)| !*b).map(|(v,_)| *v as usize).sum::<usize>()*(*number as usize)); * (*number as usize);
board_wins[board_n]=true; }
} }
} }
} unreachable!()
return ret.unwrap(); }
}
#[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<bool> = 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::<usize>()
* (*number as usize),
);
board_wins[board_n] = true;
}
}
}
return ret.unwrap();
}

View file

@ -1,106 +1,110 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
#[derive(Debug)] #[derive(Debug)]
pub struct Line { pub struct Line {
x: (i64, i64), x: (i64, i64),
y: (i64, i64), y: (i64, i64),
} }
impl Line { impl Line {
fn iter(&self) -> LineIterator { fn iter(&self) -> LineIterator {
let ret= LineIterator { let ret = LineIterator {
line: self, line: self,
px: self.x.0, px: self.x.0,
py: self.y.0, py: self.y.0,
sx: match self.x.0.cmp(&self.x.1) { sx: match self.x.0.cmp(&self.x.1) {
std::cmp::Ordering::Less => 1, std::cmp::Ordering::Less => 1,
std::cmp::Ordering::Equal => 0, std::cmp::Ordering::Equal => 0,
std::cmp::Ordering::Greater => -1, std::cmp::Ordering::Greater => -1,
}, },
sy: match self.y.0.cmp(&self.y.1) { sy: match self.y.0.cmp(&self.y.1) {
std::cmp::Ordering::Less => 1, std::cmp::Ordering::Less => 1,
std::cmp::Ordering::Equal => 0, std::cmp::Ordering::Equal => 0,
std::cmp::Ordering::Greater => -1, std::cmp::Ordering::Greater => -1,
}, },
}; };
assert!(ret.sx!=0||ret.sy!=0); assert!(ret.sx != 0 || ret.sy != 0);
ret ret
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct LineIterator<'a> { struct LineIterator<'a> {
line: &'a Line, line: &'a Line,
px: i64, px: i64,
py: i64, py: i64,
sx: i64, sx: i64,
sy: i64, sy: i64,
} }
impl<'a> Iterator for LineIterator<'a> { impl<'a> Iterator for LineIterator<'a> {
type Item = (i64, i64); type Item = (i64, i64);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let ret = (self.px,self.py); let ret = (self.px, self.py);
if self.sx>0 && self.px>self.line.x.1 { if self.sx > 0 && self.px > self.line.x.1 {
return None; return None;
} }
if self.sx<0 && self.px<self.line.x.1 { if self.sx < 0 && self.px < self.line.x.1 {
return None; return None;
} }
if self.sy>0 && self.py>self.line.y.1 { if self.sy > 0 && self.py > self.line.y.1 {
return None; return None;
} }
if self.sy<0 && self.py<self.line.y.1 { if self.sy < 0 && self.py < self.line.y.1 {
return None; return None;
} }
self.px+=self.sx; self.px += self.sx;
self.py+=self.sy; self.py += self.sy;
Some(ret) Some(ret)
} }
} }
type Data = Vec<Line>; type Data = Vec<Line>;
#[aoc_generator(day05)] #[aoc_generator(day05)]
pub fn input_generator(input: &str) -> Data { pub fn input_generator(input: &str) -> Data {
input input
.lines() .lines()
.map(|line| { .map(|line| {
let parts= line.split(" -> ").collect::<Vec<_>>(); let parts = line.split(" -> ").collect::<Vec<_>>();
let start = parts[0] let start = parts[0]
.split(',') .split(',')
.map(|v| v.parse().unwrap()) .map(|v| v.parse().unwrap())
.collect::<Vec<i64>>(); .collect::<Vec<i64>>();
let end = parts[1] let end = parts[1]
.split(',') .split(',')
.map(|v| v.parse().unwrap()) .map(|v| v.parse().unwrap())
.collect::<Vec<i64>>(); .collect::<Vec<i64>>();
Line { Line {
x: (start[0], end[0]), x: (start[0], end[0]),
y: (start[1], end[1]), y: (start[1], end[1]),
} }
}) })
.collect() .collect()
} }
#[aoc(day05, part1)] #[aoc(day05, part1)]
pub fn solve_part1(input: &Data) -> usize { pub fn solve_part1(input: &Data) -> usize {
let mut grid = vec![vec![0u8; 1000]; 1000]; 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()) { for (x, y) in input
let x: usize=x.try_into().unwrap(); .iter()
let y: usize=y.try_into().unwrap(); .filter(|l| l.x.0 == l.x.1 || l.y.0 == l.y.1)
grid[x][y] += 1; .flat_map(|v| v.iter())
} {
return grid.iter().flatten().filter(|&v| *v > 1).count(); let x: usize = x.try_into().unwrap();
} let y: usize = y.try_into().unwrap();
grid[x][y] += 1;
#[aoc(day05, part2)] }
pub fn solve_part2(input: &Data) -> usize { return grid.iter().flatten().filter(|&v| *v > 1).count();
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(); #[aoc(day05, part2)]
let y: usize=y.try_into().unwrap(); pub fn solve_part2(input: &Data) -> usize {
grid[x][y] += 1; let mut grid = vec![vec![0u8; 1000]; 1000];
} for (x, y) in input.iter().flat_map(|v| v.iter()) {
return grid.iter().flatten().filter(|&v| *v > 1).count(); 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();
}

View file

@ -1,33 +1,31 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
type Data = [usize;9]; type Data = [usize; 9];
#[aoc_generator(day06)] #[aoc_generator(day06)]
pub fn input_generator(input: &str) -> [usize;9] { pub fn input_generator(input: &str) -> [usize; 9] {
let mut state: [usize;9] = [0;9]; let mut state: [usize; 9] = [0; 9];
let input = input.trim().split(',').map(|v| v.parse::<usize>().unwrap()); let input = input.trim().split(',').map(|v| v.parse::<usize>().unwrap());
for v in input { for v in input {
state[v]+=1; state[v] += 1;
} }
state state
} }
fn simulate(input: &Data, n: usize) -> usize {
fn simulate(input: &Data,n: usize) -> usize { let mut state = *input;
let mut state=*input; for i in 0..n {
for i in 0..n { state[(7 + i) % 9] += state[i % 9];
state[(7+i)%9]+=state[i%9]; }
} state.iter().sum()
state.iter().sum() }
} #[aoc(day06, part1)] // 353274
pub fn solve_part1(input: &Data) -> usize {
#[aoc(day06, part1)] // 353274 simulate(input, 80)
pub fn solve_part1(input: &Data) -> usize { }
simulate(input,80)
} #[aoc(day06, part2)] // 1609314870967
pub fn solve_part2(input: &Data) -> usize {
#[aoc(day06, part2)] // 1609314870967 simulate(input, 256)
pub fn solve_part2(input: &Data) -> usize { }
simulate(input,256)
}

View file

@ -1,33 +1,38 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
type Data = Vec<i64>; type Data = Vec<i64>;
#[aoc_generator(day07)] #[aoc_generator(day07)]
pub fn input_generator(input: &str) -> Data { pub fn input_generator(input: &str) -> Data {
let mut input: Vec<_> = input.split(',').map(|v| v.parse().unwrap()).collect(); let mut input: Vec<_> = input.split(',').map(|v| v.parse().unwrap()).collect();
input.sort_unstable(); input.sort_unstable();
input input
} }
#[aoc(day07, part1)] // 336040 #[aoc(day07, part1)] // 336040
pub fn solve_part1(input: &Data) -> i64 { pub fn solve_part1(input: &Data) -> i64 {
let start = *input.first().unwrap(); let start = *input.first().unwrap();
let end = *input.last().unwrap(); let end = *input.last().unwrap();
(start..=end).map(|n| { (start..=end)
input.iter().map(|v| { .map(|n| input.iter().map(|v| (v - n).abs()).sum())
(v-n).abs() .min()
}).sum() .unwrap()
}).min().unwrap() }
}
#[aoc(day07, part2)] // 94813675
#[aoc(day07, part2)] // 94813675 pub fn solve_part2(input: &Data) -> i64 {
pub fn solve_part2(input: &Data) -> i64 { let start = *input.first().unwrap();
let start = *input.first().unwrap(); let end = *input.last().unwrap();
let end = *input.last().unwrap(); (start..=end)
(start..=end).map(|n| { .map(|n| {
input.iter().map(|v| { input
let diff=(v-n).abs(); .iter()
(diff*(diff+1))>>1 // Gauss .map(|v| {
}).sum() let diff = (v - n).abs();
}).min().unwrap() (diff * (diff + 1)) >> 1 // Gauss
} })
.sum()
})
.min()
.unwrap()
}

93
src/day08.rs Normal file
View file

@ -0,0 +1,93 @@
use std::collections::{BTreeSet, HashMap, HashSet};
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
type Data = HashMap<Vec<String>, Vec<String>>;
#[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::<String>())
.collect::<Vec<_>>()
});
ret.insert(line.next().unwrap(), line.next().unwrap());
}
ret
}
fn resolve_overlaps(digits: &HashMap<BTreeSet<char>, HashSet<u8>>) -> HashMap<BTreeSet<char>, u8> {
todo!()
}
fn unshuffle(input: &[String], output: &[String]) -> usize {
let mut results: HashMap<BTreeSet<char>, u8> = HashMap::new();
// segments -> candidate digits
let mut digits: HashMap<BTreeSet<char>, HashSet<u8>> = 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<u8,Vec<u8>> = HashMap::from([
(0,vec![8]),
(1,vec![3,4,7,8,9]),
(2,vec![8]),
]);
for val in input {
let candidates: Vec<u8> = 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()
}

103
src/day09.rs Normal file
View file

@ -0,0 +1,103 @@
use std::collections::{BTreeSet, VecDeque};
use aoc_runner_derive::{aoc, aoc_generator};
pub struct Data(Vec<Vec<u8>>);
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<u8> {
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<usize> = 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();
}

66
src/day10.rs Normal file
View file

@ -0,0 +1,66 @@
use aoc_runner_derive::{aoc, aoc_generator};
type Data = Vec<Vec<char>>;
#[aoc_generator(day10)]
pub fn input_generator(input: &str) -> Data {
input.lines().map(|l| l.chars().collect()).collect()
}
pub fn error_score(line: &Vec<char>) -> (usize,Vec<char>) {
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]
}

View file

@ -1,6 +1,5 @@
#![allow(clippy::clippy::needless_return)] #![allow(clippy::clippy::needless_return)]
#![feature(int_abs_diff)] #![feature(int_abs_diff)]
use aoc_runner_derive::aoc_lib; use aoc_runner_derive::aoc_lib;
pub mod day01; pub mod day01;
pub mod day02; pub mod day02;
@ -9,4 +8,7 @@ pub mod day04;
pub mod day05; pub mod day05;
pub mod day06; pub mod day06;
pub mod day07; pub mod day07;
pub mod day08;
pub mod day09;
pub mod day10;
aoc_lib! { year = 2021 } aoc_lib! { year = 2021 }