Restructure Rust solutions

This commit is contained in:
Felix Bargfeldt 2023-10-19 17:32:53 +02:00
parent da9884da75
commit a8685c5145
Signed by: Defelo
GPG key ID: 2A05272471204DD3
331 changed files with 3081 additions and 11948 deletions

View file

@ -1,52 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<i32>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/01.txt").unwrap();
return puzzle.lines().map(|x| x.parse().unwrap()).collect();
}
fn count(input: &Input, window: usize) -> i32 {
let mut out = 0;
for (a, b) in input.iter().zip(&input[window..]) {
if b > a { out += 1; }
}
out
}
fn part1(input: &Input) -> String {
count(input, 1).to_string()
}
fn part2(input: &Input) -> String {
count(input, 3).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,78 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
enum Command { Forward(i32), Down(i32), Up(i32) }
type Input = Vec<Command>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/02.txt").unwrap();
puzzle.lines().map(|line| {
let mut x = line.split(" ");
let cmd = x.next().unwrap();
let n: i32 = x.next().unwrap().parse().unwrap();
match cmd {
"forward" => Command::Forward(n),
"up" => Command::Up(n),
"down" => Command::Down(n),
_ => panic!(),
}
}).collect()
}
fn part1(input: &Input) -> String {
let mut d = 0;
let mut h = 0;
for cmd in input {
match cmd {
Command::Forward(n) => { h += n }
Command::Down(n) => { d += n }
Command::Up(n) => { d -= n }
}
}
(d * h).to_string()
}
fn part2(input: &Input) -> String {
let mut d = 0;
let mut h = 0;
let mut a = 0;
for cmd in input {
match cmd {
Command::Forward(n) => {
h += n;
d += a * n;
}
Command::Down(n) => { a += n }
Command::Up(n) => { a -= n }
}
}
(d * h).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,71 +0,0 @@
#![feature(test)]
#![feature(drain_filter)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<String>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/03.txt").unwrap();
puzzle.lines().map(|s| s.to_string()).collect()
}
fn count(input: &Input, i: usize, chr: &char) -> usize {
input.iter().filter(|s| s.chars().nth(i).unwrap() == *chr).count()
}
fn most_common(input: &Input, i: usize) -> char { "01".chars().max_by_key(|c| count(input, i, c)).unwrap() }
fn least_common(input: &Input, i: usize) -> char { "01".chars().min_by_key(|c| count(input, i, c)).unwrap() }
fn part1(input: &Input) -> String {
let mut most = 0;
let mut least = 0;
for i in 0..input[0].len() {
most = most << 1 | most_common(input, i) as u32 - '0' as u32;
least = least << 1 | least_common(input, i) as u32 - '0' as u32;
}
(most * least).to_string()
}
fn find(input: &Input, x: bool) -> isize {
let mut out = input.clone();
for i in 0..input[0].len() {
let mx = if x {least_common(&out, i) } else {most_common(&out, i)};
out.drain_filter(|x|x.chars().nth(i).unwrap() != mx).count();
if out.len() == 1 {
return isize::from_str_radix(out[0].as_str(), 2).unwrap();
}
}
panic!();
}
fn part2(input: &Input) -> String {
(find(input, true) * find(input, false)).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,105 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::FxHashSet;
struct Input {
nums: Vec<i32>,
boards: Vec<Vec<Vec<i32>>>,
}
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/04.txt").unwrap();
let nums = puzzle.lines().next().unwrap().split(",").map(|n| n.parse().unwrap()).collect();
let boards = puzzle.split("\n\n").skip(1).map(|board| {
board.lines().map(|line| {
line.split_whitespace().map(|n| n.parse().unwrap()).collect()
}).collect()
}).collect();
return Input { nums, boards };
}
struct State {
boards: Vec<Vec<Vec<i32>>>,
marked: FxHashSet<i32>,
}
impl State {
fn from_input(input: &Input) -> State {
State {boards: input.boards.clone(), marked: FxHashSet::default()}
}
fn mark(&mut self, num: i32) {
self.marked.insert(num);
}
fn check_board(&self, board: usize) -> bool {
let board = &self.boards[board];
for row in board {
if row.iter().all(|n| self.marked.contains(n)) { return true; }
}
for i in 0..board[0].len() {
if board.iter().all(|row| self.marked.contains(&row[i])) { return true; }
}
false
}
fn get_score(&self, board: usize) -> i32 {
*&self.boards[board].iter().flatten().filter(|n| {
!self.marked.contains(n)
}).map(|n|*n).reduce(|a, b| a + b).unwrap()
}
}
fn part1(input: &Input) -> String {
let mut state = State::from_input(input);
for num in &input.nums {
state.mark(*num);
for i in 0..state.boards.len() {
if state.check_board(i) {
return (num * state.get_score(i)).to_string();
}
}
}
panic!();
}
fn part2(input: &Input) -> String {
let mut state = State::from_input(input);
for num in &input.nums {
state.mark(*num);
let mut i = 0;
while i < state.boards.len() {
if !state.check_board(i) { i += 1; continue }
if state.boards.len() == 1 { return (num * state.get_score(i)).to_string()}
state.boards.remove(i);
}
}
panic!()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,84 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use regex::Regex;
use rustc_hash::FxHashMap;
type Line = (i32, i32, i32, i32);
type Input = Vec<Line>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/05.txt").unwrap();
let regex = Regex::new(r"^(\d+),(\d+) -> (\d+),(\d+)$").unwrap();
puzzle.lines().map(|line| {
let capture = regex.captures(line).unwrap();
(
capture[1].parse().unwrap(),
capture[2].parse().unwrap(),
capture[3].parse().unwrap(),
capture[4].parse().unwrap(),
)
}).collect()
}
fn iter_line(line: &Line) -> Vec<(i32, i32)> {
let (mut x, mut y, x2, y2) = line;
let mut result = vec![(x, y)];
while (x != *x2) || (y != *y2) {
if x < *x2 { x += 1; }
else if x > *x2 { x -= 1; }
if y < *y2 { y += 1; }
else if y > *y2 { y -= 1; }
result.push((x, y));
}
result
}
fn part1(input: &Input) -> String {
let mut counter = FxHashMap::default();
for line in input {
if (line.0 != line.2) && (line.1 != line.3) { continue }
for (x, y) in iter_line(line) {
let cnt = *counter.entry((x, y)).or_insert(0) + 1;
counter.insert((x, y), cnt);
}
}
counter.iter().filter(|&(_, &cnt)| cnt > 1).count().to_string()
}
fn part2(input: &Input) -> String {
let mut counter = FxHashMap::default();
for line in input {
for (x, y) in iter_line(line) {
let cnt = *counter.entry((x, y)).or_insert(0) + 1;
counter.insert((x, y), cnt);
}
}
counter.iter().filter(|&(_, &cnt)| cnt > 1).count().to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,57 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<i32>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/06.txt").unwrap();
puzzle.trim().split(",").map(|x| x.parse().unwrap()).collect()
}
fn solve(input: &Input, n: u32) -> String {
let mut counter = vec![0; 9];
for num in input {
counter[*num as usize] += 1;
}
for _ in 0..n {
let x = counter.remove(0);
counter.push(x);
counter[6] += x;
}
counter.iter().sum::<u64>().to_string()
}
fn part1(input: &Input) -> String {
solve(input, 80)
}
fn part2(input: &Input) -> String {
solve(input, 256)
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,51 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<i32>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/07.txt").unwrap();
puzzle.trim().split(",").map(|x| x.parse().unwrap()).collect()
}
fn part1(input: &Input) -> String {
(0..=input.len()).map(|pos| {
input.iter().map(|n| (pos as i32 - *n).abs()).sum::<i32>()
}).min().unwrap().to_string()
}
fn part2(input: &Input) -> String {
(0..=input.len()).map(|pos| {
input.iter().map(|n| {
let x = (pos as i32 - *n).abs();
x * (x + 1) >> 1
}).sum::<i32>()
}).min().unwrap().to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,107 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::{FxHashMap, FxHashSet};
struct Line {
patterns: Vec<String>,
output: Vec<String>,
}
type Input = Vec<Line>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/08.txt").unwrap();
puzzle.lines().map(|line| {
let mut line = line.trim().split(" | ");
let mut parse = || line.next().unwrap().split(" ").map(|x| x.to_string()).collect();
Line {
patterns: parse(),
output: parse(),
}
}).collect()
}
fn part1(input: &Input) -> String {
input.iter().map(|line| {
line.output.iter().filter(|x| [2, 3, 4, 7].contains(&x.len())).count()
}).sum::<usize>().to_string()
}
fn parse_num(num: &String) -> u16 {
num.chars().map(|c| {
1 << (c as u16) - ('a' as u16)
}).sum::<u16>()
}
fn is_subset(mut a: u16, mut b: u16) -> bool {
while a > 0 {
if 1 & a & !b == 1 { return false; }
a >>= 1;
b >>= 1;
}
true
}
fn part2(input: &Input) -> String {
let digits = FxHashMap::from_iter([((7, 2), 1), ((2, 5), 2), ((3, 5), 3), ((3, 4), 4), ((4, 5), 5), ((5, 3), 7), ((1, 7), 8)]);
input.iter().map(|line| {
let patterns: Vec<u16> = line.patterns.iter().map(parse_num).collect();
let output: Vec<u16> = line.output.iter().map(parse_num).collect();
let mut mp: FxHashMap<u16, u8> = FxHashMap::default();
let mut rp: FxHashMap<u8, u16> = FxHashMap::default();
let mut u: FxHashSet<u16> = FxHashSet::from_iter(patterns.iter().cloned());
for x in &patterns {
let sc = patterns.iter().filter(|y| is_subset(*x, **y)).count();
match digits.get(&(sc, x.count_ones())) {
None => {}
Some(digit) => {
mp.insert(*x, *digit);
rp.insert(*digit, *x);
u.remove(x);
}
}
}
let x = *u.iter().filter(|x| !is_subset(*rp.get(&5).unwrap(), **x)).next().unwrap();
mp.insert(x, 0);
u.remove(&x);
let x = *u.iter().filter(|x| is_subset(*rp.get(&4).unwrap(), **x)).next().unwrap();
mp.insert(x, 9);
u.remove(&x);
let x = *u.iter().next().unwrap();
mp.insert(x, 6);
output.iter().map(|x| *mp.get(x).unwrap() as u32).reduce(|a, b| a * 10 + b).unwrap()
}).sum::<u32>().to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}

View file

