rust: Move modules to their own files

This commit is contained in:
Sijmen 2020-12-22 15:40:04 +01:00
parent d6888248c3
commit 46dff81bad
Signed by: vijfhoek
GPG key ID: DAF7821E067D9C48
12 changed files with 730 additions and 803 deletions

33
rust/src/day01.rs Normal file
View file

@ -0,0 +1,33 @@
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
}

47
rust/src/day02.rs Normal file
View file

@ -0,0 +1,47 @@
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
}

42
rust/src/day03.rs Normal file
View file

@ -0,0 +1,42 @@
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
}

75
rust/src/day04.rs Normal file
View file

@ -0,0 +1,75 @@
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
}

51
rust/src/day05.rs Normal file
View file

@ -0,0 +1,51 @@
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
}

95
rust/src/day08.rs Normal file
View file

@ -0,0 +1,95 @@
use std::{
collections::HashSet,
time::{Duration, Instant},
};
#[derive(Debug, Copy, Clone)]
enum Instruction {
Acc(i32),
Jmp(i32),
Nop,
}
fn part1(instructions: &[Instruction]) -> (i32, Vec<i32>) {
let mut accumulator = 0;
let mut pc = 0;
let mut pc_history = HashSet::new();
let mut jumps = Vec::new();
loop {
match instructions[pc as usize] {
Instruction::Acc(i) => accumulator += i,
Instruction::Jmp(i) => {
let target = pc + i - 1;
if !pc_history.insert(target) {
break (accumulator, jumps);
}
jumps.push(pc);
pc += i - 1
}
Instruction::Nop => (),
};
pc += 1;
}
}
fn part2(instructions: &[Instruction], skip: i32) -> Option<i32> {
let mut accumulator = 0;
let mut pc = 0;
let mut pc_history = HashSet::new();
loop {
if pc != skip {
match instructions.get(pc as usize) {
Some(Instruction::Acc(i)) => accumulator += i,
Some(Instruction::Jmp(i)) => {
let target = pc + i;
if !pc_history.insert(target) {
break None;
}
pc = target - 1;
}
Some(Instruction::Nop) => (),
None => break Some(accumulator),
};
}
pc += 1;
}
}
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("inputs/day08").unwrap();
let instant = Instant::now();
let instructions: Vec<_> = input
.lines()
.map(|line| {
let operation = &line[0..3];
let value: i32 = line[4..].parse().unwrap();
match operation {
"acc" => Instruction::Acc(value),
"jmp" => Instruction::Jmp(value),
"nop" => Instruction::Nop,
_ => unreachable!(operation),
}
})
.collect();
let (part1, jumps) = part1(&instructions);
let part2 = jumps
.iter()
.rev()
.find_map(|skip_pc| part2(&instructions, *skip_pc))
.unwrap();
let elapsed = instant.elapsed();
if print {
dbg!(elapsed, part1, part2);
}
elapsed
}

58
rust/src/day09.rs Normal file
View file

@ -0,0 +1,58 @@
use std::time::{Duration, Instant};
fn part1(numbers: &[usize]) -> usize {
'outer: for i in COUNT..numbers.len() {
for x in i - COUNT..i {
if numbers[x] > numbers[i] {
continue;
}
for y in x + 1..i {
if numbers[x] + numbers[y] == numbers[i] {
continue 'outer;
}
}
}
return numbers[i];
}
panic!();
}
fn part2(numbers: &[usize], part1: usize) -> usize {
let mut lower = 0;
let mut upper = 0;
let mut sum = 0;
while sum != part1 {
while sum < part1 {
sum += numbers[upper];
upper += 1;
}
while sum > part1 {
sum -= numbers[lower];
lower += 1;
}
}
let slice = &numbers[lower..upper];
slice.iter().min().unwrap() + slice.iter().max().unwrap()
}
const COUNT: usize = 25;
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/09").unwrap();
let instant = Instant::now();
let numbers: Vec<usize> = input.split('\n').flat_map(str::parse).collect();
let part1 = part1(&numbers);
let part2 = part2(&numbers, part1);
if print {
dbg!(part1, part2);
}
instant.elapsed()
}

37
rust/src/day15.rs Normal file
View file

@ -0,0 +1,37 @@
use std::time::{Duration, Instant};
const END: usize = 30_000_000;
pub fn run(print: bool) -> Duration {
let input: Vec<usize> = "0,1,5,10,3,12,19"
.split(",")
.map(|i| i.parse().unwrap())
.collect();
let instant = Instant::now();
let mut history = vec![0; END];
let mut last = input[0];
for turn in 0..input.len() {
history[last] = turn;
last = input[turn];
}
for turn in input.len()..2020 {
let stored = history[last];
history[last] = turn;
last = if stored == 0 { 0 } else { turn - stored };
}
if print {
println!("Part 1: {}", last);
}
for turn in 2020..END {
let stored = history[last];
history[last] = turn;
last = if stored == 0 { 0 } else { turn - stored };
}
if print {
println!("Part 2: {}", last);
}
instant.elapsed()
}

