Compare commits

..

1 Commits

Author SHA1 Message Date
c9e45c4685 day10 2023-12-28 13:36:06 -05:00
8 changed files with 2 additions and 577 deletions

View File

@@ -28,10 +28,7 @@ fn part2(input: &Vec<u32>) -> i64 {
let mut ans = HashMap::new();
ans.insert(0, 1);
for adapter in input.iter().cloned().map(|x| x as i32) {
let to_insert = ans.get(&(adapter as i32 - 1)).unwrap_or(&0)
+ ans.get(&(adapter as i32 - 2)).unwrap_or(&0)
+ ans.get(&(adapter as i32 - 3)).unwrap_or(&0);
let to_insert = ans.get(&(adapter as i32 - 1)).unwrap_or(&0) + ans.get(&(adapter as i32 - 2)).unwrap_or(&0) + ans.get(&(adapter as i32 - 3)).unwrap_or(&0);
ans.insert(adapter, to_insert.clone());
}

View File

@@ -1,137 +0,0 @@
use aoc_runner_derive::{aoc, aoc_generator};
use Instruction::*;
use itertools::Itertools;
#[derive(Debug)]
enum Instruction {
MoveNorth(i32),
MoveSouth(i32),
MoveEast(i32),
MoveWest(i32),
TurnLeft(i32),
TurnRight(i32),
MoveForward(i32)
}
impl From<(char, i32)> for Instruction {
fn from(value: (char, i32)) -> Self {
match value {
(i, v) if i == 'N' => MoveNorth(v),
(i, v) if i == 'S' => MoveSouth(v),
(i, v) if i == 'E' => MoveEast(v),
(i, v) if i == 'W' => MoveWest(v),
(i, v) if i == 'L' => TurnLeft(v),
(i, v) if i == 'R' => TurnRight(v),
(i, v) if i == 'F' => MoveForward(v),
_ => unreachable!()
}
}
}
#[aoc_generator(day12)]
fn parse(input: &str) -> Vec<Instruction> {
input
.lines()
.map(|line| {
(line.chars().next().unwrap(), line[1..].parse::<i32>().unwrap()).into()
})
.collect_vec()
}
const DIR_POS_MODIFIER: [(i32, i32); 4] = [(1, 0), (0, -1), (-1, 0), (0, 1)];
#[aoc(day12, part1)]
fn part1(input: &Vec<Instruction>) -> i32 {
let mut x = 0;
let mut y = 0;
let mut direction = 0; // 0 is east, thus 90 is south, 180 is west, and 270 is north
for instr in input {
match instr {
MoveNorth(val) => y += val,
MoveSouth(val) => y -= val,
MoveEast(val) => x += val,
MoveWest(val) => x -= val,
TurnLeft(val) => {
direction -= val;
if direction < 0 {
direction += 360;
}
},
TurnRight(val) => {
direction += val;
if direction >= 360 {
direction -= 360
}
},
MoveForward(val) => {
let (xmod, ymod) = DIR_POS_MODIFIER[(direction / 90) as usize];
x += xmod * val;
y += ymod * val;
},
}
}
x.abs() + y.abs()
}
#[aoc(day12, part2)]
fn part2(input: &Vec<Instruction>) -> i32 {
let mut way_x = 10;
let mut way_y = 1;
let mut ship_x: i32 = 0;
let mut ship_y: i32 = 0;
for instr in input {
match instr {
MoveNorth(val) => way_y += val,
MoveSouth(val) => way_y -= val,
MoveEast(val) => way_x += val,
MoveWest(val) => way_x -= val,
TurnLeft(val) => {
for _ in 0..(val / 90) {
let tmp = way_y;
way_y = way_x;
way_x = -tmp;
}
},
TurnRight(val) => {
for _ in 0..(val / 90) {
let tmp = way_y;
way_y = -way_x;
way_x = tmp;
}
},
MoveForward(val) => {
ship_x += way_x * val;
ship_y += way_y * val;
},
}
}
ship_x.abs() + ship_y.abs()
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"F10
N3
F7
R90
F11";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 25);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX)), 286);
}
}

View File