@ -1,82 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<String>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/10.txt").unwrap();
puzzle.lines().map(|s| s.to_string()).collect()
}
fn part1(input: &Input) -> String {
input.iter().map(|line| {
let mut stack = Vec::new();
for c in line.chars() {
if "([{<".contains(c) {
stack.push(c);
} else {
let x = stack.pop().unwrap();
if !["()", "[]", "{}", "<>"].contains(&format!("{}{}", x, c).as_str()) {
return match c {
')' => 3,
']' => 57,
'}' => 1197,
'>' => 25137,
_ => panic!()
};
}
}
}
0
}).sum::<u32>().to_string()
}
fn part2(input: &Input) -> String {
let mut scores: Vec<usize> = input.iter().filter_map(|line| {
let mut stack = Vec::new();
for c in line.chars() {
if "([{<".contains(c) {
stack.push(c);
} else {
let x = stack.pop().unwrap();
if !["()", "[]", "{}", "<>"].contains(&format!("{}{}", x, c).as_str()) {
return None;
}
}
}
let mut out = 0;
for c in stack.iter().rev() {
out = out * 5 + " ([{<".find(*c).unwrap();
}
Some(out)
}).collect();
scores.sort();
scores[scores.len() / 2].to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,87 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::{FxHashMap, FxHashSet};
type Input = FxHashMap<i32, Vec<i32>>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/12.txt").unwrap();
let mut out = FxHashMap::default();
let mut map = FxHashMap::default();
map.insert("start", 0);
map.insert("end", 1);
for line in puzzle.trim().lines() {
let mut split = line.split("-").map(|x| {
if !map.contains_key(x) { map.insert(x, (map.len() as i32) * if x < "a" { 1 } else { -1 }); }
*map.get(x).unwrap()
});
let a = split.next().unwrap();
let b = split.next().unwrap();
match out.get_mut(&a) {
None => { out.insert(a, vec![b]); }
Some(x) => { x.push(b); }
}
match out.get_mut(&b) {
None => { out.insert(b, vec![a]); }
Some(x) => { x.push(a); }
}
}
out
}
fn search(node: i32, graph: &Input, visited: &mut FxHashSet<i32>, small_twice: bool) -> u32 {
if node == 1 { return 1; }
let mut twice = false;
if node <= 0 && visited.contains(&node) {
if small_twice || node == 0 { return 0; }
twice = true;
}
visited.insert(node);
let out = match graph.get(&node) {
None => 0,
Some(edges) => edges.iter().cloned().map(|next|
search(next, graph, visited, twice || small_twice)
).sum::<u32>()
};
if !twice { visited.remove(&node); }
out
}
fn part1(input: &Input) -> String {
search(0, input, &mut FxHashSet::default(), true).to_string()
}
fn part2(input: &Input) -> String {
search(0, input, &mut FxHashSet::default(), false).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,109 +0,0 @@
#![feature(test)]
extern crate test;
use std::borrow::Borrow;
use std::fs;
use test::Bencher;
use regex::Regex;
use rustc_hash::FxHashSet;
enum Instruction { X(u32), Y(u32) }
struct Input {
dots: FxHashSet<(u32, u32)>,
instructions: Vec<Instruction>,
}
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/13.txt").unwrap();
let mut blocks = puzzle.split("\n\n");
let dots = blocks.next().unwrap().lines().map(|line| {
let mut coords = line.split(",");
(coords.next().unwrap().parse().unwrap(), coords.next().unwrap().parse().unwrap())
}).collect();
let regex = Regex::new(r"^fold along (.)=(\d+)$").unwrap();
let instructions = blocks.next().unwrap().lines().map(|line| {
let capture = regex.captures(line).unwrap();
let n: u32 = capture.get(2).unwrap().as_str().parse().unwrap();
match capture.get(1).unwrap().as_str() {
"x" => Instruction::X(n),
"y" => Instruction::Y(n),
_ => panic!()
}
}).collect();
Input { dots, instructions }
}
fn fold(dots: &FxHashSet<(u32, u32)>, instruction: &Instruction) -> FxHashSet<(u32, u32)> {
dots.iter().cloned().map(|(x, y)| {
match instruction {
Instruction::X(n) => (x.min(2 * n - x), y),
Instruction::Y(n) => (x, y.min(2 * n - y)),
}
}).collect()
}
fn part1(input: &Input) -> String {
let mut dots = input.dots.clone();
let instruction = input.instructions.first().unwrap();
dots = fold(&dots, instruction);
dots.len().to_string()
}
fn part2(input: &Input) -> String {
let mut dots = input.dots.clone();
for instruction in &input.instructions {
dots = fold(&dots, instruction);
}
(0..8).map(|n| {
let k = (5 * n..5 * n+4).flat_map(|i| {
let dots = &dots;
(0..6).map(move |j| {
dots.contains(&(i, j))
})
}).fold(0, |acc, x| { (acc << 1) | (x as i32) });
match k {
0b011111100100100100011111 => 'A',
0b111111101001101001010110 => 'B',
0b011110100001100001010010 => 'C',
0b111111101001101001100001 => 'E',
0b111111101000101000100000 => 'F',
0b011110100001100101010111 => 'G',
0b111111001000001000111111 => 'H',
0b000010000001100001111111 => 'J',
0b111111001000010110100001 => 'K',
0b111111000001000001000001 => 'L',
0b111111100100100100011000 => 'P',
0b111111100100100110011001 => 'R',
0b111110000001000001111110 => 'U',
0b100011100101101001110001 => 'Z',
_ => '?'
}
}).collect::<String>()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,78 +0,0 @@
#![feature(test)]
extern crate test;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::fs;
use test::Bencher;
use rustc_hash::FxHashSet;
type Input = Vec<Vec<u32>>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/15.txt").unwrap();
puzzle.lines().map(|line| {
line.chars().map(|c| (c as u32) - 0x30).collect()
}).collect()
}
fn dijkstra(grid: &Input, k: usize) -> u32 {
let w = grid[0].len();
let h = grid.len();
let mut queue = BinaryHeap::new();
queue.push(Reverse((0u32, 0usize, 0usize)));
let mut visited = FxHashSet::default();
while !queue.is_empty() {
let (d, x, y) = queue.pop().unwrap().0;
if visited.contains(&(x, y)) { continue; }
visited.insert((x, y));
if x == w * k - 1 && y == h * k - 1 { return d; }
for (dx, dy) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let p = (x as i32) + dx;
let q = (y as i32) + dy;
if p < 0 || q < 0 { continue; }
let p = p as usize;
let q = q as usize;
if p >= k * w || q >= k * h { continue; }
if visited.contains(&(p, q)) { continue; }
let c = grid[q % h][p % w] + (q / h + p / w) as u32;
queue.push(Reverse((d + (c - 1) % 9 + 1, p, q)));
}
}
panic!();
}
fn part1(input: &Input) -> String {
dijkstra(input, 1).to_string()
}
fn part2(input: &Input) -> String {
dijkstra(input, 5).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,144 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Number = [Option<u32>; 64];
type Input = Vec<Number>;
fn parent(n: usize) -> usize { n >> 1 }
fn left(n: usize) -> usize { n << 1 }
fn right(n: usize) -> usize { n << 1 | 1 }
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/18.txt").unwrap();
puzzle.trim().lines().map(|line| {
let mut out = [Option::None; 64];
let mut acc = Option::None;
let mut n = 1;
for c in line.trim().chars() {
let digit = (c as i32) - 0x30;
if digit >= 0 && digit <= 9 {
acc = Option::Some(acc.unwrap_or(0) * 10 + (digit as u32));
continue;
}
let mut write = |x| {
if let Some(_) = acc { out[n] = acc; }
acc = Option::None;
x
};
n = match c {
'[' => left(n),
',' => write(n + 1),
']' => write(parent(n)),
_ => panic!()
}
}
out
}).collect()
}
fn move_up(lst: &mut Number, i: usize, x: u32) {
match lst[i] {
None => { move_up(lst, parent(i), x); }
Some(y) => { lst[i] = Some(x + y); }
}
}
fn explode(lst: &mut Number) -> bool {
for n in (1 << 4)..(1 << 5) {
if let Option::Some(_) = lst[n] { continue; }
let a = left(n);
let b = right(n);
if let (Option::Some(l), Option::Some(r)) = (lst[a], lst[b]) {
lst[a] = Option::None;
lst[b] = Option::None;
lst[n] = Option::Some(0);
if a - 1 >= 1 << 5 {
move_up(lst, a - 1, l);
}
if b + 1 < 1 << 6 {
move_up(lst, b + 1, r);
}
return true;
}
}
false
}
fn split(lst: &mut Number, n: usize) -> bool {
if let Option::Some(x) = lst[n] {
if x < 10 { return false; }
let k = x >> 1;
lst[n] = Option::None;
lst[left(n)] = Option::Some(k);
lst[right(n)] = Option::Some(x - k);
return true;
}
split(lst, left(n)) || split(lst, right(n))
}
fn add(a: &Number, b: &Number) -> Number {
let mut out = [Option::None; 64];
let mut j = 2;
for i in 0..=4 {
for k in (1 << i)..(1 << i + 1) {
out[j] = a[k];
j += 1;
}
for k in (1 << i)..(1 << i + 1) {
out[j] = b[k];
j += 1;
}
}
while explode(&mut out) || split(&mut out, 1) {};
out
}
fn magnitude(lst: &Number, n: usize) -> u32 {
if let Some(x) = lst[n] { x }
else { 3 * magnitude(lst, left(n)) + 2 * magnitude(lst, right(n)) }
}
fn part1(input: &Input) -> String {
magnitude(&input.iter().cloned().reduce(|a, b| { add(&a, &b) }).unwrap(), 1).to_string()
}
fn part2(input: &Input) -> String {
input.iter().flat_map(|a| {
input.iter().filter_map(move |b| {
if a == b { Option::None } else { Option::Some(magnitude(&add(a, b), 1)) }
})
}).max().unwrap().to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,77 +0,0 @@
#![feature(test)]
#![feature(destructuring_assignment)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::FxHashSet;
struct Input {
algo: Vec<bool>,
width: usize,
height: usize,
grid: FxHashSet<(i32, i32)>,
}
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/20.txt").unwrap();
let mut lines = puzzle.lines();
let algo = lines.next().unwrap().chars().map(|c| c == '#').collect();
let grid = lines.skip(1).enumerate().flat_map(|(i, line)| {
line.chars().enumerate().filter_map(move |(j, c)| {
if c == '#' { Option::Some((j as i32, i as i32)) } else { Option::None }
})
}).collect();
Input { algo, grid, width: puzzle.lines().nth(2).unwrap().len(), height: puzzle.lines().count() - 2 }
}
fn get_neighbors(x: i32, y: i32) -> Vec<(i32, i32)> {
(-1..=1).flat_map(|dy| {
(-1..=1).map(move |dx| {
(x + dx, y + dy)
})
}).collect()
}
fn solve(input: &Input) -> (usize, usize) {
let mut grid = input.grid.clone();
let mut inf = false;
let mut part1 = 0;
let mut part2 = 0;
for i in 1..=50 {
let new_inf = inf != input.algo[0];
grid = (-i..=input.height as i32 + i).flat_map(|y| {
(-i..=input.width as i32 + i).map(move |x| (x, y))
}).filter(|(x, y)| {
let idx = get_neighbors(*x, *y).iter().fold(0, |acc, (p, q)| {
acc << 1 | (grid.contains(&(*p, *q)) != inf) as usize
});
input.algo[idx] != new_inf
}).collect();
inf = new_inf;
if i == 2 {part1 = grid.len(); }
if i == 50 {part2 = grid.len(); }
}
(part1, part2)
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
let (part1, part2) = solve(&input);
(part1.to_string(), part2.to_string())
}
#[bench]
fn bench(b: &mut Bencher) {
let input = get_input();
b.iter(|| solve(&input))
}

View file

@ -1,176 +0,0 @@
#![allow(unused)]
#![feature(test)]
#![feature(drain_filter)]
#![feature(int_abs_diff)]
#![feature(binary_heap_into_iter_sorted)]
#![feature(div_duration)]
use std::ops::AddAssign;
use std::path::Path;
use std::time::{Duration, Instant};
#[path = "01.rs"]
mod d01;
#[path = "02.rs"]
mod d02;
#[path = "03.rs"]
mod d03;
#[path = "04.rs"]
mod d04;
#[path = "05.rs"]
mod d05;
#[path = "06.rs"]
mod d06;
#[path = "07.rs"]
mod d07;
#[path = "08.rs"]
mod d08;
#[path = "09.rs"]
mod d09;
#[path = "10.rs"]
mod d10;
#[path = "11.rs"]
mod d11;
#[path = "12.rs"]
mod d12;
#[path = "13.rs"]
mod d13;
#[path = "14.rs"]
mod d14;
#[path = "15.rs"]
mod d15;
#[path = "16.rs"]
mod d16;
#[path = "17.rs"]
mod d17;
#[path = "18.rs"]
mod d18;
#[path = "19.rs"]
mod d19;
#[path = "20.rs"]
mod d20;
#[path = "21.rs"]
mod d21;
#[path = "22.rs"]
mod d22;
#[path = "23.rs"]
mod d23;
#[path = "24.rs"]
mod d24;
#[path = "25.rs"]
mod d25;
struct Day {
day: i32,
func: fn() -> (String, String),
part1: &'static str,
part2: &'static str,
}
struct DayResult<'a> {
day: &'a Day,
part1: String,
part2: String,
duration: Duration,
}
fn print_result(part: u8, actual: &String, expected: &str, total: &mut usize, failed: &mut usize) {
if expected.is_empty() {
println!("\x1b[33m skipped\x1b[0m | Part {}: \x1b[33m{}\x1b[0m", part, actual);
} else if actual == expected {
total.add_assign(1);
println!("\x1b[32m\x1b[1m✔ passed\x1b[0m | Part {}: \x1b[32m{}\x1b[0m", part, actual);
} else {
total.add_assign(1);
failed.add_assign(1);
println!("\x1b[31m\x1b[1m✘ failed\x1b[0m | Part {}: \x1b[31m{}\x1b[0m -> \x1b[32m{}\x1b[0m", part, actual, expected);
}
}
fn main() {
println!("##### Advent of Code 2021 #####");
let mut results = vec![];
let mut total = 0;
let mut failed = 0;
for day in &[
Day { day: 01, func: d01::run, part1: "1266", part2: "1217" },
Day { day: 02, func: d02::run, part1: "1648020", part2: "1759818555" },
Day { day: 03, func: d03::run, part1: "3895776", part2: "7928162" },
Day { day: 04, func: d04::run, part1: "49860", part2: "24628" },
Day { day: 05, func: d05::run, part1: "5698", part2: "15463" },
Day { day: 06, func: d06::run, part1: "345793", part2: "1572643095893" },
Day { day: 07, func: d07::run, part1: "340052", part2: "92948968" },
Day { day: 08, func: d08::run, part1: "392", part2: "1004688" },
Day { day: 09, func: d09::run, part1: "425", part2: "1135260" },
Day { day: 10, func: d10::run, part1: "278475", part2: "3015539998" },
Day { day: 11, func: d11::run, part1: "1659", part2: "227" },
Day { day: 12, func: d12::run, part1: "3679", part2: "107395" },
Day { day: 13, func: d13::run, part1: "747", part2: "ARHZPCUH" },
Day { day: 14, func: d14::run, part1: "3247", part2: "4110568157153" },
Day { day: 15, func: d15::run, part1: "366", part2: "2829" },
Day { day: 16, func: d16::run, part1: "906", part2: "819324480368" },
Day { day: 17, func: d17::run, part1: "3916", part2: "2986" },
Day { day: 18, func: d18::run, part1: "4469", part2: "4770" },
Day { day: 19, func: d19::run, part1: "403", part2: "10569" },
Day { day: 20, func: d20::run, part1: "5419", part2: "17325" },
Day { day: 21, func: d21::run, part1: "1067724", part2: "630947104784464" },
Day { day: 22, func: d22::run, part1: "623748", part2: "1227345351869476" },
Day { day: 23, func: d23::run, part1: "13520", part2: "48708" },
Day { day: 24, func: d24::run, part1: "96979989692495", part2: "51316214181141" },
Day { day: 25, func: d25::run, part1: "380", part2: "" },
] {
if !Path::new(format!("2021/{:02}.txt", day.day).as_str()).exists() {continue;}
let s = Instant::now();
let (part1, part2) = (day.func)() as (String, String);
results.push(DayResult {day, part1, part2, duration: s.elapsed()});
}
let total_duration = results.iter().map(|DayResult {duration, .. }| {
duration
}).sum::<Duration>();
for DayResult {day, part1, part2, duration} in results {
println!();
println!("=== Day {} ===", day.day);
print_result(1, &part1, day.part1, &mut total, &mut failed);
if day.day != 25 {
print_result(2, &part2, day.part2, &mut total, &mut failed);
}
println!(" => {:.6} ms ({:.2}%)", duration.as_secs_f64() * 1000f64, duration.div_duration_f64(total_duration) * 100f64);
}
println!();
if failed == 0 {
println!("\x1b[32m\x1b[1m✔ {}/{} passed\x1b[0m", total, total);
} else {
println!("\x1b[31m\x1b[1m✘ {}/{} failed\x1b[0m", failed, total);
}
println!("=> {:.6} ms", total_duration.as_secs_f64() * 1000f64);
}

View file

@ -1,122 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use regex::Regex;
struct Cuboid {
x1: i64,
x2: i64,
y1: i64,
y2: i64,
z1: i64,
z2: i64,
off: Vec<Cuboid>,
}
fn line_intersection(a1: i64, a2: i64, b1: i64, b2: i64) -> Option<(i64, i64)> {
if a2 < b1 || b2 < a1 { Option::None } else { Option::Some((a1.max(b1), a2.min(b2))) }
}
impl Cuboid {
fn copy(&self) -> Cuboid {
Cuboid {
x1: self.x1,
x2: self.x2,
y1: self.y1,
y2: self.y2,
z1: self.z1,
z2: self.z2,
off: vec![],
}
}
fn get_intersection(&self, c: &Cuboid) -> Option<Cuboid> {
let x = line_intersection(self.x1, self.x2, c.x1, c.x2);
let y = line_intersection(self.y1, self.y2, c.y1, c.y2);
let z = line_intersection(self.z1, self.z2, c.z1, c.z2);
if let (Option::Some(x), Option::Some(y), Option::Some(z)) = (x, y, z) {
Option::Some(Cuboid { x1: x.0, x2: x.1, y1: y.0, y2: y.1, z1: z.0, z2: z.1, off: vec![] })
} else { Option::None }
}
fn subtract(&mut self, c: &Cuboid) {
if let Option::Some(intersection) = self.get_intersection(c) {
for o in self.off.iter_mut() {
o.subtract(c);
}
self.off.push(intersection);
}
}
fn volume(&self) -> i64 {
(self.x2 - self.x1 + 1) * (self.y2 - self.y1 + 1) * (self.z2 - self.z1 + 1) - self.off.iter().map(|c| c.volume()).sum::<i64>()
}
}
struct Step {
on: bool,
cuboid: Cuboid,
}
type Input = Vec<Step>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/22.txt").unwrap();
let regex = Regex::new(r"^(on|off) x=(-?\d+)..(-?\d+),y=(-?\d+)..(-?\d+),z=(-?\d+)..(-?\d+)$").unwrap();
puzzle.lines().map(|line| {
let capture = regex.captures(line).unwrap();
let get_num = |i| capture.get(i).unwrap().as_str().parse().unwrap();
Step {
on: capture.get(1).unwrap().as_str() == "on",
cuboid: Cuboid { x1: get_num(2), x2: get_num(3), y1: get_num(4), y2: get_num(5), z1: get_num(6), z2: get_num(7), off: vec![] },
}
}).collect()
}
fn part1(input: &Input) -> String {
let mut cuboids: Vec<Cuboid> = vec![];
for Step { on, cuboid } in input {
if cuboid.x1 < -50 || cuboid.x2 > 50 || cuboid.y1 < -50 || cuboid.y2 > 50 || cuboid.z1 < -50 || cuboid.z2 > 50 {
continue;
}
for c in cuboids.iter_mut() { c.subtract(cuboid); }
if *on { cuboids.push(cuboid.copy()); }
}
cuboids.iter().map(|c| c.volume()).sum::<i64>().to_string()
}
fn part2(input: &Input) -> String {
let mut cuboids: Vec<Cuboid> = vec![];
for Step { on, cuboid } in input {
for c in cuboids.iter_mut() { c.subtract(cuboid); }
if *on { cuboids.push(cuboid.copy()); }
}
cuboids.iter().map(|c| c.volume()).sum::<i64>().to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}

