Rust solutions
This commit is contained in:
commit
59264dfa91
3 changed files with 352 additions and 0 deletions
56
rust/Cargo.lock
generated
Normal file
56
rust/Cargo.lock
generated
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aoc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
"thread_local",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
10
rust/Cargo.toml
Normal file
10
rust/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "aoc"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Sijmen Schoon <me@sijmenschoon.nl>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
regex = "1.4.2"
|
286
rust/src/main.rs
Normal file
286
rust/src/main.rs
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
mod day01 {
|
||||||
|
use std::{collections::HashMap, time::Duration, time::Instant};
|
||||||
|
|
||||||
|
pub fn run(print: bool) -> Duration {
|
||||||
|
let file_string = std::fs::read_to_string("inputs/day01").unwrap();
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let entries: Vec<usize> = file_string.lines().flat_map(|line| line.parse()).collect();
|
||||||
|
let mut sums = HashMap::new();
|
||||||
|
|
||||||
|
let mut part1 = None;
|
||||||
|
for i in &entries {
|
||||||
|
for j in &entries {
|
||||||
|
if i + j < 2020 {
|
||||||
|
sums.insert(i + j, i * j);
|
||||||
|
} else if i + j == 2020 {
|
||||||
|
part1 = Some(i * j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let part1 = part1.unwrap();
|
||||||
|
|
||||||
|
let part2 = entries
|
||||||
|
.iter()
|
||||||
|
.find_map(|i| sums.get(&(2020 - i)).map(|mul| i * mul))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let elapsed = instant.elapsed();
|
||||||
|
if print {
|
||||||
|
dbg!(elapsed, part1, part2);
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod day02 {
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub fn run(print: bool) -> Duration {
|
||||||
|
let file_string = std::fs::read_to_string("inputs/day02").unwrap();
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let rules: Vec<(usize, usize, char, &str)> = file_string
|
||||||
|
.lines()
|
||||||
|
.flat_map(|rule| {
|
||||||
|
let mut splitc = rule.splitn(2, ' ');
|
||||||
|
let mut split_range = splitc.next()?.split('-');
|
||||||
|
|
||||||
|
let min: usize = split_range.next()?.parse().ok()?;
|
||||||
|
let max: usize = split_range.next()?.parse().ok()?;
|
||||||
|
|
||||||
|
let rest = splitc.next()?;
|
||||||
|
let c = rest.chars().next()?;
|
||||||
|
let pw = &rest[3..];
|
||||||
|
|
||||||
|
Some((min, max, c, pw))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let part1 = rules
|
||||||
|
.iter()
|
||||||
|
.filter(|(min, max, c, pw)| {
|
||||||
|
let c = &pw.chars().filter(|n| n == c).count();
|
||||||
|
min <= c && c <= max
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let part2 = rules
|
||||||
|
.iter()
|
||||||
|
.filter(|(min, max, c, pw)| {
|
||||||
|
let mut chars = pw.chars();
|
||||||
|
let a = chars.nth(min - 1) == Some(*c);
|
||||||
|
let b = chars.nth(max - min - 1) == Some(*c);
|
||||||
|
a ^ b
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let elapsed = instant.elapsed();
|
||||||
|
if print {
|
||||||
|
dbg!(elapsed, part1, part2);
|
||||||
|
}
|
||||||
|
elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod day03 {
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
fn count(rows: &[Vec<char>], dx: usize, dy: usize) -> usize {
|
||||||
|
let mut x = 0;
|
||||||
|
let mut trees = 0;
|
||||||
|
for y in (0..rows.len()).step_by(dy) {
|
||||||
|
let row = &rows[y];
|
||||||
|
|
||||||
|
if row[x] == '#' {
|
||||||
|
trees += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = (x + dx) % row.len();
|
||||||
|
}
|
||||||
|
trees
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(print: bool) -> Duration {
|
||||||
|
let file_string = std::fs::read_to_string("inputs/day3").unwrap();
|
||||||
|
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let rows: Vec<Vec<char>> = file_string
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.chars().collect())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let part1 = count(&rows, 3, 1);
|
||||||
|
|
||||||
|
let part2 = part1
|
||||||
|
* [(1, 1), (5, 1), (7, 1), (1, 2)]
|
||||||
|
.iter()
|
||||||
|
.map(|(dx, dy)| count(&rows, *dx, *dy))
|
||||||
|
.fold(1, |acc, element| acc * element);
|
||||||
|
|
||||||
|
let elapsed = instant.elapsed();
|
||||||
|
if print {
|
||||||
|
dbg!(elapsed, part1, part2);
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod day04 {
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
fn between(field: &str, lower: i32, higher: i32) -> bool {
|
||||||
|
let n: i32 = field.parse().unwrap();
|
||||||
|
n >= lower && n <= higher
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(print: bool) -> Duration {
|
||||||
|
let input = std::fs::read_to_string("inputs/day04").unwrap();
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
let passports: Vec<_> = input
|
||||||
|
.split("\n\n")
|
||||||
|
.map(|p| p.replace('\n', " ").trim().to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let valid_passports = passports.iter().filter(|p| {
|
||||||
|
p.contains("byr")
|
||||||
|
&& p.contains("iyr")
|
||||||
|
&& p.contains("eyr")
|
||||||
|
&& p.contains("hgt")
|
||||||
|
&& p.contains("hcl")
|
||||||
|
&& p.contains("ecl")
|
||||||
|
&& p.contains("pid")
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut part1 = 0;
|
||||||
|
|
||||||
|
let part2 = valid_passports
|
||||||
|
.filter(|p| {
|
||||||
|
part1 += 1;
|
||||||
|
|
||||||
|
let mut valid = true;
|
||||||
|
for field in p.split(' ') {
|
||||||
|
let mut parts = field.split(':');
|
||||||
|
let label = parts.next().unwrap();
|
||||||
|
let value = parts.next().unwrap();
|
||||||
|
|
||||||
|
valid = valid
|
||||||
|
&& match label {
|
||||||
|
"byr" => between(value, 1920, 2002),
|
||||||
|
"iyr" => between(value, 2010, 2020),
|
||||||
|
"eyr" => between(value, 2020, 2030),
|
||||||
|
"hgt" => {
|
||||||
|
let height = &value[..value.len() - 2];
|
||||||
|
(value.ends_with("in") && between(height, 59, 76))
|
||||||
|
|| (value.ends_with("cm") && between(height, 150, 193))
|
||||||
|
}
|
||||||
|
"hcl" => value.starts_with("#"),
|
||||||
|
"ecl" => {
|
||||||
|
value == "amb"
|
||||||
|
|| value == "blu"
|
||||||
|
|| value == "brn"
|
||||||
|
|| value == "gry"
|
||||||
|
|| value == "grn"
|
||||||
|
|| value == "hzl"
|
||||||
|
|| value == "oth"
|
||||||
|
}
|
||||||
|
"pid" => value.len() == 9,
|
||||||
|
"cid" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valid
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let elapsed = now.elapsed();
|
||||||
|
if print {
|
||||||
|
dbg!(elapsed, part1, part2);
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod day05 {
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub fn run(print: bool) -> Duration {
|
||||||
|
let input = std::fs::read_to_string("inputs/day05").unwrap();
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let passes: Vec<_> = input.lines().collect();
|
||||||
|
let mut ids: Vec<_> = passes
|
||||||
|
.iter()
|
||||||
|
.map(|pass| {
|
||||||
|
let mut row_min = 0;
|
||||||
|
let mut row_max = 128;
|
||||||
|
let mut column_min = 0;
|
||||||
|
let mut column_max = 8;
|
||||||
|
|
||||||
|
for c in pass.chars() {
|
||||||
|
match c {
|
||||||
|
'F' => row_max = (row_min + row_max) / 2,
|
||||||
|
'B' => row_min = (row_min + row_max) / 2,
|
||||||
|
'L' => column_max = (column_min + column_max) / 2,
|
||||||
|
'R' => column_min = (column_min + column_max) / 2,
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
row_min * 8 + column_min
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ids.sort();
|
||||||
|
|
||||||
|
let part1 = ids.iter().max().unwrap();
|
||||||
|
|
||||||
|
let part2 = ids
|
||||||
|
.windows(2)
|
||||||
|
.find_map(|window| {
|
||||||
|
if window[0] + 2 == window[1] {
|
||||||
|
Some(window[0] + 1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let elapsed = instant.elapsed();
|
||||||
|
if print {
|
||||||
|
dbg!(elapsed, part1, part2);
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let days = [day01::run, day02::run, day03::run, day04::run, day05::run];
|
||||||
|
|
||||||
|
if let Some(day) = std::env::args().nth(1) {
|
||||||
|
let day: usize = day.parse().expect("day not an integer");
|
||||||
|
if day > 0 {
|
||||||
|
days[day - 1](true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let repetitions = 2000;
|
||||||
|
let mut total = Duration::new(0, 0);
|
||||||
|
|
||||||
|
for day in 0..days.len() {
|
||||||
|
for _ in 0..repetitions {
|
||||||
|
total += days[day](false) / repetitions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(total);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue