add: more days

This commit is contained in:
Charles
2024-12-03 21:38:03 -08:00
parent 79d1618ede
commit 9f780311ed
19 changed files with 389 additions and 201 deletions
Generated
+47
View File
@@ -5,3 +5,50 @@ version = 3
[[package]] [[package]]
name = "advent-of-code-2024" name = "advent-of-code-2024"
version = "0.1.0" version = "0.1.0"
dependencies = [
"regex",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+1
View File
@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
regex = "1.11.1"
+23
View File
@@ -0,0 +1,23 @@
import re
with open("input-xlarge", "r") as inputFile:
memory = inputFile.read()
do_memory = memory.split("don't()")
# part 1
def apply_multipliers(s: str):
prods = []
multipliers = re.findall("mul\(\d{1,3},\d{1,3}\)", s)
for m in multipliers:
nums = list(map(int, re.findall("\d+", m)))
prods.append(nums[0] * nums[1])
return sum(prods)
# part 2
sum_dos = apply_multipliers(do_memory[0])
for line in do_memory[1:]:
if "do()" in line:
split_line = "".join(line.split('do()')[1:])
sum_dos += apply_multipliers(split_line)
print(sum_dos)
-9
View File
@@ -1,9 +0,0 @@
# Advent of code 2024
Usage:
rustc dp1.rs
cat input.txt | dp1.rs
## Day
-22
View File
@@ -1,22 +0,0 @@
use std::collections::BinaryHeap;
use std::io;
fn main() -> io::Result<()> {
let mut l1 = BinaryHeap::<u64>::new();
let mut l2 = BinaryHeap::<u64>::new();
for line in io::stdin().lines() {
let line = line?;
let parts: Vec<&str> = line.trim().split_whitespace().collect();
let (n1, n2) = (parts[0], parts[1]);
l1.push(n1.parse().unwrap());
l2.push(n2.parse().unwrap());
}
let l1 = l1.into_sorted_vec();
let l2 = l2.into_sorted_vec();
let mut sum = 0;
for (n1, n2) in l1.into_iter().zip(l2.into_iter()) {
sum += n1.abs_diff(n2);
}
println!("{}", sum);
Ok(())
}
-6
View File
@@ -1,6 +0,0 @@
3 4
4 3
2 5
1 3
3 9
3 3
-21
View File
@@ -1,21 +0,0 @@
use std::collections::HashMap;
use std::io;
fn main() -> io::Result<()> {
let mut l1: Vec<u64> = vec!();
let mut l2: HashMap<u64, u64> = HashMap::default();
for line in io::stdin().lines() {
let line = line?;
let parts: Vec<&str> = line.trim().split_whitespace().collect();
let (n1, n2) = (parts[0], parts[1]);
l1.push(n1.parse().unwrap());
let v = l2.entry(n2.parse::<u64>().unwrap()).or_insert(0);
*v += 1;
}
let mut sum = 0;
for n1 in l1.into_iter() {
sum += n1*l2.get(&n1).unwrap_or(&0);
}
println!("{}", sum);
Ok(())
}
-58
View File
@@ -1,58 +0,0 @@
use advent_of_code_2024::{make_main, SResult};
make_main!();
// CODE
#[derive(PartialEq)]
enum Direction {
Up,
Down,
}
impl Direction {
fn from(a: usize, b: usize) -> Self {
if a > b {
Direction::Down
} else {
Direction::Up
}
}
}
fn solve(lines: Vec<String>) -> SResult<usize> {
let mut failed = 0;
for line in lines.iter() {
let reports: Vec<usize> = line.split_whitespace().map(|v| v.parse::<usize>().unwrap()).collect();
let mut i = 0;
let direction = Direction::from(reports[0], reports[1]);
while i + 1 < reports.len() {
let delta = reports[i].abs_diff(reports[i+1]);
if delta < 1 || delta > 3 {
failed += 1;
break;
}
if direction != Direction::from(reports[i], reports[i+1]) {
failed += 1;
break;
}
i += 1;
}
}
Ok(lines.len() - failed)
}
// CODE
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d2p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 2);
}
}
-6
View File
@@ -1,6 +0,0 @@
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
-78
View File
@@ -1,78 +0,0 @@
use advent_of_code_2024::{make_main, SResult};
make_main!();
#[derive(PartialEq, Clone, Copy)]
enum Direction {
Up,
Down,
}
impl Direction {
fn from(a: usize, b: usize) -> Self {
if a > b {
Direction::Down
} else {
Direction::Up
}
}
}
fn solve(lines: Vec<String>) -> SResult<usize> {
let mut fail_count = 0;
for line in lines.iter() {
let reports: Vec<usize> = line
.split_whitespace()
.map(|v| v.parse::<usize>().unwrap())
.collect();
let problems = match test(&reports) {
// Cool, nothing to see here
Ok(_) => continue,
Err(e) => e,
};
let mut pass = false;
for problem in problems {
let mut l1 = reports.clone();
l1.remove(problem);
if test(&l1).is_ok() {
pass = true;
break;
}
}
if !pass {
fail_count += 1;
}
}
Ok(lines.len() - fail_count)
}
// Tests the report, and returns indexes around where a failure is detected.
fn test(reports: &[usize]) -> Result<(), Vec<usize>> {
let mut i = 0;
let direction = Direction::from(reports[0], reports[1]);
while i + 1 < reports.len() {
let delta = reports[i].abs_diff(reports[i + 1]);
if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) {
let mut errs = vec![i, i + 1];
if i > 0 {
errs.push(i - 1);
}
return Err(errs);
}
i += 1;
}
Ok(())
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d2p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 4);
}
}
+29
View File
@@ -0,0 +1,29 @@
use advent_of_code_2024::{make_main, SResult};
use regex::Regex;
make_main!();
fn solve(lines: Vec<String>) -> SResult<usize> {
let mut result = 0;
let re = Regex::new(r"mul\((?<mul1>\d{1,3}),(?<mul2>\d{1,3})\)")?;
for line in lines {
for caps in re.captures_iter(&line) {
result += caps["mul1"].parse::<usize>().unwrap() * caps["mul2"].parse::<usize>().unwrap();
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d3p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 161);
}
}
+1
View File
@@ -0,0 +1 @@
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
+94
View File
@@ -0,0 +1,94 @@
use advent_of_code_2024::{make_main, SResult};
make_main!();
type PResult<'a, T> = Result<(&'a str, T), ()>;
fn literal<'a, 'b>(p: &'a str, lit: &'b str) -> PResult<'a, ()> {
if p.len() < lit.len() {
Err(())
} else {
let (found, rest) = p.split_at(lit.len());
if found == lit {
Ok((rest, ()))
} else {
Err(())
}
}
}
fn next(p: &str) -> PResult<char> {
let mut chars = p.chars();
let next = chars.next().ok_or(())?;
Ok((chars.as_str(), next))
}
fn int(mut p: &str) -> PResult<usize> {
let (_p, total) = next(p)?;
let mut total = total.to_digit(10).ok_or(())?;
p = _p;
let mut i = 1;
while let Ok((_p, digit)) = next(p) {
if !digit.is_digit(10) {
break;
}
total = (total * 10) + digit.to_digit(10).ok_or(())?;
p = _p;
// We only accept integers between 1 and 3 digits
i += 1;
if i > 3 {
return Err(());
}
}
Ok((p, total as usize))
}
fn mul(p: &str) -> PResult<usize> {
let (p, _) = literal(p, "mul(")?;
let (p, mul1) = int(p)?;
let (p, _) = literal(p, ",")?;
let (p, mul2) = int(p)?;
let (p, _) = literal(p, ")")?;
Ok((p, mul1*mul2))
}
fn solve(lines: Vec<String>) -> SResult<usize> {
let mut result = 0;
let mut enabled = true;
for line in lines {
let mut line = line.as_str();
while line.len() > 0 {
if let Ok(val) = mul(&line) {
if enabled {
result += val.1;
}
line = val.0;
} else if let Ok(val) = literal(&line, "do()") {
enabled = true;
line = val.0;
} else if let Ok(val) = literal(&line, "don't()") {
enabled = false;
line = val.0;
} else {
let n = next(line).unwrap();
line = n.0;
}
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d3p2.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 48);
}
}
+36
View File
@@ -0,0 +1,36 @@
use advent_of_code_2024::{make_main, SResult};
use regex::Regex;
make_main!();
fn solve(lines: Vec<String>) -> SResult<usize> {
let mut result = 0;
let re = Regex::new(r"(?<do>do\(\))|(?<dont>don't\(\))|mul\(((?<mul1>\d{1,3})),((?<mul2>\d{1,3}))\)")?;
let mut enabled = true;
for line in lines {
for caps in re.captures_iter(&line) {
if caps.name("do").is_some() {
enabled = true;
} else if caps.name("dont").is_some() {
enabled = false;
} else if caps.name("mul1").is_some() && enabled {
result += caps["mul1"].parse::<usize>().unwrap() * caps["mul2"].parse::<usize>().unwrap();
}
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d3p2.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 48);
}
}
+1
View File
@@ -0,0 +1 @@
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
+61
View File
@@ -0,0 +1,61 @@
use advent_of_code_2024::{make_main, SResult};
make_main!();
fn solve(lines: Vec<String>) -> SResult<usize> {
// Convert to a grid of chars for easy searching
let mut grid = vec!();
for line in lines {
let line: Vec<char> = line.chars().collect();
grid.push(line);
}
let mut total = 0;
let word: Vec<char> = "XMAS".chars().collect();
for x in 0..grid.len() {
for y in 0..grid[x].len() {
for vel in [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (-1, 1), (1, -1)] {
let mut matches = 0;
let mut pos = (x, y);
for c in &word {
if grid[pos.0][pos.1] != *c {
break;
}
matches += 1;
if let Some(_pos) = next(pos, vel, grid.len()) {
pos = _pos;
} else {
break;
}
}
if matches == word.len() {
total += 1;
}
}
}
}
Ok(total)
}
fn next((x, y): (usize, usize), (xvel, yvel): (i64, i64), width: usize) -> Option<(usize, usize)> {
let x = x as i64 + xvel;
let y = y as i64 + yvel;
if x < 0 || y < 0 || x == width as i64 || y == width as i64 {
None
} else {
Some((x as usize, y as usize))
}
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d4p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 18);
}
}
+10
View File
@@ -0,0 +1,10 @@
MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
+73
View File
@@ -0,0 +1,73 @@
use advent_of_code_2024::{make_main, SResult};
make_main!();
fn solve(lines: Vec<String>) -> SResult<usize> {
// Convert to a grid of chars for easy searching
let mut grid = vec!();
for line in lines {
let line: Vec<char> = line.chars().collect();
grid.push(line);
}
let mut total = 0;
let word: Vec<char> = "XMAS".chars().collect();
for x in 0..grid.len() {
for y in 0..grid[x].len() {
if grid[x][y] != 'A' {
continue;
}
let mut count = 0;
for vel in [(1, 1), (1, -1), (-1, -1), (-1, 1)] {
if let Some(pos) = next((x, y), vel, grid.len()) {
if check_mas(&grid, pos, (-1*vel.0, -1*vel.1)) {
count += 1;
}
}
}
if count == 2 {
total += 1;
}
}
}
Ok(total)
}
fn check_mas(grid: &[Vec<char>], mut pos: (usize, usize), vel: (i64, i64)) -> bool {
let mut matches = 0;
for c in "MAS".chars() {
if c != grid[pos.0][pos.1] {
break;
}
matches += 1;
if let Some(_pos) = next(pos, vel, grid.len()) {
pos = _pos;
} else {
break;
}
}
matches == "MAS".len()
}
fn next((x, y): (usize, usize), (xvel, yvel): (i64, i64), width: usize) -> Option<(usize, usize)> {
let x = x as i64 + xvel;
let y = y as i64 + yvel;
if x < 0 || y < 0 || x == width as i64 || y == width as i64 {
None
} else {
Some((x as usize, y as usize))
}
}
#[cfg(test)]
mod tests {
use advent_of_code_2024::input;
use super::*;
#[test]
fn sample_input() {
let strings: Vec<String> = input!("d4p1.txt");
let got = solve(strings).unwrap();
assert_eq!(got, 9);
}
}
+13 -1
View File
@@ -18,4 +18,16 @@ macro_rules! input {
}; };
} }
pub type SResult<T> = Result<T, Box<dyn std::error::Error>>; pub type SResult<T> = Result<T, Box<dyn std::error::Error>>;
pub type Pair<T = usize> = (T, T);
pub fn next((x, y): Pair, (xvel, yvel): Pair<i64>, width: usize) -> Option<Pair> {
let x = x as i64 + xvel;
let y = y as i64 + yvel;
if x < 0 || y < 0 || x == width as i64 || y == width as i64 {
None
} else {
Some((x as usize, y as usize))
}
}