@@ -1,76 +0,0 @@
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
#[aoc_generator(day13, part1)]
fn parse(input: &str) -> (i32, Vec<i32>) {
let (start, buses) = input
.lines()
.collect_tuple()
.unwrap();
let buses = buses
.split(',')
.filter_map(|num| num.parse::<i32>().ok())
.collect_vec();
(start.parse::<i32>().unwrap(), buses)
}
#[aoc(day13, part1)]
fn part1((start, buses): &(i32, Vec<i32>)) -> i32 {
let mut cur = 0;
loop {
if let Some(bus) = buses.iter().find(|x| (cur + start) % *x == 0) {
return bus * cur;
}
cur += 1;
}
}
#[aoc_generator(day13, part2)]
fn parse2(input: &str) -> Vec<Option<i64>> {
let buses = input
.lines().skip(1).next().unwrap();
let buses = buses
.split(',')
.map(|num| num.parse::<i64>().ok())
.collect_vec();
buses
}
#[aoc(day13, part2)]
fn part2(input: &Vec<Option<i64>>) -> i64 {
let mut min_value = 0;
let mut running_product = 1;
for (index, bus) in input.iter().enumerate() {
if let Some(bus) = bus {
while (min_value + index as i64) % bus != 0 {
min_value += running_product;
}
running_product *= bus;
}
}
min_value
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"939
7,13,x,x,59,x,31,19";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 295);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse2(EX)), 1068781);
}
}

View File

@@ -1,149 +0,0 @@
use std::{collections::HashMap, iter::zip};
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::{Itertools, iproduct};
#[derive(Debug)]
enum ProgramStep {
Mask(String),
Mem(u64, u64)
}
impl From<&str> for ProgramStep {
fn from(value: &str) -> Self {
let (name, value) = value.split(" = ").collect_tuple().unwrap();
return match name {
"mask" => Self::Mask(value.to_string()),
name if name.starts_with("mem") => {
Self::Mem(name[4..name.len() - 1].parse::<u64>().unwrap(), value.parse::<u64>().unwrap())
}
_ => unreachable!()
};
}
}
#[aoc_generator(day14)]
fn parse(input: &str) -> Vec<ProgramStep> {
input.lines().map(ProgramStep::from).collect_vec()
}
fn apply_mask(mask: &str, val: u64) -> u64 {
let mut val = val;
for (i, char) in mask.chars().enumerate() {
match char {
'X' => continue,
'1' => val = val | (2_u64.pow((36 - i - 1).try_into().unwrap())),
'0' => val = val & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
_ => unreachable!()
};
}
val
}
#[aoc(day14, part1)]
fn part1(program: &Vec<ProgramStep>) -> u64 {
let mut mem: HashMap<u64, u64> = HashMap::new();
let mut mask = "";
for step in program {
match step {
ProgramStep::Mask(val) => mask = val,
ProgramStep::Mem(addr, val) => {
let val = apply_mask(mask, *val);
mem.insert(*addr, val);
},
}
}
mem.values().sum()
}
fn permute_masks(mask: &str) -> Vec<String> {
let mut masks: Vec<String> = vec![];
let bits = mask.chars().enumerate().filter(|(_, v)| *v == 'X').map(|(i, _)| i).collect_vec();
let perms = kproduct("21".to_string(), bits.len() as u32);
let mut new_mask = mask.to_string();
for perm in perms {
let bit_vals = zip(bits.clone(), perm.chars()).collect::<HashMap<usize, char>>();
for (k, val) in bit_vals {
new_mask = new_mask[0..k].to_string() + &val.to_string() + &new_mask[k+1..];
}
masks.push(new_mask.clone());
}
masks
}
fn kproduct(seq: String, k: u32) -> Vec<String> {
match k {
0 => vec![],
1 => seq.chars().map(|c| c.to_string()).collect(),
2 => iproduct!(seq.chars(), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
_ => iproduct!(kproduct(seq.clone(), k - 1), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
}
}
fn get_addrs(addr: u64, mask: &str) -> Vec<u64> {
let mut addrs = vec![];
let masks = permute_masks(mask);
for mask in masks {
let mut addr = addr;
for (i, char) in mask.chars().enumerate() {
match char {
'1' => addr = addr | (2_u64.pow((36 - i - 1).try_into().unwrap())),
'2' => addr = addr & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
'0' => continue,
_ => unreachable!()
}
}
addrs.push(addr)
}
addrs
}
#[aoc(day14, part2)]
fn part2(program: &Vec<ProgramStep>) -> u64 {
let mut mem: HashMap<u64, u64> = HashMap::new();
let mut mask = "";
for step in program {
match step {
ProgramStep::Mask(val) => mask = val,
ProgramStep::Mem(addr, val) => {
let addrs = get_addrs(*addr, mask);
for addr in addrs {
mem.insert(addr, *val);
}
},
}
}
mem.values().sum()
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 165);
}
const EX_2: &str = r"mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1";
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX_2)), 208);
}
}

View File