View file

@ -1,79 +0,0 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
#[derive(Copy, Clone, Eq, PartialEq)]
enum Type { EMPTY, RIGHT, DOWN }
type Input = Vec<Vec<Type>>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/25.txt").unwrap();
puzzle.lines().map(|line| {
line.chars().map(|c| {
match c {
'v' => Type::DOWN,
'>' => Type::RIGHT,
_ => Type::EMPTY
}
}).collect()
}).collect()
}
fn solve(input: &Input) -> String {
let mut grid = input.clone();
let mut cnt = 0;
loop {
let mut moved = false;
let mut new_grid = grid.clone();
for (i, line) in grid.iter().enumerate() {
for (j, &c) in line.iter().enumerate() {
if c == Type::RIGHT {
let k = (j + 1) % line.len();
if grid[i][k] == Type::EMPTY {
new_grid[i][k] = Type::RIGHT;
new_grid[i][j] = Type::EMPTY;
moved = true;
}
}
}
}
grid = new_grid;
let mut new_grid = grid.clone();
for (i, line) in grid.iter().enumerate() {
for (j, &c) in line.iter().enumerate() {
if c == Type::DOWN {
let k = (i + 1) % grid.len();
if grid[k][j] == Type::EMPTY {
new_grid[k][j] = Type::DOWN;
new_grid[i][j] = Type::EMPTY;
moved = true;
}
}
}
}
grid = new_grid;
cnt += 1;
if !moved { break; }
}
cnt.to_string()
}
fn main() {
let (part1, _) = run();
println!("Part 1: {}", part1);
}
pub fn run() -> (String, String) {
let input = get_input();
(solve(&input), "".to_string())
}
#[bench]
fn bench(b: &mut Bencher) {
let input = get_input();
b.iter(|| solve(&input))
}

View file

@ -1,37 +0,0 @@
type Input = Vec<Vec<u32>>;
fn setup(input: &str) -> Input {
input
.trim()
.split("\n\n")
.map(|elf| elf.split_whitespace().map(|x| x.parse().unwrap()).collect())
.collect()
}
fn part1(input: &Input) -> u32 {
input.iter().map(|elf| elf.iter().sum()).max().unwrap()
}
fn part2(input: &Input) -> u32 {
let (a, b, c) = input
.iter()
.map(|elf| elf.iter().sum())
.fold((0, 0, 0), |(a, b, c), x| {
if x > b {
if x > a {
(x, a, b)
} else {
(a, x, b)
}
} else if x > c {
(a, b, x)
} else {
(a, b, c)
}
});
a + b + c
}
aoc::main!(2022, 1);
aoc::example!(ex01, "01.1.txt", 24000, 45000);
aoc::test_input!("01.txt", 69912, 208180);

691
Cargo.lock generated
View file

@ -1,691 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "AdventOfCode"
version = "0.1.0"
dependencies = [
"counter",
"criterion",
"itertools",
"num",
"regex",
"rustc-hash",
]
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
[[package]]
name = "ciborium-ll"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"bitflags",
"clap_lex",
"indexmap",
"textwrap",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "counter"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d458e66999348f56fd3ffcfbb7f7951542075ca8359687c703de6500c1ddccd"
dependencies = [
"num-traits",
]
[[package]]
name = "criterion"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
dependencies = [
"anes",
"atty",
"cast",
"ciborium",
"clap",
"criterion-plot",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "js-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "plotters"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
[[package]]
name = "plotters-svg"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
dependencies = [
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "web-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -1,197 +0,0 @@
[package]
name = "AdventOfCode"
version = "0.1.0"
edition = "2021"
[profile.dev]
opt-level = 3
[profile.release]
opt-level = 3
debug = false
strip = true
debug-assertions = false
overflow-checks = false
lto = true
panic = "abort"
incremental = false
codegen-units = 1
rpath = false
[dependencies]
regex = "*"
counter = "*"
rustc-hash = "*"
criterion = "0.4.0"
itertools = "0.10.5"
num = "0.4.0"
[features]
default = ["test_input"]
test_input = []
[lib]
name = "aoc"
path = "lib/lib.rs"
[[bin]]
name = "2022_01"
path = "2022/01.rs"
[[bench]]
name = "2022_01"
path = "2022/01.rs"
harness = false
[[bin]]
name = "2022_02"
path = "2022/02.rs"
[[bench]]
name = "2022_02"
path = "2022/02.rs"
harness = false
[[bin]]
name = "2022_03"
path = "2022/03.rs"
[[bench]]
name = "2022_03"
path = "2022/03.rs"
harness = false
[[bin]]
name = "2022_04"
path = "2022/04.rs"
[[bench]]
name = "2022_04"
path = "2022/04.rs"
harness = false
[[bin]]
name = "2022_05"
path = "2022/05.rs"
[[bench]]
name = "2022_05"
path = "2022/05.rs"
harness = false
[[bin]]
name = "2022_06"
path = "2022/06.rs"
[[bench]]
name = "2022_06"
path = "2022/06.rs"
harness = false
[[bin]]
name = "2022_07"
path = "2022/07.rs"
[[bench]]
name = "2022_07"
path = "2022/07.rs"
harness = false
[[bin]]
name = "2022_08"
path = "2022/08.rs"
[[bench]]
name = "2022_08"
path = "2022/08.rs"
harness = false
[[bin]]
name = "2022_09"
path = "2022/09.rs"
[[bench]]
name = "2022_09"
path = "2022/09.rs"
harness = false
[[bin]]
name = "2022_10"
path = "2022/10.rs"
[[bench]]
name = "2022_10"
path = "2022/10.rs"
harness = false
[[bin]]
name = "2022_11"
path = "2022/11.rs"
[[bench]]
name = "2022_11"
path = "2022/11.rs"
harness = false
[[bin]]
name = "2022_12"
path = "2022/12.rs"
[[bench]]
name = "2022_12"
path = "2022/12.rs"
harness = false
[[bin]]
name = "2022_13"
path = "2022/13.rs"
[[bench]]
name = "2022_13"
path = "2022/13.rs"
harness = false
[[bin]]
name = "2022_14"
path = "2022/14.rs"
[[bench]]
name = "2022_14"
path = "2022/14.rs"
harness = false
[[bin]]
name = "2022_15"
path = "2022/15.rs"
[[bench]]
name = "2022_15"
path = "2022/15.rs"
harness = false
[[bin]]
name = "2022_16"
path = "2022/16.rs"
[[bench]]
name = "2022_16"
path = "2022/16.rs"
harness = false
[[bin]]
name = "2022_17"
path = "2022/17.rs"
[[bench]]
name = "2022_17"
path = "2022/17.rs"
harness = false
[[bin]]
name = "2022_18"
path = "2022/18.rs"
[[bench]]
name = "2022_18"
path = "2022/18.rs"
harness = false

View file

@ -1,11 +1,14 @@
#![feature(test)]
use std::collections::HashSet;
fn get_input() -> Vec<i32> {
let puzzle = include_str!("01.txt");
puzzle.lines().map(|i| i.parse().unwrap()).collect()
type Input = Vec<i32>;
fn setup(input: &str) -> Input {
input.lines().map(|i| i.parse().unwrap()).collect()
}
fn part1(input: &Vec<i32>) -> i32 {
fn part1(input: &Input) -> i32 {
let mut seen: HashSet<i32> = HashSet::new();
for &x in input {
let y = 2020 - x;
@ -17,10 +20,10 @@ fn part1(input: &Vec<i32>) -> i32 {
panic!();
}
fn part2(input: &Vec<i32>) -> i32 {
fn part2(input: &Input) -> i32 {
for (i, &x) in input.iter().enumerate() {
let mut seen: HashSet<i32> = HashSet::new();
for &y in &input[i+1..] {
for &y in &input[i + 1..] {
let z = 2020 - x - y;
if seen.contains(&z) {
return x * y * z;
@ -31,8 +34,4 @@ fn part2(input: &Vec<i32>) -> i32 {
panic!();
}
fn main() {
let input = get_input();
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
aoc::main!(2020, 1, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use regex::Regex;
struct Policy {
@ -8,11 +10,10 @@ struct Policy {
type Input = Vec<(Policy, String)>;
fn get_input() -> Input {
let puzzle = include_str!("02.txt");
fn setup(input: &str) -> Input {
let mut out: Input = Vec::new();
let regex = Regex::new(r"^(\d+)-(\d+) (.): (\w+)$").unwrap();
for line in puzzle.lines() {
for line in input.lines() {
let result = regex.captures(line).unwrap();
let a = result[1].parse::<u32>().unwrap();
let b = result[2].parse::<u32>().unwrap();
@ -20,7 +21,7 @@ fn get_input() -> Input {
let password = result[4].to_string();
out.push((Policy { a, b, c }, password));
}
return out;
out
}
fn part1(input: &Input) -> String {
@ -31,7 +32,7 @@ fn part1(input: &Input) -> String {
out += 1;
}
}
return out.to_string();
out.to_string()
}
fn part2(input: &Input) -> String {
@ -43,11 +44,7 @@ fn part2(input: &Input) -> String {
out += 1;
}
}
return out.to_string();
out.to_string()
}
fn main() {
let input = get_input();
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
aoc::main!(2020, 2, ex: 1);

View file

@ -1,8 +1,9 @@
#![feature(test)]
type Input = Vec<String>;
fn get_input() -> Input {
let puzzle = include_str!("03.txt");
return puzzle.lines().map(|s| s.to_string()).collect();
fn setup(input: &str) -> Input {
input.lines().map(|s| s.to_string()).collect()
}
fn cnt_slope(input: &Input, dx: u64, dy: u64) -> u64 {
@ -24,11 +25,11 @@ fn part1(input: &Input) -> String {
}
fn part2(input: &Input) -> String {
[(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)].iter().map(|&(dx, dy)| cnt_slope(input, dx, dy)).product::<u64>().to_string()
[(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
.iter()
.map(|&(dx, dy)| cnt_slope(input, dx, dy))
.product::<u64>()
.to_string()
}
fn main() {
let input = get_input();
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
aoc::main!(2020, 3, ex: 1);

View file

@ -1,17 +1,18 @@
#![feature(test)]
use std::collections::HashMap;
use regex::Regex;
type Input = Vec<HashMap<String, String>>;
fn get_input() -> Input {
let puzzle = include_str!("04.txt");
fn setup(input: &str) -> Input {
let mut out = Vec::new();
for block in puzzle.split("\n\n") {
for block in input.split("\n\n") {
let mut cur = HashMap::new();
for line in block.trim().lines() {
for (key, value) in line.split(" ").map(|a| {
let mut x = a.trim().split(":");
for (key, value) in line.split(' ').map(|a| {
let mut x = a.trim().split(':');
(x.next().unwrap(), x.next().unwrap())
}) {
cur.insert(key.to_string(), value.to_string());
@ -25,25 +26,30 @@ fn get_input() -> Input {
fn part1(input: &Input) -> String {
let mut out = 0;
for passport in input {
if ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"].iter().all(|x| passport.contains_key(&x.to_string())) {
if ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
.iter()
.all(|x| passport.contains_key(&x.to_string()))
{
out += 1;
}
}
out.to_string()
}
const RULES: [(&str, fn(&String) -> bool); 7] = [
type Rule = (&'static str, fn(&String) -> bool);
const RULES: [Rule; 7] = [
("byr", |x: &String| {
let num: i32 = x.parse().unwrap();
num >= 1920 && num <= 2002
(1920..=2002).contains(&num)
}),
("iyr", |x: &String| {
let num: i32 = x.parse().unwrap();
num >= 2010 && num <= 2020
(2010..=2020).contains(&num)
}),
("eyr", |x: &String| {
let num: i32 = x.parse().unwrap();
num >= 2020 && num <= 2030
(2020..=2030).contains(&num)
}),
("hgt", |x: &String| {
let regex = Regex::new(r"^(\d+)(cm|in)$").unwrap();
@ -52,9 +58,9 @@ const RULES: [(&str, fn(&String) -> bool); 7] = [
Some(result) => {
let num: i32 = result[1].parse().unwrap();
match &result[2] {
"cm" => num >= 150 && num <= 193,
"in" => num >= 59 && num <= 76,
_ => false
"cm" => (150..=193).contains(&num),
"in" => (59..=76).contains(&num),
_ => false,
}
}
}
@ -69,26 +75,23 @@ const RULES: [(&str, fn(&String) -> bool); 7] = [
("pid", |x: &String| {
let regex = Regex::new(r"^\d{9}$").unwrap();
regex.captures(x).is_some()
})
}),
];
fn part2(input: &Input) -> String {
let mut out = 0;
for passport in input {
if RULES.iter().all(|(key, validator)| {
match passport.get(&key.to_string()) {
if RULES
.iter()
.all(|(key, validator)| match passport.get(&key.to_string()) {
None => false,
Some(value) => validator(value)
}
}) {
Some(value) => validator(value),
})
{
out += 1;
}
}
out.to_string()
}
fn main() {
let input = get_input();
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
aoc::main!(2020, 4, ex: 1[a]);

27
Rust/2021/01.rs Normal file
View file

@ -0,0 +1,27 @@
#![feature(test)]
type Input = Vec<i32>;
fn setup(input: &str) -> Input {
input.lines().map(|x| x.parse().unwrap()).collect()
}
fn count(input: &Input, window: usize) -> i32 {
let mut out = 0;
for (a, b) in input.iter().zip(&input[window..]) {
if b > a {
out += 1;
}
}
out
}
fn part1(input: &Input) -> String {
count(input, 1).to_string()
}
fn part2(input: &Input) -> String {
count(input, 3).to_string()
}
aoc::main!(2021, 1, ex: 1);

58
Rust/2021/02.rs Normal file
View file

@ -0,0 +1,58 @@
#![feature(test)]
enum Command {
Forward(i32),
Down(i32),
Up(i32),
}
type Input = Vec<Command>;
fn setup(input: &str) -> Input {
input
.lines()
.map(|line| {
let mut x = line.split(' ');
let cmd = x.next().unwrap();
let n: i32 = x.next().unwrap().parse().unwrap();
match cmd {
"forward" => Command::Forward(n),
"up" => Command::Up(n),
"down" => Command::Down(n),
_ => panic!(),
}
})
.collect()
}
fn part1(input: &Input) -> String {
let mut d = 0;
let mut h = 0;
for cmd in input {
match cmd {
Command::Forward(n) => h += n,
Command::Down(n) => d += n,
Command::Up(n) => d -= n,
}
}
(d * h).to_string()
}
fn part2(input: &Input) -> String {
let mut d = 0;
let mut h = 0;
let mut a = 0;
for cmd in input {
match cmd {
Command::Forward(n) => {
h += n;
d += a * n;
}
Command::Down(n) => a += n,
Command::Up(n) => a -= n,
}
}
(d * h).to_string()
}
aoc::main!(2021, 2, ex: 1);

54
Rust/2021/03.rs Normal file
View file

@ -0,0 +1,54 @@
#![feature(test, extract_if)]
type Input = Vec<String>;
fn setup(input: &str) -> Input {
input.lines().map(|s| s.to_string()).collect()
}
fn count(input: &Input, i: usize, chr: &char) -> usize {
input
.iter()
.filter(|s| s.chars().nth(i).unwrap() == *chr)
.count()
}
fn most_common(input: &Input, i: usize) -> char {
"01".chars().max_by_key(|c| count(input, i, c)).unwrap()
}
fn least_common(input: &Input, i: usize) -> char {
"01".chars().min_by_key(|c| count(input, i, c)).unwrap()
}
fn part1(input: &Input) -> String {
let mut most = 0;
let mut least = 0;
for i in 0..input[0].len() {
most = most << 1 | (most_common(input, i) as u32 - '0' as u32);
least = least << 1 | (least_common(input, i) as u32 - '0' as u32);
}
(most * least).to_string()
}
fn find(input: &Input, x: bool) -> isize {
let mut out = input.clone();
for i in 0..input[0].len() {
let mx = if x {
least_common(&out, i)
} else {
most_common(&out, i)
};
out.extract_if(|x| x.chars().nth(i).unwrap() != mx).count();
if out.len() == 1 {
return isize::from_str_radix(out[0].as_str(), 2).unwrap();
}
}
panic!();
}
fn part2(input: &Input) -> String {
(find(input, true) * find(input, false)).to_string()
}
aoc::main!(2021, 3, ex: 1);

110
Rust/2021/04.rs Normal file
View file

@ -0,0 +1,110 @@
#![feature(test)]
use rustc_hash::FxHashSet;
struct Input {
nums: Vec<i32>,
boards: Vec<Vec<Vec<i32>>>,
}
fn setup(input: &str) -> Input {
let nums = input
.lines()
.next()
.unwrap()
.split(',')
.map(|n| n.parse().unwrap())
.collect();
let boards = input
.split("\n\n")
.skip(1)
.map(|board| {
board
.lines()
.map(|line| {
line.split_whitespace()
.map(|n| n.parse().unwrap())
.collect()
})
.collect()
})
.collect();
Input { nums, boards }
}
struct State {
boards: Vec<Vec<Vec<i32>>>,
marked: FxHashSet<i32>,
}
impl State {
fn from_input(input: &Input) -> State {
State {
boards: input.boards.clone(),
marked: FxHashSet::default(),
}
}
fn mark(&mut self, num: i32) {
self.marked.insert(num);
}
fn check_board(&self, board: usize) -> bool {
let board = &self.boards[board];
for row in board {
if row.iter().all(|n| self.marked.contains(n)) {
return true;
}
}
for i in 0..board[0].len() {
if board.iter().all(|row| self.marked.contains(&row[i])) {
return true;
}
}
false
}
fn get_score(&self, board: usize) -> i32 {
self.boards[board]
.iter()
.flatten()
.filter(|n| !self.marked.contains(n))
.copied()
.reduce(|a, b| a + b)
.unwrap()
}
}
fn part1(input: &Input) -> String {
let mut state = State::from_input(input);
for num in &input.nums {
state.mark(*num);
for i in 0..state.boards.len() {
if state.check_board(i) {
return (num * state.get_score(i)).to_string();
}
}
}
panic!();
}
fn part2(input: &Input) -> String {
let mut state = State::from_input(input);
for num in &input.nums {
state.mark(*num);
let mut i = 0;
while i < state.boards.len() {
if !state.check_board(i) {
i += 1;
continue;
}
if state.boards.len() == 1 {
return (num * state.get_score(i)).to_string();
}
state.boards.remove(i);
}
}
panic!()
}
aoc::main!(2021, 4, ex: 1);

79
Rust/2021/05.rs Normal file
View file

@ -0,0 +1,79 @@
#![feature(test)]
use std::cmp::Ordering;
use regex::Regex;
use rustc_hash::FxHashMap;
type Line = (i32, i32, i32, i32);
type Input = Vec<Line>;
fn setup(input: &str) -> Input {
let regex = Regex::new(r"^(\d+),(\d+) -> (\d+),(\d+)$").unwrap();
input
.lines()
.map(|line| {
let capture = regex.captures(line).unwrap();
(
capture[1].parse().unwrap(),
capture[2].parse().unwrap(),
capture[3].parse().unwrap(),
capture[4].parse().unwrap(),
)
})
.collect()
}
fn iter_line(line: &Line) -> Vec<(i32, i32)> {
let (mut x, mut y, x2, y2) = line;
let mut result = vec![(x, y)];
while (x != *x2) || (y != *y2) {
match x.cmp(x2) {
Ordering::Less => x += 1,
Ordering::Greater => x -= 1,
_ => {}
}
match y.cmp(y2) {
Ordering::Less => y += 1,
Ordering::Greater => y -= 1,
_ => {}
}
result.push((x, y));
}
result
}
fn part1(input: &Input) -> String {
let mut counter = FxHashMap::default();
for line in input {
if (line.0 != line.2) && (line.1 != line.3) {
continue;
}
for (x, y) in iter_line(line) {
let cnt = *counter.entry((x, y)).or_insert(0) + 1;
counter.insert((x, y), cnt);
}
}
counter
.iter()
.filter(|&(_, &cnt)| cnt > 1)
.count()
.to_string()
}
fn part2(input: &Input) -> String {
let mut counter = FxHashMap::default();
for line in input {
for (x, y) in iter_line(line) {
let cnt = *counter.entry((x, y)).or_insert(0) + 1;
counter.insert((x, y), cnt);
}
}
counter
.iter()
.filter(|&(_, &cnt)| cnt > 1)
.count()
.to_string()
}
aoc::main!(2021, 5, ex: 1);

34
Rust/2021/06.rs Normal file
View file

@ -0,0 +1,34 @@
#![feature(test)]
type Input = Vec<i32>;
fn setup(input: &str) -> Input {
input
.trim()
.split(',')
.map(|x| x.parse().unwrap())
.collect()
}
fn solve(input: &Input, n: u32) -> String {
let mut counter = vec![0; 9];
for num in input {
counter[*num as usize] += 1;
}
for _ in 0..n {
let x = counter.remove(0);
counter.push(x);
counter[6] += x;
}
counter.iter().sum::<u64>().to_string()
}
fn part1(input: &Input) -> String {
solve(input, 80)
}
fn part2(input: &Input) -> String {
solve(input, 256)
}
aoc::main!(2021, 6, ex: 1);

37
Rust/2021/07.rs Normal file
View file

@ -0,0 +1,37 @@
#![feature(test)]
type Input = Vec<i32>;
fn setup(input: &str) -> Input {
input
.trim()
.split(',')
.map(|x| x.parse().unwrap())
.collect()
}
fn part1(input: &Input) -> String {
(0..=input.len())
.map(|pos| input.iter().map(|n| (pos as i32 - *n).abs()).sum::<i32>())
.min()
.unwrap()
.to_string()
}
fn part2(input: &Input) -> String {
(0..=input.len())
.map(|pos| {
input
.iter()
.map(|n| {
let x = (pos as i32 - *n).abs();
(x * (x + 1)) >> 1
})
.sum::<i32>()
})
.min()
.unwrap()
.to_string()
}
aoc::main!(2021, 7, ex: 1);

120
Rust/2021/08.rs Normal file
View file

@ -0,0 +1,120 @@
#![feature(test)]
use rustc_hash::{FxHashMap, FxHashSet};
struct Line {
patterns: Vec<String>,
output: Vec<String>,
}
type Input = Vec<Line>;
fn setup(input: &str) -> Input {
input
.lines()
.map(|line| {
let mut line = line.trim().split(" | ");
let mut parse = || {
line.next()
.unwrap()
.split(' ')
.map(|x| x.to_string())
.collect()
};
Line {
patterns: parse(),
output: parse(),
}
})
.collect()
}
fn part1(input: &Input) -> String {
input
.iter()
.map(|line| {
line.output
.iter()
.filter(|x| [2, 3, 4, 7].contains(&x.len()))
.count()
})
.sum::<usize>()
.to_string()
}
fn parse_num(num: &str) -> u16 {
num.chars()
.map(|c| 1 << ((c as u16) - ('a' as u16)))
.sum::<u16>()
}
fn is_subset(mut a: u16, mut b: u16) -> bool {
while a > 0 {
if 1 & a & !b == 1 {
return false;
}
a >>= 1;
b >>= 1;
}
true
}
fn part2(input: &Input) -> String {
let digits = FxHashMap::from_iter([
((7, 2), 1),
((2, 5), 2),
((3, 5), 3),
((3, 4), 4),
((4, 5), 5),
((5, 3), 7),
((1, 7), 8),
]);
input
.iter()
.map(|line| {
let patterns: Vec<u16> = line.patterns.iter().map(|s| parse_num(s)).collect();
let output: Vec<u16> = line.output.iter().map(|s| parse_num(s)).collect();
let mut mp: FxHashMap<u16, u8> = FxHashMap::default();
let mut rp: FxHashMap<u8, u16> = FxHashMap::default();
let mut u: FxHashSet<u16> = FxHashSet::from_iter(patterns.iter().cloned());
for x in &patterns {
let sc = patterns.iter().filter(|y| is_subset(*x, **y)).count();
match digits.get(&(sc, x.count_ones())) {
None => {}
Some(digit) => {
mp.insert(*x, *digit);
rp.insert(*digit, *x);
u.remove(x);
}
}
}
let x = *u
.iter()
.find(|x| !is_subset(*rp.get(&5).unwrap(), **x))
.unwrap();
mp.insert(x, 0);
u.remove(&x);
let x = *u
.iter()
.find(|x| is_subset(*rp.get(&4).unwrap(), **x))
.unwrap();
mp.insert(x, 9);
u.remove(&x);
let x = *u.iter().next().unwrap();
mp.insert(x, 6);
output
.iter()
.map(|x| *mp.get(x).unwrap() as u32)
.reduce(|a, b| a * 10 + b)
.unwrap()
})
.sum::<u32>()
.to_string()
}
aoc::main!(2021, 8, ex: 1[b], 2);

View file

@ -4,29 +4,32 @@
extern crate test;
use std::collections::{BinaryHeap, VecDeque};
use std::fs;
use test::Bencher;
use rustc_hash::FxHashSet;
type Input = Vec<Vec<u32>>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/09.txt").unwrap();
puzzle.trim().lines().map(|line| {
line.trim().chars().map(|c| (c as u32) - 48).collect()
}).collect()
fn setup(input: &str) -> Input {
input
.trim()
.lines()
.map(|line| line.trim().chars().map(|c| (c as u32) - 48).collect())
.collect()
}
fn get_neighbors(i: i32, j: i32, w: i32, h: i32) -> impl Iterator<Item=(i32, i32)> {
[(-1, 0), (1, 0), (0, -1), (0, 1)].iter().cloned().filter_map(move |(dx, dy)| {
let x = j + dx;
let y = i + dy;
if x >= 0 && y >= 0 && x < w && y < h {
Option::Some((x, y))
} else {
Option::None
}
})
fn get_neighbors(i: i32, j: i32, w: i32, h: i32) -> impl Iterator<Item = (i32, i32)> {
[(-1, 0), (1, 0), (0, -1), (0, 1)]
.iter()
.cloned()
.filter_map(move |(dx, dy)| {
let x = j + dx;
let y = i + dy;
if x >= 0 && y >= 0 && x < w && y < h {
Option::Some((x, y))
} else {
Option::None
}
})
}
fn part1(input: &Input) -> String {
@ -34,7 +37,8 @@ fn part1(input: &Input) -> String {
for (i, line) in input.iter().enumerate() {
for (j, c) in line.iter().enumerate() {
if get_neighbors(i as i32, j as i32, line.len() as i32, input.len() as i32)
.all(|(p, q)| c < &input[q as usize][p as usize].clone()) {
.all(|(p, q)| c < &input[q as usize][p as usize].clone())
{
out += c + 1;
}
}
@ -47,18 +51,25 @@ fn part2(input: &Input) -> String {
for (i, line) in input.iter().enumerate() {
for (j, c) in line.iter().enumerate() {
if get_neighbors(i as i32, j as i32, line.len() as i32, input.len() as i32)
.all(|(p, q)| c < &input[q as usize][p as usize].clone()) {
.all(|(p, q)| c < &input[q as usize][p as usize].clone())
{
let mut queue = VecDeque::from([(i, j)]);
let mut visited = FxHashSet::default();
while !queue.is_empty() {
let (y, x) = queue.pop_front().unwrap();
if input[y][x] == 9 { continue; }
if input[y][x] == 9 {
continue;
}
if visited.contains(&(y, x)) { continue; }
if visited.contains(&(y, x)) {
continue;
}
visited.insert((y, x));
for (p, q) in get_neighbors(y as i32, x as i32, line.len() as i32, input.len() as i32) {
for (p, q) in
get_neighbors(y as i32, x as i32, line.len() as i32, input.len() as i32)
{
queue.push_back((q as usize, p as usize));
}
}
@ -66,28 +77,11 @@ fn part2(input: &Input) -> String {
}
}
}
sizes.into_iter_sorted().take(3).product::<usize>().to_string()
sizes
.into_iter_sorted()
.take(3)
.product::<usize>()
.to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part1(&input) })
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| { part2(&input) })
}
aoc::main!(2021, 9, ex: 1);

62
Rust/2021/10.rs Normal file
View file

@ -0,0 +1,62 @@
#![feature(test)]
type Input = Vec<String>;
fn setup(input: &str) -> Input {
input.lines().map(|s| s.to_string()).collect()
}
fn part1(input: &Input) -> String {
input
.iter()
.map(|line| {
let mut stack = Vec::new();
for c in line.chars() {
if "([{<".contains(c) {
stack.push(c);
} else {
let x = stack.pop().unwrap();
if !["()", "[]", "{}", "<>"].contains(&format!("{}{}", x, c).as_str()) {
return match c {
')' => 3,
']' => 57,
'}' => 1197,
'>' => 25137,
_ => panic!(),
};
}
}
}
0
})
.sum::<u32>()
.to_string()
}
fn part2(input: &Input) -> String {
let mut scores: Vec<usize> = input
.iter()
.filter_map(|line| {
let mut stack = Vec::new();
for c in line.chars() {
if "([{<".contains(c) {
stack.push(c);
} else {
let x = stack.pop().unwrap();
if !["()", "[]", "{}", "<>"].contains(&format!("{}{}", x, c).as_str()) {
return None;
}
}
}
let mut out = 0;
for c in stack.iter().rev() {
out = out * 5 + " ([{<".find(*c).unwrap();
}
Some(out)
})
.collect();
scores.sort();
scores[scores.len() / 2].to_string()
}
aoc::main!(2021, 10, ex: 1);

View file

@ -1,16 +1,14 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::FxHashSet;
type Input = Vec<Vec<u8>>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/11.txt").unwrap();
puzzle.lines().map(|line| line.chars().map(|c| (c as u8) - 48).collect()).collect()
fn setup(input: &str) -> Input {
input
.lines()
.map(|line| line.chars().map(|c| (c as u8) - 48).collect())
.collect()
}
fn flash(grid: &mut Input) -> usize {
@ -26,21 +24,27 @@ fn flash(grid: &mut Input) -> usize {
}
let mut visited: FxHashSet<(usize, usize)> = FxHashSet::default();
while !flashes.is_empty() {
let (i, j) = flashes.pop().unwrap();
if visited.contains(&(i, j)) { continue }
while let Some((i, j)) = flashes.pop() {
if visited.contains(&(i, j)) {
continue;
}
visited.insert((i, j));
grid[i][j] = 0;
for k in 0..9 {
if k == 4 {continue;}
if k == 4 {
continue;
}
let p = (i as i32) + k / 3 - 1;
let q = (j as i32) + k % 3 - 1;
if p < 0 || q < 0 {continue;}
if p < 0 || q < 0 {
continue;
}
let (p, q) = (p as usize, q as usize);
if p >= grid.len() || q >= grid[0].len() {continue;}
if p >= grid.len() || q >= grid[0].len() {
continue;
}
if grid[p][q] >= 9 {
flashes.push((p, q));
} else if !visited.contains(&(p, q)) {
@ -53,34 +57,19 @@ fn flash(grid: &mut Input) -> usize {
fn part1(input: &Input) -> String {
let mut grid = input.clone();
(0..100).map(|_| flash(&mut grid)).sum::<usize>().to_string()
(0..100)
.map(|_| flash(&mut grid))
.sum::<usize>()
.to_string()
}
fn part2(input: &Input) -> String {
let mut grid = input.clone();
let size = grid.len() * grid[0].len();
(1..).filter(|_| flash(&mut grid) == size).next().unwrap().to_string()
(1..)
.find(|_| flash(&mut grid) == size)
.unwrap()
.to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}
aoc::main!(2021, 11, ex: 1);

79
Rust/2021/12.rs Normal file
View file

@ -0,0 +1,79 @@
#![feature(test)]
use rustc_hash::{FxHashMap, FxHashSet};
type Input = FxHashMap<i32, Vec<i32>>;
fn setup(input: &str) -> Input {
let mut out = FxHashMap::default();
let mut map = FxHashMap::default();
map.insert("start", 0);
map.insert("end", 1);
for line in input.trim().lines() {
let mut split = line.split('-').map(|x| {
if !map.contains_key(x) {
map.insert(x, (map.len() as i32) * if x < "a" { 1 } else { -1 });
}
*map.get(x).unwrap()
});
let a = split.next().unwrap();
let b = split.next().unwrap();
match out.get_mut(&a) {
None => {
out.insert(a, vec![b]);
}
Some(x) => {
x.push(b);
}
}
match out.get_mut(&b) {
None => {
out.insert(b, vec![a]);
}
Some(x) => {
x.push(a);
}
}
}
out
}
fn search(node: i32, graph: &Input, visited: &mut FxHashSet<i32>, small_twice: bool) -> u32 {
if node == 1 {
return 1;
}
let mut twice = false;
if node <= 0 && visited.contains(&node) {
if small_twice || node == 0 {
return 0;
}
twice = true;
}
visited.insert(node);
let out = match graph.get(&node) {
None => 0,
Some(edges) => edges
.iter()
.cloned()
.map(|next| search(next, graph, visited, twice || small_twice))
.sum::<u32>(),
};
if !twice {
visited.remove(&node);
}
out
}
fn part1(input: &Input) -> String {
search(0, input, &mut FxHashSet::default(), true).to_string()
}
fn part2(input: &Input) -> String {
search(0, input, &mut FxHashSet::default(), false).to_string()
}
aoc::main!(2021, 12, ex: 1, 2, 3);

100
Rust/2021/13.rs Normal file
View file

@ -0,0 +1,100 @@
#![feature(test)]
use regex::Regex;
use rustc_hash::FxHashSet;
enum Instruction {
X(u32),
Y(u32),
}
struct Input {
dots: FxHashSet<(u32, u32)>,
instructions: Vec<Instruction>,
}
fn setup(input: &str) -> Input {
let mut blocks = input.split("\n\n");
let dots = blocks
.next()
.unwrap()
.lines()
.map(|line| {
let mut coords = line.split(',');
(
coords.next().unwrap().parse().unwrap(),
coords.next().unwrap().parse().unwrap(),
)
})
.collect();
let regex = Regex::new(r"^fold along (.)=(\d+)$").unwrap();
let instructions = blocks
.next()
.unwrap()
.lines()
.map(|line| {
let capture = regex.captures(line).unwrap();
let n: u32 = capture.get(2).unwrap().as_str().parse().unwrap();
match capture.get(1).unwrap().as_str() {
"x" => Instruction::X(n),
"y" => Instruction::Y(n),
_ => panic!(),
}
})
.collect();
Input { dots, instructions }
}
fn fold(dots: &FxHashSet<(u32, u32)>, instruction: &Instruction) -> FxHashSet<(u32, u32)> {
dots.iter()
.cloned()
.map(|(x, y)| match instruction {
Instruction::X(n) => (x.min(2 * n - x), y),
Instruction::Y(n) => (x, y.min(2 * n - y)),
})
.collect()
}
fn part1(input: &Input) -> String {
let mut dots = input.dots.clone();
let instruction = input.instructions.first().unwrap();
dots = fold(&dots, instruction);
dots.len().to_string()
}
fn part2(input: &Input) -> String {
let mut dots = input.dots.clone();
for instruction in &input.instructions {
dots = fold(&dots, instruction);
}
(0..8)
.map(|n| {
let k = (5 * n..5 * n + 4)
.flat_map(|i| {
let dots = &dots;
(0..6).map(move |j| dots.contains(&(i, j)))
})
.fold(0, |acc, x| (acc << 1) | (x as i32));
match k {
0b011111100100100100011111 => 'A',
0b111111101001101001010110 => 'B',
0b011110100001100001010010 => 'C',
0b111111101001101001100001 => 'E',
0b111111101000101000100000 => 'F',
0b011110100001100101010111 => 'G',
0b111111001000001000111111 => 'H',
0b000010000001100001111111 => 'J',
0b111111001000010110100001 => 'K',
0b111111000001000001000001 => 'L',
0b111111100100100100011000 => 'P',
0b111111100100100110011001 => 'R',
0b111110000001000001111110 => 'U',
0b100011100101101001110001 => 'Z',
_ => '?',
}
})
.collect::<String>()
}
aoc::main!(2021, 13, ex: 1[a]);

View file

@ -1,10 +1,5 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use counter::Counter;
use regex::Regex;
use rustc_hash::FxHashMap;
@ -14,23 +9,28 @@ struct Input {
rules: FxHashMap<(char, char), char>,
}
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/14.txt").unwrap();
let mut lines = puzzle.lines();
fn setup(input: &str) -> Input {
let mut lines = input.lines();
let template = lines.next().unwrap().to_string();
lines.next();
let regex = Regex::new(r"^([A-Z])([A-Z]) -> ([A-Z])$").unwrap();
let rules = lines.map(|line| {
let capture = regex.captures(line).unwrap();
let get = |i| capture.get(i).unwrap().as_str().chars().next().unwrap();
((get(1), get(2)), get(3))
}).collect();
let rules = lines
.map(|line| {
let capture = regex.captures(line).unwrap();
let get = |i| capture.get(i).unwrap().as_str().chars().next().unwrap();
((get(1), get(2)), get(3))
})
.collect();
Input { template, rules }
}
fn solve(input: &Input, n: usize) -> usize {
let mut adj: Counter<(char, char)> = input.template.chars().zip(input.template[1..].chars()).collect();
let mut adj: Counter<(char, char)> = input
.template
.chars()
.zip(input.template[1..].chars())
.collect();
for _ in 0..n {
let mut new: Counter<(char, char)> = Counter::new();
for ((a, b), c) in adj.iter().map(|((a, b), c)| ((*a, *b), *c)) {
@ -62,25 +62,4 @@ fn part2(input: &Input) -> String {
solve(input, 40).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}
aoc::main!(2021, 14, ex: 1);

63
Rust/2021/15.rs Normal file
View file

@ -0,0 +1,63 @@
#![feature(test)]
use std::{cmp::Reverse, collections::BinaryHeap};
use rustc_hash::FxHashSet;
type Input = Vec<Vec<u32>>;
fn setup(input: &str) -> Input {
input
.lines()
.map(|line| line.chars().map(|c| (c as u32) - 0x30).collect())
.collect()
}
fn dijkstra(grid: &Input, k: usize) -> u32 {
let w = grid[0].len();
let h = grid.len();
let mut queue = BinaryHeap::new();
queue.push(Reverse((0u32, 0usize, 0usize)));
let mut visited = FxHashSet::default();
while !queue.is_empty() {
let (d, x, y) = queue.pop().unwrap().0;
if visited.contains(&(x, y)) {
continue;
}
visited.insert((x, y));
if x == w * k - 1 && y == h * k - 1 {
return d;
}
for (dx, dy) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let p = (x as i32) + dx;
let q = (y as i32) + dy;
if p < 0 || q < 0 {
continue;
}
let p = p as usize;
let q = q as usize;
if p >= k * w || q >= k * h {
continue;
}
if visited.contains(&(p, q)) {
continue;
}
let c = grid[q % h][p % w] + (q / h + p / w) as u32;
queue.push(Reverse((d + (c - 1) % 9 + 1, p, q)));
}
}
panic!();
}
fn part1(input: &Input) -> String {
dijkstra(input, 1).to_string()
}
fn part2(input: &Input) -> String {
dijkstra(input, 5).to_string()
}
aoc::main!(2021, 15, ex: 1);

View file

@ -1,36 +1,38 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<bool>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/16.txt").unwrap();
puzzle.trim().chars().flat_map(|c| {
let n = "0123456789ABCDEF".find(c).unwrap();
(0..4).rev().map(move |i| n & (1 << i) > 0)
}).collect()
fn setup(input: &str) -> Input {
input
.trim()
.chars()
.flat_map(|c| {
let n = "0123456789ABCDEF".find(c).unwrap();
(0..4).rev().map(move |i| n & (1 << i) > 0)
})
.collect()
}
struct Reader {
data: Vec<bool>,
struct Reader<'a> {
data: &'a [bool],
pos: usize,
}
impl Reader {
fn new(data: Vec<bool>) -> Reader {
impl<'a> Reader<'a> {
fn new(data: &'a [bool]) -> Self {
Reader { data, pos: 0 }
}
fn read(&mut self, n: usize) -> u64 {
let mut out = 0;
for _ in 0..n {
if self.pos >= self.data.len() { break; }
if self.pos >= self.data.len() {
break;
}
out <<= 1;
if self.data[self.pos] { out |= 1; }
if self.data[self.pos] {
out |= 1;
}
self.pos += 1;
}
out
@ -51,9 +53,14 @@ fn solve(io: &mut Reader) -> Result {
let c = io.read(1);
lit <<= 4;
lit |= io.read(4);
if c == 0 { break; }
if c == 0 {
break;
}
}
return Result { version_sum: version, value: lit };
return Result {
version_sum: version,
value: lit,
};
}
let mut values = vec![];
@ -82,25 +89,19 @@ fn solve(io: &mut Reader) -> Result {
5 => (values[0] > values[1]) as u64,
6 => (values[0] < values[1]) as u64,
7 => (values[0] == values[1]) as u64,
_ => panic!()
_ => panic!(),
},
}
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
fn part1(input: &Input) -> u64 {
let mut reader = Reader::new(input);
solve(&mut reader).version_sum
}
pub fn run() -> (String, String) {
let input = get_input();
let result = solve(&mut Reader::new(input.clone()));
(result.version_sum.to_string(), result.value.to_string())
fn part2(input: &Input) -> u64 {
let mut reader = Reader::new(input);
solve(&mut reader).value
}
#[bench]
fn bench_solution(b: &mut Bencher) {
let input = get_input();
b.iter(|| solve(&mut Reader::new(input.clone())))
}
aoc::main!(2021, 16, ex: "1a"[a], "2a"[a], "3a"[a], "4a"[a], "1b"[b], "2b"[b], "3b"[b], "4b"[b], "5b"[b], "6b"[b], "7b"[b], "8b"[b]);

View file

@ -1,9 +1,5 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use regex::Regex;
use rustc_hash::{FxHashMap, FxHashSet};
@ -14,10 +10,9 @@ struct Input {
y2: i32,
}
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/17.txt").unwrap();
fn setup(input: &str) -> Input {
let regex = Regex::new(r"^target area: x=(-?\d+)..(-?\d+), y=(-?\d+)..(-?\d+)$").unwrap();
let capture = regex.captures(puzzle.trim()).unwrap();
let capture = regex.captures(input.trim()).unwrap();
let get = |i| capture.get(i).unwrap().as_str().parse().unwrap();
Input {
x1: get(1),
@ -38,7 +33,7 @@ fn solve(input: &Input) -> (i32, usize) {
while y >= input.y1 {
if y <= input.y2 {
if !ok.contains_key(&t) {ok.insert(t, (0, FxHashSet::default()));}
ok.entry(t).or_insert_with(|| (0, FxHashSet::default()));
let (my, vys) = ok.get_mut(&t).unwrap();
*my = maxy.max(*my);
vys.insert(ovy);
@ -77,20 +72,12 @@ fn solve(input: &Input) -> (i32, usize) {
(outa, outb)
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
fn part1(input: &Input) -> i32 {
solve(input).0
}
pub fn run() -> (String, String) {
let input = get_input();
let (part1, part2) = solve(&input);
(part1.to_string(), part2.to_string())
fn part2(input: &Input) -> usize {
solve(input).1
}
#[bench]
fn bench(b: &mut Bencher) {
let input = get_input();
b.iter(|| solve(&input))
}
aoc::main!(2021, 17, ex: 1);

153
Rust/2021/18.rs Normal file
View file

@ -0,0 +1,153 @@
#![feature(test)]
type Number = [Option<u32>; 64];
type Input = Vec<Number>;
fn parent(n: usize) -> usize {
n >> 1
}
fn left(n: usize) -> usize {
n << 1
}
fn right(n: usize) -> usize {
n << 1 | 1
}
fn setup(input: &str) -> Input {
input
.trim()
.lines()
.map(|line| {
let mut out = [Option::None; 64];
let mut acc = Option::None;
let mut n = 1;
for c in line.trim().chars() {
let digit = (c as i32) - 0x30;
if (0..=9).contains(&digit) {
acc = Option::Some(acc.unwrap_or(0) * 10 + (digit as u32));
continue;
}
let mut write = |x| {
if acc.is_some() {
out[n] = acc;
}
acc = Option::None;
x
};
n = match c {
'[' => left(n),
',' => write(n + 1),
']' => write(parent(n)),
_ => panic!(),
}
}
out
})
.collect()
}
fn move_up(lst: &mut Number, i: usize, x: u32) {
match lst[i] {
None => {
move_up(lst, parent(i), x);
}
Some(y) => {
lst[i] = Some(x + y);
}
}
}
fn explode(lst: &mut Number) -> bool {
for n in (1 << 4)..(1 << 5) {
if lst[n].is_some() {
continue;
}
let a = left(n);
let b = right(n);
if let (Option::Some(l), Option::Some(r)) = (lst[a], lst[b]) {
lst[a] = Option::None;
lst[b] = Option::None;
lst[n] = Option::Some(0);
if a > 1 << 5 {
move_up(lst, a - 1, l);
}
if b + 1 < 1 << 6 {
move_up(lst, b + 1, r);
}
return true;
}
}
false
}
fn split(lst: &mut Number, n: usize) -> bool {
if let Option::Some(x) = lst[n] {
if x < 10 {
return false;
}
let k = x >> 1;
lst[n] = Option::None;
lst[left(n)] = Option::Some(k);
lst[right(n)] = Option::Some(x - k);
return true;
}
split(lst, left(n)) || split(lst, right(n))
}
fn add(a: &Number, b: &Number) -> Number {
let mut out = [Option::None; 64];
let mut j = 2;
for i in 0..=4 {
((1 << i)..(1 << (i + 1))).for_each(|k| {
out[j] = a[k];
j += 1;
});
((1 << i)..(1 << (i + 1))).for_each(|k| {
out[j] = b[k];
j += 1;
});
}
while explode(&mut out) || split(&mut out, 1) {}
out
}
fn magnitude(lst: &Number, n: usize) -> u32 {
if let Some(x) = lst[n] {
x
} else {
3 * magnitude(lst, left(n)) + 2 * magnitude(lst, right(n))
}
}
fn part1(input: &Input) -> String {
magnitude(
&input.iter().cloned().reduce(|a, b| add(&a, &b)).unwrap(),
1,
)
.to_string()
}
fn part2(input: &Input) -> String {
input
.iter()
.flat_map(|a| {
input.iter().filter_map(move |b| {
if a == b {
Option::None
} else {
Option::Some(magnitude(&add(a, b), 1))
}
})
})
.max()
.unwrap()
.to_string()
}
aoc::main!(2021, 18, ex: 1);

View file

@ -1,11 +1,10 @@
#![feature(test)]
extern crate test;
use std::{
hash::Hash,
ops::{Add, Sub},
};
use std::fs;
use std::hash::Hash;
use std::ops::{Add, Sub};
use test::Bencher;
use rustc_hash::{FxHashMap, FxHashSet};
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
@ -24,7 +23,11 @@ impl Pos {
2 => Pos { x, y: -y, z: -z },
3 => Pos { x, y: z, z: -y },
4 => Pos { x: -x, y: -y, z },
5 => Pos { x: -x, y: -z, z: -y },
5 => Pos {
x: -x,
y: -z,
z: -y,
},
6 => Pos { x: -x, y, z: -z },
7 => Pos { x: -x, y: z, z: y },
8 => Pos { x: y, y: -x, z },
@ -33,7 +36,11 @@ impl Pos {
11 => Pos { x: y, y: z, z: x },
12 => Pos { x: -y, y: x, z },
13 => Pos { x: -y, y: -z, z: x },
14 => Pos { x: -y, y: -x, z: -z },
14 => Pos {
x: -y,
y: -x,
z: -z,
},
15 => Pos { x: -y, y: z, z: -x },
16 => Pos { x: z, y: -y, z: x },
17 => Pos { x: z, y: -x, z: -y },
@ -41,9 +48,13 @@ impl Pos {
19 => Pos { x: z, y: x, z: y },
20 => Pos { x: -z, y, z: x },
21 => Pos { x: -z, y: -x, z: y },
22 => Pos { x: -z, y: -y, z: -x },
22 => Pos {
x: -z,
y: -y,
z: -x,
},
23 => Pos { x: -z, y: x, z: -y },
_ => panic!()
_ => panic!(),
}
}
@ -62,7 +73,11 @@ impl Add for Pos {
type Output = Pos;
fn add(self, rhs: Self) -> Self::Output {
Pos { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
Pos {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
@ -70,28 +85,47 @@ impl Sub for Pos {
type Output = Pos;
fn sub(self, rhs: Self) -> Self::Output {
Pos { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z }
Pos {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
type Scanner = (Vec<Pos>, FxHashSet<i32>);
type Input = Vec<Scanner>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/19.txt").unwrap();
puzzle.split("\n\n").map(|scanner| {
let poss: Vec<Pos> = scanner.lines().skip(1).map(|line| {
let mut res = line.split(",").map(|x| x.parse().unwrap());
Pos { x: res.next().unwrap(), y: res.next().unwrap(), z: res.next().unwrap() }
}).collect();
let distances: FxHashSet<i32> = poss.iter().flat_map(|a| {
poss.iter().map(|b| a.distance(*b))
}).collect();
(poss, distances)
}).collect()
fn setup(input: &str) -> Input {
input
.split("\n\n")
.map(|scanner| {
let poss: Vec<Pos> = scanner
.lines()
.skip(1)
.map(|line| {
let mut res = line.split(',').map(|x| x.parse().unwrap());
Pos {
x: res.next().unwrap(),
y: res.next().unwrap(),
z: res.next().unwrap(),
}
})
.collect();
let distances: FxHashSet<i32> = poss
.iter()
.flat_map(|a| poss.iter().map(|b| a.distance(*b)))
.collect();
(poss, distances)
})
.collect()
}
fn match_scanner(beacons: &mut FxHashSet<Pos>, scanner_positions: &mut Vec<Pos>, scanner: &Scanner) {
fn match_scanner(
beacons: &mut FxHashSet<Pos>,
scanner_positions: &mut Vec<Pos>,
scanner: &Scanner,
) {
for i in 0..24 {
let mut counter: FxHashMap<Pos, usize> = FxHashMap::default();
for rel in &scanner.0 {
@ -114,15 +148,15 @@ fn match_scanner(beacons: &mut FxHashSet<Pos>, scanner_positions: &mut Vec<Pos>,
}
fn solve(input: &Input) -> (usize, i32) {
let mut remaining: Vec<Scanner> = input.iter().cloned().collect();
let mut remaining: Vec<Scanner> = input.to_vec();
let first = remaining.remove(0);
let mut beacons: FxHashSet<Pos> = FxHashSet::from_iter(first.0);
let mut distances: FxHashSet<i32> = FxHashSet::from_iter(first.1);
let mut scanners: Vec<Pos> = vec![];
while !remaining.is_empty() {
let i = (0..remaining.len()).max_by_key(|&i| {
remaining[i].1.intersection(&distances).count()
}).unwrap();
let i = (0..remaining.len())
.max_by_key(|&i| remaining[i].1.intersection(&distances).count())
.unwrap();
let s = remaining.remove(i);
match_scanner(&mut beacons, &mut scanners, &s);
@ -130,25 +164,22 @@ fn solve(input: &Input) -> (usize, i32) {
distances.insert(*x);
}
}
(beacons.len(), scanners.iter().flat_map(|x| {
scanners.iter().map(|&y| { x.manhatten_distance(y) })
}).max().unwrap())
(
beacons.len(),
scanners
.iter()
.flat_map(|x| scanners.iter().map(|&y| x.manhatten_distance(y)))
.max()
.unwrap(),
)
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
fn part1(input: &Input) -> usize {
solve(input).0
}
pub fn run() -> (String, String) {
let input = get_input();
let (part1, part2) = solve(&input);
(part1.to_string(), part2.to_string())
fn part2(input: &Input) -> i32 {
solve(input).1
}
#[bench]
fn bench(b: &mut Bencher) {
let input = get_input();
b.iter(|| solve(&input))
}
aoc::main!(2021, 19, ex: 1);

77
Rust/2021/20.rs Normal file
View file

@ -0,0 +1,77 @@
#![feature(test)]
use rustc_hash::FxHashSet;
struct Input {
algo: Vec<bool>,
width: usize,
height: usize,
grid: FxHashSet<(i32, i32)>,
}
fn setup(input: &str) -> Input {
let mut lines = input.lines();
let algo = lines.next().unwrap().chars().map(|c| c == '#').collect();
let grid = lines
.skip(1)
.enumerate()
.flat_map(|(i, line)| {
line.chars().enumerate().filter_map(move |(j, c)| {
if c == '#' {
Option::Some((j as i32, i as i32))
} else {
Option::None
}
})
})
.collect();
Input {
algo,
grid,
width: input.lines().nth(2).unwrap().len(),
height: input.lines().count() - 2,
}
}
fn get_neighbors(x: i32, y: i32) -> Vec<(i32, i32)> {
(-1..=1)
.flat_map(|dy| (-1..=1).map(move |dx| (x + dx, y + dy)))
.collect()
}
fn solve(input: &Input) -> (usize, usize) {
let mut grid = input.grid.clone();
let mut inf = false;
let mut part1 = 0;
let mut part2 = 0;
for i in 1..=50 {
let new_inf = inf != input.algo[0];
grid = (-i..=input.height as i32 + i)
.flat_map(|y| (-i..=input.width as i32 + i).map(move |x| (x, y)))
.filter(|(x, y)| {
let idx = get_neighbors(*x, *y).iter().fold(0, |acc, (p, q)| {
acc << 1 | (grid.contains(&(*p, *q)) != inf) as usize
});
input.algo[idx] != new_inf
})
.collect();
inf = new_inf;
if i == 2 {
part1 = grid.len();
}
if i == 50 {
part2 = grid.len();
}
}
(part1, part2)
}
fn part1(input: &Input) -> usize {
solve(input).0
}
fn part2(input: &Input) -> usize {
solve(input).1
}
aoc::main!(2021, 20, ex: 1);

View file

@ -1,18 +1,21 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
use rustc_hash::FxHashMap;
type Input = (u32, u32);
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/21.txt").unwrap();
let mut lines = puzzle.lines();
let mut next = || lines.next().unwrap().split(" ").last().unwrap().parse().unwrap();
fn setup(input: &str) -> Input {
let mut lines = input.lines();
let mut next = || {
lines
.next()
.unwrap()
.split(' ')
.last()
.unwrap()
.parse()
.unwrap()
};
(next(), next())
}
@ -40,7 +43,9 @@ struct State {
}
fn dirac(state: State, mem: &mut FxHashMap<State, (u64, u64)>) -> (u64, u64) {
if state.s2 >= 21 { return (0, 1); }
if state.s2 >= 21 {
return (0, 1);
}
match mem.get(&state) {
Some(&result) => result,
@ -48,7 +53,15 @@ fn dirac(state: State, mem: &mut FxHashMap<State, (u64, u64)>) -> (u64, u64) {
let result = (0u32..27).fold((0, 0), |acc, i| {
let x = i / 9 % 3 + i / 3 % 3 + i % 3 + 3;
let q = (state.p1 - 1 + x) % 10 + 1;
let res = dirac(State { p1: state.p2, p2: q, s1: state.s2, s2: state.s1 + q }, mem);
let res = dirac(
State {
p1: state.p2,
p2: q,
s1: state.s2,
s2: state.s1 + q,
},
mem,
);
(acc.0 + res.1, acc.1 + res.0)
});
@ -59,34 +72,16 @@ fn dirac(state: State, mem: &mut FxHashMap<State, (u64, u64)>) -> (u64, u64) {
}
fn part2(input: &Input) -> String {
let (a, b) = dirac(State {
p1: input.0,
p2: input.1,
s1: 0,
s2: 0,
}, &mut FxHashMap::default());
let (a, b) = dirac(
State {
p1: input.0,
p2: input.1,
s1: 0,
s2: 0,
},
&mut FxHashMap::default(),
);
a.max(b).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}
aoc::main!(2021, 21, ex: 1);

136
Rust/2021/22.rs Normal file
View file

@ -0,0 +1,136 @@
#![feature(test)]
use regex::Regex;
struct Cuboid {
x1: i64,
x2: i64,
y1: i64,
y2: i64,
z1: i64,
z2: i64,
off: Vec<Cuboid>,
}
fn line_intersection(a1: i64, a2: i64, b1: i64, b2: i64) -> Option<(i64, i64)> {
if a2 < b1 || b2 < a1 {
Option::None
} else {
Option::Some((a1.max(b1), a2.min(b2)))
}
}
impl Cuboid {
fn copy(&self) -> Cuboid {
Cuboid {
x1: self.x1,
x2: self.x2,
y1: self.y1,
y2: self.y2,
z1: self.z1,
z2: self.z2,
off: vec![],
}
}
fn get_intersection(&self, c: &Cuboid) -> Option<Cuboid> {
let x = line_intersection(self.x1, self.x2, c.x1, c.x2);
let y = line_intersection(self.y1, self.y2, c.y1, c.y2);
let z = line_intersection(self.z1, self.z2, c.z1, c.z2);
if let (Option::Some(x), Option::Some(y), Option::Some(z)) = (x, y, z) {
Option::Some(Cuboid {
x1: x.0,
x2: x.1,
y1: y.0,
y2: y.1,
z1: z.0,
z2: z.1,
off: vec![],
})
} else {
Option::None
}
}
fn subtract(&mut self, c: &Cuboid) {
if let Option::Some(intersection) = self.get_intersection(c) {
for o in self.off.iter_mut() {
o.subtract(c);
}
self.off.push(intersection);
}
}
fn volume(&self) -> i64 {
(self.x2 - self.x1 + 1) * (self.y2 - self.y1 + 1) * (self.z2 - self.z1 + 1)
- self.off.iter().map(|c| c.volume()).sum::<i64>()
}
}
struct Step {
on: bool,
cuboid: Cuboid,
}
type Input = Vec<Step>;
fn setup(input: &str) -> Input {
let regex =
Regex::new(r"^(on|off) x=(-?\d+)..(-?\d+),y=(-?\d+)..(-?\d+),z=(-?\d+)..(-?\d+)$").unwrap();
input
.lines()
.map(|line| {
let capture = regex.captures(line).unwrap();
let get_num = |i| capture.get(i).unwrap().as_str().parse().unwrap();
Step {
on: capture.get(1).unwrap().as_str() == "on",
cuboid: Cuboid {
x1: get_num(2),
x2: get_num(3),
y1: get_num(4),
y2: get_num(5),
z1: get_num(6),
z2: get_num(7),
off: vec![],
},
}
})
.collect()
}
fn part1(input: &Input) -> String {
let mut cuboids: Vec<Cuboid> = vec![];
for Step { on, cuboid } in input {
if cuboid.x1 < -50
|| cuboid.x2 > 50
|| cuboid.y1 < -50
|| cuboid.y2 > 50
|| cuboid.z1 < -50
|| cuboid.z2 > 50
{
continue;
}
for c in cuboids.iter_mut() {
c.subtract(cuboid);
}
if *on {
cuboids.push(cuboid.copy());
}
}
cuboids.iter().map(|c| c.volume()).sum::<i64>().to_string()
}
fn part2(input: &Input) -> String {
let mut cuboids: Vec<Cuboid> = vec![];
for Step { on, cuboid } in input {
for c in cuboids.iter_mut() {
c.subtract(cuboid);
}
if *on {
cuboids.push(cuboid.copy());
}
}
cuboids.iter().map(|c| c.volume()).sum::<i64>().to_string()
}
aoc::main!(2021, 22, ex: "1a"[a], "2a"[a], "1b"[b]);

View file

@ -1,24 +1,22 @@
#![feature(test)]
#![feature(int_abs_diff)]
extern crate test;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::fs;
use test::Bencher;
use std::{cmp::Reverse, collections::BinaryHeap};
use rustc_hash::FxHashSet;
type Input = [Vec<char>; 4];
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/23.txt").unwrap();
fn setup(input: &str) -> Input {
let mut out = [vec![], vec![], vec![], vec![]];
let lines: Vec<(char, char, char, char)> = puzzle.lines().skip(2).take(2).map(|line| {
let get = |i| line.chars().nth(3 + 2 * i as usize).unwrap();
(get(0), get(1), get(2), get(3))
}).collect();
let lines: Vec<(char, char, char, char)> = input
.lines()
.skip(2)
.take(2)
.map(|line| {
let get = |i| line.chars().nth(3 + 2 * i as usize).unwrap();
(get(0), get(1), get(2), get(3))
})
.collect();
for line in lines.iter().rev() {
out[0].push(line.0);
out[1].push(line.1);
@ -37,7 +35,7 @@ struct State {
impl State {
fn make_key(&self) -> ([Vec<char>; 4], [char; 11]) {
(self.rooms.clone(), self.hallway.clone())
(self.rooms.clone(), self.hallway)
}
fn check_room(&self, idx: usize) -> bool {
@ -46,11 +44,11 @@ impl State {
}
fn done(&self) -> bool {
self.hallway.iter().all(|&x| x == '.') && (0..4).all(|i| { self.check_room(i) })
self.hallway.iter().all(|&x| x == '.') && (0..4).all(|i| self.check_room(i))
}
fn check_hallway(&self, start: usize, end: usize) -> bool {
(start.min(end)..=end.max(start)).all(|i| { self.hallway[i] == '.' || i == start })
(start.min(end)..=end.max(start)).all(|i| self.hallway[i] == '.' || i == start)
}
fn add_cost(mut self, cost: u32) -> Self {
@ -75,14 +73,21 @@ impl State {
fn generate_moves(&self, n: usize) -> Vec<State> {
for (i, &c) in self.hallway.iter().enumerate() {
if c == '.' { continue; }
if c == '.' {
continue;
}
let dst = "ABCD".find(c).unwrap();
if self.rooms[dst].iter().any(|&x| x != c) { continue; }
if !self.check_hallway(i, 2 + 2 * dst) { continue; }
if self.rooms[dst].iter().any(|&x| x != c) {
continue;
}
if !self.check_hallway(i, 2 + 2 * dst) {
continue;
}
let dist = i.abs_diff(2 + 2 * dst) + n - self.rooms[dst].len();
return vec![self.clone()
return vec![self
.clone()
.add_cost(dist as u32 * 10u32.pow(dst as u32))
.push_room(dst, c)
.set_hallway(i, '.')];
@ -90,18 +95,24 @@ impl State {
let mut out = vec![];
for i in 0..4 {
if self.check_room(i) { continue; }
if self.check_room(i) {
continue;
}
let c = *self.rooms[i].last().unwrap();
let src = 2 + 2 * i;
let dst = "ABCD".find(c).unwrap();
for j in [0, 1, 3, 5, 7, 9, 10] {
if !self.check_hallway(src, j) {continue;}
if !self.check_hallway(src, j) {
continue;
}
let dist = (1 + n - self.rooms[i].len()) + src.abs_diff(j);
out.push(self.clone()
.add_cost(dist as u32 * 10u32.pow(dst as u32))
.pop_room(i)
.set_hallway(j, c))
out.push(
self.clone()
.add_cost(dist as u32 * 10u32.pow(dst as u32))
.pop_room(i)
.set_hallway(j, c),
)
}
}
out
@ -111,10 +122,10 @@ impl State {
fn solve(input: &Input, part2: bool) -> u32 {
let mut input = input.clone();
if part2 {
for i in 0..4 {
(0..4).for_each(|i| {
input[i].insert(1, "DBAC".chars().nth(i).unwrap());
input[i].insert(2, "DCBA".chars().nth(i).unwrap());
}
});
}
let n = input[0].len();
let mut queue = BinaryHeap::new();
@ -128,10 +139,14 @@ fn solve(input: &Input, part2: bool) -> u32 {
let state = queue.pop().unwrap().0;
let key = state.make_key();
if visited.contains(&key) { continue; }
if visited.contains(&key) {
continue;
}
visited.insert(key);
if state.done() { return state.energy; }
if state.done() {
return state.energy;
}
for next in state.generate_moves(n) {
queue.push(Reverse(next));
@ -148,25 +163,4 @@ fn part2(input: &Input) -> String {
solve(input, true).to_string()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}
aoc::main!(2021, 23, ex: 1);

View file

@ -1,19 +1,22 @@
#![feature(test)]
extern crate test;
use std::fs;
use test::Bencher;
type Input = Vec<(i8, i8)>;
fn get_input() -> Input {
let puzzle = fs::read_to_string("2021/24.txt").unwrap();
let lines: Vec<String> = puzzle.lines().map(|line| line.to_string()).collect();
(0..14).map(|i| {
let get = |j: usize| lines[i * 18 + j].split(" ").nth(2).unwrap().parse().unwrap();
(get(5), get(15))
}).collect()
fn setup(input: &str) -> Input {
let lines: Vec<String> = input.lines().map(|line| line.to_string()).collect();
(0..14)
.map(|i| {
let get = |j: usize| {
lines[i * 18 + j]
.split(' ')
.nth(2)
.unwrap()
.parse()
.unwrap()
};
(get(5), get(15))
})
.collect()
}
fn part1(input: &Input) -> String {
@ -54,25 +57,4 @@ fn part2(input: &Input) -> String {
out.iter().map(|&x| (x + 0x30) as char).collect()
}
fn main() {
let (part1, part2) = run();
println!("Part 1: {}", part1);
println!("Part 2: {}", part2);
}
pub fn run() -> (String, String) {
let input = get_input();
(part1(&input), part2(&input))
}
#[bench]
fn bench_part1(b: &mut Bencher) {
let input = get_input();
b.iter(|| part1(&input))
}
#[bench]
fn bench_part2(b: &mut Bencher) {
let input = get_input();
b.iter(|| part2(&input))
}
aoc::main!(2021, 24);

68
Rust/2021/25.rs Normal file
View file

@ -0,0 +1,68 @@
#![feature(test)]
#[derive(Copy, Clone, Eq, PartialEq)]
enum Type {
Empty,
Right,
Down,
}
type Input = Vec<Vec<Type>>;
fn setup(input: &str) -> Input {
input
.lines()
.map(|line| {
line.chars()
.map(|c| match c {
'v' => Type::Down,
'>' => Type::Right,
_ => Type::Empty,
})
.collect()
})
.collect()
}
fn part1(input: &Input) -> String {
let mut grid = input.clone();
let mut cnt = 0;
loop {
let mut moved = false;
let mut new_grid = grid.clone();
for (i, line) in grid.iter().enumerate() {
for (j, &c) in line.iter().enumerate() {
if c == Type::Right {
let k = (j + 1) % line.len();
if grid[i][k] == Type::Empty {
new_grid[i][k] = Type::Right;
new_grid[i][j] = Type::Empty;
moved = true;
}
}
}
}
grid = new_grid;
let mut new_grid = grid.clone();
for (i, line) in grid.iter().enumerate() {
for (j, &c) in line.iter().enumerate() {
if c == Type::Down {
let k = (i + 1) % grid.len();
if grid[k][j] == Type::Empty {
new_grid[k][j] = Type::Down;
new_grid[i][j] = Type::Empty;
moved = true;
}
}
}
}
grid = new_grid;
cnt += 1;
if !moved {
break;
}
}
cnt.to_string()
}
aoc::main!(2021, 25, ex: 1);

31
Rust/2022/01.rs Normal file
View file

@ -0,0 +1,31 @@
#![feature(test)]
use itertools::Itertools;
type Input = Vec<Vec<u32>>;
fn setup(input: &str) -> Input {
input
.split("\n\n")
.map(|block| {
block
.split_whitespace()
.map(|num| num.parse().unwrap())
.collect()
})
.collect()
}
fn part1(input: &Input) -> u32 {
input.iter().map(|block| block.iter().sum()).max().unwrap()
}
fn part2(input: &Input) -> u32 {
-input
.iter()
.map(|block| -(block.iter().sum::<u32>() as i32))
.k_smallest(3)
.sum::<i32>() as u32
}
aoc::main!(2022, 1, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
type Input = Vec<(u32, u32)>;
fn setup(input: &str) -> Input {
@ -21,6 +23,4 @@ fn part2(input: &Input) -> u32 {
input.iter().map(|(a, b)| (2 + a + b) % 3 + 1 + b * 3).sum()
}
aoc::main!(2022, 2);
aoc::example!(ex01, "02.1.txt", 15, 12);
aoc::test_input!("02.txt", 10816, 11657);
aoc::main!(2022, 2, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
type Input<'a> = Vec<&'a [u8]>;
fn setup(input: &str) -> Input {
@ -36,6 +38,4 @@ fn part2(input: &Input) -> u32 {
.sum()
}
aoc::main!(2022, 3);
aoc::example!(ex01, "03.1.txt", 157, 70);
aoc::test_input!("03.txt", 7903, 2548);
aoc::main!(2022, 3, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
type Input = Vec<(u8, u8, u8, u8)>;
fn setup(input: &str) -> Input {
@ -21,6 +23,4 @@ fn part2(input: &Input) -> usize {
input.iter().filter(|(a, b, c, d)| d >= a && c <= b).count()
}
aoc::main!(2022, 4);
aoc::example!(ex01, "04.1.txt", 2, 4);
aoc::test_input!("04.txt", 453, 919);
aoc::main!(2022, 4, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
type Input = (Vec<String>, Vec<(usize, usize, usize)>);
pub fn solve((stacks, instructions): &Input, get_next: fn(usize, usize) -> usize) -> String {
@ -63,6 +65,4 @@ fn part2(input: &Input) -> String {
solve(input, |_, h| h)
}
aoc::main!(2022, 5);
aoc::example!(ex01, "05.1.txt", "CMZ", "MCD");
aoc::test_input!("05.txt", "QMBMJDFTD", "NBTVTJNFJ");
aoc::main!(2022, 5, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
type Input = Vec<usize>;
fn setup(input: &str) -> Input {
@ -51,10 +53,4 @@ fn part2(input: &Input) -> usize {
solve(input, 14)
}
aoc::main!(2022, 6);
aoc::example!(ex01, "06.1.txt", 7, 19);
aoc::example!(ex02, "06.2.txt", 5, 23);
aoc::example!(ex03, "06.3.txt", 6, 23);
aoc::example!(ex04, "06.4.txt", 10, 29);
aoc::example!(ex05, "06.5.txt", 11, 26);
aoc::test_input!("06.txt", 1802, 3551);
aoc::main!(2022, 6, ex: 1, 2, 3, 4, 5);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use rustc_hash::FxHashMap;
type Input<'a> = Vec<Node<'a>>;
@ -92,6 +94,4 @@ fn part2(nodes: &Input) -> u64 {
.unwrap()
}
aoc::main!(2022, 7);
aoc::example!(ex01, "07.1.txt", 95437, 24933642);
aoc::test_input!("07.txt", 1206825, 9608311);
aoc::main!(2022, 7, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use aoc::{grid::Direction, iter_ext::IterExt};
type Input = Vec<Vec<u8>>;
@ -75,6 +77,4 @@ fn part2(grid: &Input) -> usize {
.unwrap()
}
aoc::main!(2022, 8);
aoc::example!(ex01, "08.1.txt", 21, 8);
aoc::test_input!("08.txt", 1825, 235200);
aoc::main!(2022, 8, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use aoc::grid::Direction;
use rustc_hash::FxHashSet;
@ -66,7 +68,4 @@ fn part2(input: &Input) -> usize {
Solver::new(input, 10).solve()
}
aoc::main!(2022, 9);
aoc::example!(ex01, "09.1.txt", 13, 1);
aoc::example!(ex02, "09.2.txt", 88, 36);
aoc::test_input!("09.txt", 6030, 2545);
aoc::main!(2022, 9, ex: 1, 2);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use aoc::parsing::parse_ascii;
type Input = Vec<Instruction>;
@ -91,10 +93,6 @@ fn part2(input: &Input) -> String {
parse_ascii(&dots.iter().map(|l| &l[..]).collect::<Vec<_>>())
}
aoc::main!(2022, 10);
aoc::example!(ex01, "10.1.txt", p1: 13140);
aoc::test_input!("10.txt", 14820, "RZEKEFHA");
#[cfg(test)]
mod test_cpu {
#[allow(unused_imports)]
@ -125,3 +123,5 @@ mod test_cpu {
[1, 1, 1, 3, 3, 6]
);
}
aoc::main!(2022, 10, ex: 1[a]);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::collections::hash_map::Entry;
use itertools::Itertools;
@ -182,6 +184,4 @@ fn part2(input: &Input) -> u64 {
Solver::new(input, 10000, false).solve()
}
aoc::main!(2022, 11);
aoc::example!(ex01, "11.1.txt", 10605, 2713310158);
aoc::test_input!("11.txt", 54054, 14314925001);
aoc::main!(2022, 11, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::collections::VecDeque;
#[derive(Clone, PartialEq, Eq)]
@ -100,6 +102,4 @@ fn part2(Input { end, grid, .. }: &Input) -> u32 {
)
}
aoc::main!(2022, 12);
aoc::example!(ex01, "12.1.txt", 31, 29);
aoc::test_input!("12.txt", 380, 375);
aoc::main!(2022, 12, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::cmp::Ordering;
type Input = Vec<(Value, Value)>;
@ -95,6 +97,4 @@ fn part2(input: &Input) -> usize {
idx(&fst) * idx(&snd)
}
aoc::main!(2022, 13);
aoc::example!(ex01, "13.1.txt", 13, 140);
aoc::test_input!("13.txt", 6046, 21423);
aoc::main!(2022, 13, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::cmp::Ordering;
struct Input {
@ -105,6 +107,4 @@ fn part2(input: &Input) -> usize {
out
}
aoc::main!(2022, 14);
aoc::example!(ex01, "14.1.txt", 24, 93);
aoc::test_input!("14.txt", 885, 28691);
aoc::main!(2022, 14, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::ops::RangeInclusive;
use itertools::Itertools;
@ -48,7 +50,9 @@ fn merge_ranges(ranges: &mut Vec<RangeInclusive<i64>>) {
ranges.sort_unstable_by(|a, b| a.start().cmp(b.start()));
let mut out = Vec::with_capacity(ranges.len());
let mut it = ranges.iter();
let Some(mut current) = it.next().cloned() else {return;};
let Some(mut current) = it.next().cloned() else {
return;
};
for range in it {
if *range.start() > current.end() + 1 {
out.push(current);
@ -157,6 +161,4 @@ fn part2(input: &Input) -> i64 {
x * 4000000 + y
}
aoc::main!(2022, 15);
aoc::example!(ex01, "15.1.txt", 26, 56000011);
aoc::test_input!("15.txt", 5716881, 10852583132904);
aoc::main!(2022, 15, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use regex::Regex;
use rustc_hash::FxHashMap;
@ -141,6 +143,4 @@ fn part2(input: &Input) -> u32 {
.unwrap()
}
aoc::main!(2022, 16);
aoc::example!(ex01, "16.1.txt", 1651, 1707);
aoc::test_input!("16.txt", 1991, 2705);
aoc::main!(2022, 16, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use rustc_hash::{FxHashMap, FxHashSet};
const SHAPES: &[Shape] = &[
@ -189,6 +191,4 @@ fn part2(input: &Input) -> u64 {
.unwrap()
}
aoc::main!(2022, 17);
aoc::example!(ex01, "17.1.txt", 3068, 1514285714288);
aoc::test_input!("17.txt", 3168, 1554117647070);
aoc::main!(2022, 17, ex: 1);

View file

@ -1,3 +1,5 @@
#![feature(test)]
use std::collections::VecDeque;
use itertools::Itertools;
@ -106,6 +108,4 @@ fn part2(input: &Input) -> usize {
out
}
aoc::main!(2022, 18);
aoc::example!(ex01, "18.1.txt", 64, 58);
aoc::test_input!("18.txt", 4244, 2460);
aoc::main!(2022, 18, ex: 1);

177
Rust/Cargo.lock generated Normal file
View file

@ -0,0 +1,177 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "aoc"
version = "0.0.0"
dependencies = [
"counter",
"itertools",
"num",
"paste",
"regex",
"rustc-hash",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "counter"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d458e66999348f56fd3ffcfbb7f7951542075ca8359687c703de6500c1ddccd"
dependencies = [
"num-traits",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "num"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"

178
Rust/Cargo.toml Normal file
View file

@ -0,0 +1,178 @@
[package]
name = "aoc"
version = "0.0.0"
edition = "2021"
[profile.dev]
opt-level = 3
[profile.release]
opt-level = 3
debug = false
strip = true
debug-assertions = false
overflow-checks = false
lto = true
panic = "abort"
incremental = false
codegen-units = 1
rpath = false
[dependencies]
counter = "0.5.7"
itertools = "0.11.0"
num = "0.4.1"
paste = "1.0.14"
regex = "1.10.2"
rustc-hash = "1.1.0"
[lib]
name = "aoc"
path = "lib/lib.rs"
# 2020
[[bin]]
name = "2020_01"
path = "2020/01.rs"
[[bin]]
name = "2020_02"
path = "2020/02.rs"
[[bin]]
name = "2020_03"
path = "2020/03.rs"
[[bin]]
name = "2020_04"
path = "2020/04.rs"
# 2021
[[bin]]
name = "2021_01"
path = "2021/01.rs"
[[bin]]
name = "2021_02"
path = "2021/02.rs"
[[bin]]
name = "2021_03"
path = "2021/03.rs"
[[bin]]
name = "2021_04"
path = "2021/04.rs"
[[bin]]
name = "2021_05"
path = "2021/05.rs"
[[bin]]
name = "2021_06"
path = "2021/06.rs"
[[bin]]
name = "2021_07"
path = "2021/07.rs"
[[bin]]
name = "2021_08"
path = "2021/08.rs"
[[bin]]
name = "2021_09"
path = "2021/09.rs"
[[bin]]
name = "2021_10"
path = "2021/10.rs"
[[bin]]
name = "2021_11"
path = "2021/11.rs"
[[bin]]
name = "2021_12"
path = "2021/12.rs"
[[bin]]
name = "2021_13"
path = "2021/13.rs"
[[bin]]
name = "2021_14"
path = "2021/14.rs"
[[bin]]
name = "2021_15"
path = "2021/15.rs"
[[bin]]
name = "2021_16"
path = "2021/16.rs"
[[bin]]
name = "2021_17"
path = "2021/17.rs"
[[bin]]
name = "2021_18"
path = "2021/18.rs"
[[bin]]
name = "2021_19"
path = "2021/19.rs"
[[bin]]
name = "2021_20"
path = "2021/20.rs"
[[bin]]
name = "2021_21"
path = "2021/21.rs"
[[bin]]
name = "2021_22"
path = "2021/22.rs"
[[bin]]
name = "2021_23"
path = "2021/23.rs"
[[bin]]
name = "2021_24"
path = "2021/24.rs"
[[bin]]
name = "2021_25"
path = "2021/25.rs"
# 2022
[[bin]]
name = "2022_01"
path = "2022/01.rs"
[[bin]]
name = "2022_02"
path = "2022/02.rs"
[[bin]]
name = "2022_03"
path = "2022/03.rs"
[[bin]]
name = "2022_04"
path = "2022/04.rs"
[[bin]]
name = "2022_05"
path = "2022/05.rs"
[[bin]]
name = "2022_06"
path = "2022/06.rs"
[[bin]]
name = "2022_07"
path = "2022/07.rs"
[[bin]]
name = "2022_08"
path = "2022/08.rs"
[[bin]]
name = "2022_09"
path = "2022/09.rs"
[[bin]]
name = "2022_10"
path = "2022/10.rs"
[[bin]]
name = "2022_11"
path = "2022/11.rs"
[[bin]]
name = "2022_12"
path = "2022/12.rs"
[[bin]]
name = "2022_13"
path = "2022/13.rs"
[[bin]]
name = "2022_14"
path = "2022/14.rs"
[[bin]]
name = "2022_15"
path = "2022/15.rs"
[[bin]]
name = "2022_16"
path = "2022/16.rs"
[[bin]]
name = "2022_17"
path = "2022/17.rs"
[[bin]]
name = "2022_18"
path = "2022/18.rs"

View file

@ -75,7 +75,7 @@ mod tests_take_while_inclusive {
};
}
test!(split, vec![1, 2, 3, 4], |x| x < 3, vec![1, 2, 3]);
test!(always_true, vec![1, 2, 3, 4], |_| true, vec![1, 2, 3, 4]);
test!(always_false, vec![1, 2, 3, 4], |_| false, vec![1]);
test!(split, [1, 2, 3, 4], |x| x < 3, vec![1, 2, 3]);
test!(always_true, [1, 2, 3, 4], |_| true, vec![1, 2, 3, 4]);
test!(always_false, [1, 2, 3, 4], |_| false, vec![1]);
}

108
Rust/lib/lib.rs Normal file
View file

@ -0,0 +1,108 @@
#![feature(test)]
#[doc(hidden)]
pub use test::Bencher;
pub mod grid;
pub mod iter_ext;
pub mod parsing;
extern crate test;
#[macro_export]
macro_rules! main {
($year:literal, $day:tt $(, ex: $($example:literal $([$expart:ident])?),*)?) => {
::aoc::__main!($year, $day);
::aoc::__setup!(_input, ::std::concat!("../../.cache/", $year, "/", $day));
::aoc::__inp!($day, _input, ::std::concat!("../../.cache/", $year, "/", $day));
$($(
::paste::paste! {
::aoc::__setup!([< _ex $example >], ::std::concat!("../../examples/", $year, "/", $day, "/", $example));
::aoc::__inp!($day, [< _ex $example >], ::std::concat!("../../examples/", $year, "/", $day, "/", $example) $(, $expart)?);
}
)*)?
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __ifnot25 {
(25, $($tt:tt)*) => {};
($x:tt, $($tt:tt)*) => {
$($tt)*
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __main {
($year:literal, $day:tt) => {
fn main() {
let path = ::std::concat!("../.cache/", $year, "/", $day);
let input = ::std::fs::read_to_string(path).unwrap();
let input = setup(&input);
::std::println!("{}", part1(&input));
::aoc::__ifnot25! { $day,
::std::println!("{}", part2(&input));
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __setup {
($ident:expr, $in:expr) => {
::paste::paste! {
#[cfg(test)]
#[bench]
fn [< bench $ident _setup >](b: &mut ::aoc::Bencher) {
let input = ::std::include_str!($in);
b.iter(|| setup(input));
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __inp {
($day:tt, $ident:expr, $in:expr) => {
::aoc::__inp!($day, $ident, $in, 1);
::aoc::__ifnot25! { $day,
::aoc::__inp!($day, $ident, $in, 2);
}
};
($day:tt, $ident:expr, $in:expr) => {
::aoc::__inp!($day, $ident, $in, 1);
::aoc::__inp!($day, $ident, $in, 2);
};
($day:tt, $ident:expr, $in:expr, a) => {
::aoc::__inp!($day, $ident, $in, 1);
};
($day:tt, $ident:expr, $in:expr, b) => {
::aoc::__inp!($day, $ident, $in, 2);
};
($day:tt, $ident:expr, $in:expr, $part:expr) => {
::paste::paste! {
#[cfg(test)]
#[test]
fn [< test $ident _part $part >]() {
let input = setup(::std::include_str!($in));
let out = [< part $part >](&input);
assert_eq!(
out.to_string().trim(),
include_str!(::std::concat!($in, ".", $part)).trim()
);
}
#[cfg(test)]
#[bench]
fn [< bench $ident _part $part >](b: &mut ::aoc::Bencher) {
let input = setup(::std::include_str!($in));
b.iter(|| [< part $part >](&input));
}
}
};
}

6
examples/2020/1/1 Normal file
View file

@ -0,0 +1,6 @@
1721
979
366
299
675
1456

1
examples/2020/1/1.1 Normal file
View file

@ -0,0 +1 @@
514579

1
examples/2020/1/1.2 Normal file
View file

@ -0,0 +1 @@
241861950

3
examples/2020/2/1 Normal file
View file

@ -0,0 +1,3 @@
1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc

1
examples/2020/2/1.1 Normal file
View file

@ -0,0 +1 @@
2

1
examples/2020/2/1.2 Normal file
View file

@ -0,0 +1 @@
1

11
examples/2020/3/1 Normal file
View file

@ -0,0 +1,11 @@
..##.......
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#

1
examples/2020/3/1.1 Normal file
View file

@ -0,0 +1 @@
7

1
examples/2020/3/1.2 Normal file
View file

@ -0,0 +1 @@
336

13
examples/2020/4/1 Normal file
View file

@ -0,0 +1,13 @@
ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
byr:1937 iyr:2017 cid:147 hgt:183cm
iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
hcl:#cfa07d byr:1929
hcl:#ae17e1 iyr:2013
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm
hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in

1
examples/2020/4/1.1 Normal file
View file

@ -0,0 +1 @@
2

10
examples/2021/1/1 Normal file
View file

@ -0,0 +1,10 @@
199
200
208
210
200
207
240
269
260
263

1
examples/2021/1/1.1 Normal file
View file

@ -0,0 +1 @@
7

1
examples/2021/1/1.2 Normal file
View file

@ -0,0 +1 @@
5

10
examples/2021/10/1 Normal file
View file

@ -0,0 +1,10 @@
[({(<(())[]>[[{[]{<()<>>
[(()[<>])]({[<{<<[]>>(
{([(<{}[<>[]}>{[]{[(<()>
(((({<>}<{<{<>}{[]{[]{}
[[<[([]))<([[{}[[()]]]
[{[{({}]{}}([{[{{{}}([]
{<[[]]>}<{[{[{[]{()[[[]
[<(<(<(<{}))><([]([]()
<{([([[(<>()){}]>(<<{{
<{([{{}}[<[[[<>{}]]]>[]]

1
examples/2021/10/1.1 Normal file
View file

@ -0,0 +1 @@
26397

1
examples/2021/10/1.2 Normal file
View file

@ -0,0 +1 @@
288957

10
examples/2021/11/1 Normal file
View file

@ -0,0 +1,10 @@
5483143223
2745854711
5264556173
6141336146
6357385478
4167524645
2176841721
6882881134
4846848554
5283751526

1
examples/2021/11/1.1 Normal file
View file

@ -0,0 +1 @@
1656

1
examples/2021/11/1.2 Normal file
View file

@ -0,0 +1 @@
195

7
examples/2021/12/1 Normal file
View file

@ -0,0 +1,7 @@
start-A
start-b
A-c
A-b
b-d
A-end
b-end

1
examples/2021/12/1.1 Normal file
View file

@ -0,0 +1 @@
10

1
examples/2021/12/1.2 Normal file
View file

@ -0,0 +1 @@
36

10
examples/2021/12/2 Normal file
View file

@ -0,0 +1,10 @@
dc-end
HN-start
start-kj
dc-start
dc-HN
LN-dc
HN-end
kj-sa
kj-HN
kj-dc

1
examples/2021/12/2.1 Normal file
View file

@ -0,0 +1 @@
19

1
examples/2021/12/2.2 Normal file
View file

@ -0,0 +1 @@
103

18
examples/2021/12/3 Normal file
View file

@ -0,0 +1,18 @@
fs-end
he-DX
fs-he
start-DX
pj-DX
end-zg
zg-sl
zg-pj
pj-he
RW-he
fs-DX
pj-RW
zg-RW
start-pj
he-WI
zg-he
pj-fs
start-RW

Some files were not shown because too many files have changed in this diff Show more