148
rust/src/day16.rs Normal file
View file

@ -0,0 +1,148 @@
use std::fmt;
use std::time::{Duration, Instant};
type Ticket = Vec<usize>;
#[derive(PartialEq, Eq, Hash)]
struct Range {
from: usize,
to: usize,
}
impl fmt::Debug for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{} - {}", self.from, self.to))
}
}
impl Range {
fn from(s: &str) -> Self {
let mut range = s.split("-");
Self {
from: range.next().unwrap().parse().unwrap(),
to: range.next().unwrap().parse().unwrap(),
}
}
fn contains(&self, i: usize) -> bool {
i >= self.from && i <= self.to
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
struct Rule {
name: String,
ranges: (Range, Range),
}
impl Rule {
fn validate(&self, i: usize) -> bool {
let (a, b) = &self.ranges;
a.contains(i) || b.contains(i)
}
}
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/16").unwrap();
let instant = Instant::now();
let mut lines = input.lines();
let mut rules = Vec::new();
while let Some(line) = lines.next() {
let mut colon_split = line.split(": ");
let name = colon_split.next().unwrap().to_string();
if name.is_empty() {
break;
}
let mut ranges = colon_split.next().unwrap().split(" or ");
rules.push(Rule {
name,
ranges: (
Range::from(ranges.next().unwrap()),
Range::from(ranges.next().unwrap()),
),
});
}
lines.next(); // "your ticket:"
let your_ticket: Ticket = lines
.next()
.unwrap()
.split(",")
.map(|s| s.parse().unwrap())
.collect();
lines.next(); // ""
lines.next(); // "nearby tickets:"
let mut nearby_tickets: Vec<Ticket> = Vec::new();
while let Some(line) = lines.next() {
nearby_tickets.push(line.split(",").map(|s| s.parse().unwrap()).collect());
}
let mut part1 = 0;
let mut valid_tickets = Vec::new();
for ticket in &nearby_tickets {
let mut valid = true;
for &field in ticket {
let rule = rules.iter().find(|rule| rule.validate(field));
if rule.is_none() {
valid = false;
part1 += field;
}
}
if valid {
valid_tickets.push(ticket);
}
}
if print {
dbg!(part1);
}
let mut field_possibilities: Vec<_> = (0..your_ticket.len())
.map(|_| (0..rules.len()).collect::<Vec<_>>())
.collect();
for ticket in valid_tickets {
for (&field, possibilities) in ticket.iter().zip(field_possibilities.iter_mut()) {
possibilities
.iter()
.position(|&rule_i| !rules[rule_i].validate(field))
.map(|i| possibilities.remove(i));
}
}
let mut part2 = 1;
loop {
let field_possibility = field_possibilities
.iter()
.enumerate()
.find(|(_, fp)| fp.len() == 1);
let (i, possibility) = match field_possibility {
Some((i, v)) => (i, v[0]),
None => break,
};
for fp in field_possibilities.iter_mut() {
fp.iter()
.position(|&i| i == possibility)
.map(|i| fp.remove(i));
}
let rule = &rules[possibility].name;
if rule.starts_with("de") {
part2 *= your_ticket[i];
}
}
if print {
dbg!(part2);
}
instant.elapsed()
}

116
rust/src/day19.rs Normal file
View file

@ -0,0 +1,116 @@
use std::collections::BTreeMap as HashMap;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::time::{Duration, Instant};
#[derive(Debug)]
enum Rhs {
Terminal(char),
Variables(Vec<Vec<usize>>),
}
type Rules = HashMap<usize, Rhs>;
fn parse(input: &str) -> Option<(Rules, Vec<&str>)> {
let mut rules = HashMap::new();
let mut messages = Vec::new();
let mut parsing_rules = true;
for line in input.lines() {
let trim = line.trim();
if trim.is_empty() {
parsing_rules = false;
continue;
}
if parsing_rules {
let mut split = trim.split(": ");
let lhs: usize = split.next()?.parse().ok()?;
let terms = split.next()?;
let rhs = if terms.starts_with('"') {
Rhs::Terminal(terms.chars().nth(1)?)
} else {
Rhs::Variables(
terms
.split(" | ")
.map(|t| t.split(" ").flat_map(str::parse).collect())
.collect(),
)
};
rules.insert(lhs, rhs);
} else {
messages.push(trim);
}
}
Some((rules, messages))
}
fn generate(rules: &Rules, messages: &Vec<&str>, filename: &str) -> std::io::Result<()> {
let write_file = File::create(filename)?;
let mut w = BufWriter::new(&write_file);
writeln!(&mut w, "from typing import Tuple")?;
writeln!(&mut w)?;
for (i, rule) in rules.iter() {
writeln!(&mut w, "def rule_{}(s):", i)?;
writeln!(&mut w, " if s != '':")?;
match rule {
Rhs::Terminal(terminal) => {
writeln!(&mut w, " if s[0] == '{}':", terminal)?;
writeln!(&mut w, " yield s[1:]")?;
}
Rhs::Variables(variables) => {
for term in variables {
for (j, rule) in term.iter().enumerate() {
if j == 0 {
writeln!(&mut w, " v{} = rule_{}(s)", j, rule)?;
} else {
writeln!(
&mut w,
" v{} = (out for inp in v{} for out in rule_{}(inp))",
j,
j - 1,
rule,
)?;
}
}
writeln!(&mut w, " yield from v{}", term.len() - 1)?;
writeln!(&mut w)?;
}
}
}
writeln!(&mut w)?;
}
writeln!(&mut w, "def validate(s):")?;
writeln!(&mut w, " return any(x == '' for x in rule_0(s))")?;
writeln!(&mut w)?;
writeln!(&mut w, "if __name__ == '__main__':")?;
writeln!(&mut w, " result = 0")?;
for message in messages {
writeln!(&mut w, " result += validate('{}')", message)?;
}
writeln!(&mut w, " print('Result:', result)")?;
Ok(())
}
pub fn run(_print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/19").unwrap();
let instant = Instant::now();
let (mut rules, messages) = parse(&input).unwrap();
generate(&rules, &messages, "/tmp/day19-1.py").unwrap();
rules.insert(8, Rhs::Variables(vec![vec![42], vec![42, 8]]));
rules.insert(11, Rhs::Variables(vec![vec![42, 31], vec![42, 11, 31]]));
generate(&rules, &messages, "/tmp/day19-2.py").unwrap();
instant.elapsed()
}

View file

@ -1,808 +1,27 @@
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
}
}
mod day06 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day07 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day08 {
use std::{
collections::HashSet,
time::{Duration, Instant},
};
#[derive(Debug, Copy, Clone)]
enum Instruction {
Acc(i32),
Jmp(i32),
Nop,
}
fn part1(instructions: &[Instruction]) -> (i32, Vec<i32>) {
let mut accumulator = 0;
let mut pc = 0;
let mut pc_history = HashSet::new();
let mut jumps = Vec::new();
loop {
match instructions[pc as usize] {
Instruction::Acc(i) => accumulator += i,
Instruction::Jmp(i) => {
let target = pc + i - 1;
if !pc_history.insert(target) {
break (accumulator, jumps);
}
jumps.push(pc);
pc += i - 1
}
Instruction::Nop => (),
};
pc += 1;
}
}
fn part2(instructions: &[Instruction], skip: i32) -> Option<i32> {
let mut accumulator = 0;
let mut pc = 0;
let mut pc_history = HashSet::new();
loop {
if pc != skip {
match instructions.get(pc as usize) {
Some(Instruction::Acc(i)) => accumulator += i,
Some(Instruction::Jmp(i)) => {
let target = pc + i;
if !pc_history.insert(target) {
break None;
}
pc = target - 1;
}
Some(Instruction::Nop) => (),
None => break Some(accumulator),
};
}
pc += 1;
}
}
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("inputs/day08").unwrap();
let instant = Instant::now();
let instructions: Vec<_> = input
.lines()
.map(|line| {
let operation = &line[0..3];
let value: i32 = line[4..].parse().unwrap();
match operation {
"acc" => Instruction::Acc(value),
"jmp" => Instruction::Jmp(value),
"nop" => Instruction::Nop,
_ => unreachable!(operation),
}
})
.collect();
let (part1, jumps) = part1(&instructions);
let part2 = jumps
.iter()
.rev()
.find_map(|skip_pc| part2(&instructions, *skip_pc))
.unwrap();
let elapsed = instant.elapsed();
if print {
dbg!(elapsed, part1, part2);
}
elapsed
}
}
mod day09 {
use std::time::{Duration, Instant};
fn part1(numbers: &[usize]) -> usize {
'outer: for i in COUNT..numbers.len() {
for x in i - COUNT..i {
if numbers[x] > numbers[i] {
continue;
}
for y in x + 1..i {
if numbers[x] + numbers[y] == numbers[i] {
continue 'outer;
}
}
}
return numbers[i];
}
panic!();
}
fn part2(numbers: &[usize], part1: usize) -> usize {
let mut lower = 0;
let mut upper = 0;
let mut sum = 0;
while sum != part1 {
while sum < part1 {
sum += numbers[upper];
upper += 1;
}
while sum > part1 {
sum -= numbers[lower];
lower += 1;
}
}
let slice = &numbers[lower..upper];
slice.iter().min().unwrap() + slice.iter().max().unwrap()
}
const COUNT: usize = 25;
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/09").unwrap();
let instant = Instant::now();
let numbers: Vec<usize> = input.split('\n').flat_map(str::parse).collect();
let part1 = part1(&numbers);
let part2 = part2(&numbers, part1);
if print {
dbg!(part1, part2);
}
instant.elapsed()
}
}
mod day10 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day11 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day12 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day13 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day14 {
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day15 {
use std::time::{Duration, Instant};
const END: usize = 30_000_000;
pub fn run(print: bool) -> Duration {
let input: Vec<usize> = "0,1,5,10,3,12,19"
.split(",")
.map(|i| i.parse().unwrap())
.collect();
let instant = Instant::now();
let mut history = vec![0; END];
let mut last = input[0];
for turn in 0..input.len() {
history[last] = turn;
last = input[turn];
}
for turn in input.len()..2020 {
let stored = history[last];
history[last] = turn;
last = if stored == 0 { 0 } else { turn - stored };
}
if print {
println!("Part 1: {}", last);
}
for turn in 2020..END {
let stored = history[last];
history[last] = turn;
last = if stored == 0 { 0 } else { turn - stored };
}
if print {
println!("Part 2: {}", last);
}
instant.elapsed()
}
}
mod day16 {
use std::fmt;
use std::time::{Duration, Instant};
type Ticket = Vec<usize>;
#[derive(PartialEq, Eq, Hash)]
struct Range {
from: usize,
to: usize,
}
impl fmt::Debug for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{} - {}", self.from, self.to))
}
}
impl Range {
fn from(s: &str) -> Self {
let mut range = s.split("-");
Self {
from: range.next().unwrap().parse().unwrap(),
to: range.next().unwrap().parse().unwrap(),
}
}
fn contains(&self, i: usize) -> bool {
i >= self.from && i <= self.to
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
struct Rule {
name: String,
ranges: (Range, Range),
}
impl Rule {
fn validate(&self, i: usize) -> bool {
let (a, b) = &self.ranges;
a.contains(i) || b.contains(i)
}
}
pub fn run(print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/16").unwrap();
let instant = Instant::now();
let mut lines = input.lines();
let mut rules = Vec::new();
while let Some(line) = lines.next() {
let mut colon_split = line.split(": ");
let name = colon_split.next().unwrap().to_string();
if name.is_empty() {
break;
}
let mut ranges = colon_split.next().unwrap().split(" or ");
rules.push(Rule {
name,
ranges: (
Range::from(ranges.next().unwrap()),
Range::from(ranges.next().unwrap()),
),
});
}
lines.next(); // "your ticket:"
let your_ticket: Ticket = lines
.next()
.unwrap()
.split(",")
.map(|s| s.parse().unwrap())
.collect();
lines.next(); // ""
lines.next(); // "nearby tickets:"
let mut nearby_tickets: Vec<Ticket> = Vec::new();
while let Some(line) = lines.next() {
nearby_tickets.push(line.split(",").map(|s| s.parse().unwrap()).collect());
}
let mut part1 = 0;
let mut valid_tickets = Vec::new();
for ticket in &nearby_tickets {
let mut valid = true;
for &field in ticket {
let rule = rules.iter().find(|rule| rule.validate(field));
if rule.is_none() {
valid = false;
part1 += field;
}
}
if valid {
valid_tickets.push(ticket);
}
}
if print {
dbg!(part1);
}
let mut field_possibilities: Vec<_> = (0..your_ticket.len())
.map(|_| (0..rules.len()).collect::<Vec<_>>())
.collect();
for ticket in valid_tickets {
for (&field, possibilities) in ticket.iter().zip(field_possibilities.iter_mut()) {
possibilities
.iter()
.position(|&rule_i| !rules[rule_i].validate(field))
.map(|i| possibilities.remove(i));
}
}
let mut part2 = 1;
loop {
let field_possibility = field_possibilities
.iter()
.enumerate()
.find(|(_, fp)| fp.len() == 1);
let (i, possibility) = match field_possibility {
Some((i, v)) => (i, v[0]),
None => break,
};
for fp in field_possibilities.iter_mut() {
fp.iter()
.position(|&i| i == possibility)
.map(|i| fp.remove(i));
}
let rule = &rules[possibility].name;
if rule.starts_with("de") {
part2 *= your_ticket[i];
}
}
if print {
dbg!(part2);
}
instant.elapsed()
}
}
mod day17 {
use std::time::Duration;
pub fn run(_print: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day18 {
use std::time::Duration;
pub fn run(_print: bool) -> Duration {
Duration::new(0, 0)
}
}
mod day19 {
use std::collections::BTreeMap as HashMap;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::time::{Duration, Instant};
#[derive(Debug)]
enum Rhs {
Terminal(char),
Variables(Vec<Vec<usize>>),
}
type Rules = HashMap<usize, Rhs>;
fn parse(input: &str) -> Option<(Rules, Vec<&str>)> {
let mut rules = HashMap::new();
let mut messages = Vec::new();
let mut parsing_rules = true;
for line in input.lines() {
let trim = line.trim();
if trim.is_empty() {
parsing_rules = false;
continue;
}
if parsing_rules {
let mut split = trim.split(": ");
let lhs: usize = split.next()?.parse().ok()?;
let terms = split.next()?;
let rhs = if terms.starts_with('"') {
Rhs::Terminal(terms.chars().nth(1)?)
} else {
Rhs::Variables(
terms
.split(" | ")
.map(|t| t.split(" ").flat_map(str::parse).collect())
.collect(),
)
};
rules.insert(lhs, rhs);
} else {
messages.push(trim);
}
}
Some((rules, messages))
}
fn generate(rules: &Rules, messages: &Vec<&str>, filename: &str) -> std::io::Result<()> {
let write_file = File::create(filename)?;
let mut w = BufWriter::new(&write_file);
writeln!(&mut w, "from typing import Tuple")?;
writeln!(&mut w)?;
for (i, rule) in rules.iter() {
writeln!(&mut w, "def rule_{}(s):", i)?;
writeln!(&mut w, " if s != '':")?;
match rule {
Rhs::Terminal(terminal) => {
writeln!(&mut w, " if s[0] == '{}':", terminal)?;
writeln!(&mut w, " yield s[1:]")?;
}
Rhs::Variables(variables) => {
for term in variables {
for (j, rule) in term.iter().enumerate() {
if j == 0 {
writeln!(&mut w, " v{} = rule_{}(s)", j, rule)?;
} else {
writeln!(
&mut w,
" v{} = (out for inp in v{} for out in rule_{}(inp))",
j,
j - 1,
rule,
)?;
}
}
writeln!(&mut w, " yield from v{}", term.len() - 1)?;
writeln!(&mut w)?;
}
}
}
writeln!(&mut w)?;
}
writeln!(&mut w, "def validate(s):")?;
writeln!(&mut w, " return any(x == '' for x in rule_0(s))")?;
writeln!(&mut w)?;
writeln!(&mut w, "if __name__ == '__main__':")?;
writeln!(&mut w, " result = 0")?;
for message in messages {
writeln!(&mut w, " result += validate('{}')", message)?;
}
writeln!(&mut w, " print('Result:', result)")?;
Ok(())
}
pub fn run(_print: bool) -> Duration {
let input = std::fs::read_to_string("../inputs/19").unwrap();
let instant = Instant::now();
let (mut rules, messages) = parse(&input).unwrap();
generate(&rules, &messages, "/tmp/day19-1.py").unwrap();
rules.insert(8, Rhs::Variables(vec![vec![42], vec![42, 8]]));
rules.insert(11, Rhs::Variables(vec![vec![42, 31], vec![42, 11, 31]]));
generate(&rules, &messages, "/tmp/day19-2.py").unwrap();
instant.elapsed()
}
}
mod nop;
mod day01;
mod day02;
mod day03;
mod day04;
mod day05;
use nop as day06;
use nop as day07;
mod day08;
mod day09;
use nop as day10;
use nop as day11;
use nop as day12;
use nop as day13;
use nop as day14;
mod day15;
mod day16;
use nop as day17;
use nop as day18;
mod day19;
use nop as day20;
fn main() {
let days = [
@ -825,6 +44,7 @@ fn main() {
day17::run,
day18::run,
day19::run,
day20::run,
];
if let Some(day) = std::env::args().nth(1) {

5
rust/src/nop.rs Normal file
View file

@ -0,0 +1,5 @@
use std::time::Duration;
pub fn run(_: bool) -> Duration {
Duration::new(0, 0)
}