@@ -1,60 +0,0 @@
use std::collections::HashMap;
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
#[aoc_generator(day15)]
fn parse(input: &str) -> Vec<u64> {
input.split(',').map(str::parse::<u64>).map(Result::unwrap).collect_vec()
}
#[aoc(day15, part1)]
fn part1(input: &Vec<u64>) -> u64 {
let mut list = input.iter().take(input.len() - 1).cloned().enumerate().map(|(i,v)| (v,i)).collect::<HashMap<_, _>>();
let mut cur = *input.last().unwrap();
for turn in input.len() - 1..2020 - 1 {
let mut next = 0;
if let Some(last_turn) = list.get_mut(&cur) {
next = (turn - *last_turn) as u64;
}
list.insert(cur, turn);
cur = next;
}
cur
}
#[aoc(day15, part2)]
fn part2(input: &Vec<u64>) -> u64 {
let mut list = input.iter().take(input.len() - 1).cloned().enumerate().map(|(i,v)| (v,i)).collect::<HashMap<_, _>>();
let mut cur = *input.last().unwrap();
for turn in input.len() - 1..30000000 - 1 {
let mut next = 0;
if let Some(last_turn) = list.get_mut(&cur) {
next = (turn - *last_turn) as u64;
}
list.insert(cur, turn);
cur = next;
}
cur
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"0,3,6";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 436);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX)), 175594);
}
}

View File

@@ -1,145 +0,0 @@
use std::{ops::RangeInclusive, collections::HashSet};
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
use regex::Regex;
lazy_static!(
static ref RULE_RE: Regex = Regex::new(r"(.*): (\d+)-(\d+) or (\d+)-(\d+)").unwrap();
);
#[aoc_generator(day16)]
fn parse(input: &str) -> (Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>) {
let (rules, my_ticket, tickets) = input
.split("\n\n")
.collect_tuple()
.unwrap();
let rules = RULE_RE
.captures_iter(rules)
.filter_map(|captures| {
Some((
captures.get(1)?.as_str().to_string(),
captures.get(2)?.as_str().parse::<usize>().ok()?..=captures.get(3)?.as_str().parse::<usize>().ok()?,
captures.get(4)?.as_str().parse::<usize>().ok()?..=captures.get(5)?.as_str().parse::<usize>().ok()?,
))
}).collect_vec();
let my_ticket = my_ticket
.lines()
.last()
.unwrap()
.split(',')
.filter_map(|num| num.parse::<usize>().ok())
.collect_vec();
let tickets = tickets
.lines()
.skip(1)
.map(|line| {
line
.split(',')
.filter_map(|num| num.parse::<usize>().ok())
.collect_vec()
}).collect_vec();
(rules, my_ticket, tickets)
}
#[aoc(day16, part1)]
fn part1((rules, _, tickets): &(Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> usize {
let mut invalid = 0;
for ticket in tickets {
for item in ticket {
if !rules.iter().any(|rule| {
rule.1.contains(item) || rule.2.contains(item)
}) {
invalid += item;
}
}
}
invalid
}
#[aoc(day16, part2)]
fn part2((rules, my_ticket, tickets): &(Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> usize {
let mut tickets = tickets.clone();
let mut rem = 0;
for (i, ticket) in tickets.clone().iter().enumerate() {
for item in ticket {
if !rules.iter().any(|rule| {
rule.1.contains(item) || rule.2.contains(item)
}) {
tickets.remove(i - rem);
rem += 1;
}
}
}
let mut possible_rules = get_possible_rules(&tickets, rules);
let mut assigned_rules = [0; 20];
while let Some(i) = possible_rules.iter().position(|s| s.len() == 1) {
let v = *possible_rules[i].iter().next().unwrap();
assigned_rules[i] = v;
for s in &mut possible_rules { s.remove(&v); }
}
assigned_rules.iter()
.enumerate()
.filter(|(_,&rule)| rule < 6)
.map(|(i,_)| my_ticket[i])
.product()
}
fn get_possible_rules(tickets: &Vec<Vec<usize>>, rules: &Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>) -> Vec<HashSet<usize>> {
(0..20).map(|i|
(0..20).filter(|&j|
tickets.iter().all(|t| fits_rule(&rules[j], t[i]))
).collect()
).collect()
}
fn fits_rule((_, r1,r2): &(String, RangeInclusive<usize>, RangeInclusive<usize>), v: usize) -> bool {
r1.contains(&v) || r2.contains(&v)
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"class: 1-3 or 5-7
row: 6-11 or 33-44
seat: 13-40 or 45-50
your ticket:
7,1,14
nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 71);
}
const EX2: &str = r"class: 0-1 or 4-19
row: 0-5 or 8-19
seat: 0-13 or 16-19
your ticket:
11,12,13
nearby tickets:
3,9,18
15,1,5
5,14,9";
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX2)), 1716);
}
}

View File

@@ -1,7 +1,7 @@
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
const PREAMBLE_LEN: usize = 5;
const PREAMBLE_LEN: usize = 25;
#[aoc_generator(day9)]
fn parse(input: &str) -> Vec<u64> {

View File

@@ -1,8 +1,3 @@
mod day16;
mod day15;
mod day14;
mod day13;
mod day12;
mod day10;
mod day9;
mod day8;