diff --git a/aoc2024/Cargo.toml b/aoc2024/Cargo.toml index ad4e092..5f21f25 100644 --- a/aoc2024/Cargo.toml +++ b/aoc2024/Cargo.toml @@ -8,3 +8,4 @@ shared = { path = "../shared" } regex = "1.10.2" substring = "1.4.5" itertools = "0.12.0" +ndarray = "0.16.1" diff --git a/aoc2024/src/day04.rs b/aoc2024/src/day04.rs index 456f666..67c0c43 100644 --- a/aoc2024/src/day04.rs +++ b/aoc2024/src/day04.rs @@ -1,9 +1,36 @@ +use ndarray::prelude::*; use shared::{Solution, Answer}; pub struct Day04; impl Solution for Day04 { fn part_1(&self, input: &str) -> Answer { + let line_len = input.find("\n").unwrap() as i32; + let input = input.replace("\n", ""); + let input = input.as_bytes(); + + let possible_perms: [i32; 8] = [-line_len - 1, -line_len, -line_len+1, -1, 1, line_len-1, line_len, line_len+1]; + + let mut res = 0; + + for (i, x) in input.iter().enumerate().filter(|(_, x)| x==&&b'X') { + println!("{i}, {x}"); + for p in possible_perms.iter() { + let m = input.get((i as i32 + p) as usize); + let a = input.get((i as i32 + p * 2) as usize); + let s = input.get((i as i32 + p * 3) as usize); + if match (m, a, s) { + (Some(M), Some(A), Some(S)) => M == &b'M' && A == &b'A' && S == &b'S', + _ => false + } { + println!("{}, {}, {}", m.unwrap(), a.unwrap(), s.unwrap()); + res += 1; + } + } + } + + print!("{:?}", res); + Answer::Unimplemented } diff --git a/aoc2024/src/day05.rs b/aoc2024/src/day05.rs index 7f52f64..c3fc29e 100644 --- a/aoc2024/src/day05.rs +++ b/aoc2024/src/day05.rs @@ -1,9 +1,16 @@ +use std::collections::{HashMap, HashSet}; + use shared::{Solution, Answer}; pub struct Day05; impl Solution for Day05 { fn part_1(&self, input: &str) -> Answer { + let (p1, p2) = parse(input); + + // let res = p2.iter() + // .filter(|&update| ) + Answer::Unimplemented } @@ -11,3 +18,21 @@ impl Solution for Day05 { Answer::Unimplemented } } + +fn parse(input: &str) -> (HashMap>, Vec>) { + let (first, second) = input.split_once("\n\n").unwrap(); + + let mut out1: HashMap::> = HashMap::new(); + + for (a, b) in first + .lines() + .map(|s| s.split_once("|") + .unwrap()) + .map(|(a, b)| (a.parse::().unwrap(), b.parse::().unwrap())) { + out1.entry(a).or_default().insert(b); + }; + + let out2: Vec> = second.lines().map(|line| line.split(",").map(|x| x.parse::().unwrap()).collect()).collect(); + + (out1, out2) +} diff --git a/aoc2024/src/day23.rs b/aoc2024/src/day23.rs index d8b6804..ca7b0cb 100644 --- a/aoc2024/src/day23.rs +++ b/aoc2024/src/day23.rs @@ -1,13 +1,89 @@ +use std::collections::{HashMap, HashSet}; + +use itertools::Itertools; use shared::{Solution, Answer}; pub struct Day23; impl Solution for Day23 { fn part_1(&self, input: &str) -> Answer { - Answer::Unimplemented + let data = parse(input); + + let mut neighbors: HashMap<&str, HashSet<&str>> = HashMap::new(); + + for (a, b) in data.iter() { + neighbors.entry(a).or_default().insert(b); + neighbors.entry(b).or_default().insert(a); + } + + let mut triangles: Vec<[&str; 3]> = vec![]; + + for (key, values) in neighbors.iter() { + for neighbor in values { + let common = values.intersection(&neighbors[neighbor]); + for second_neighbor in common.into_iter() { + if [key, neighbor, second_neighbor].is_sorted() { + triangles.push([key, neighbor, second_neighbor]); + } + } + } + } + + let res = triangles.iter() + .filter(|[a, b, c]| a.starts_with('t') || b.starts_with('t') || c.starts_with('t')) + .count(); + + Answer::Number(res as u64) } fn part_2(&self, input: &str) -> Answer { - Answer::Unimplemented + let data: Vec<(String, String)> = parse(input) + .iter() + .map(|(a, b)| (a.to_string(), b.to_string())) + .collect(); + + let mut neighbors: HashMap> = HashMap::new(); + + for (a, b) in data.iter() { + neighbors.entry(a.clone()).or_default().insert(b.clone()); + neighbors.entry(b.clone()).or_default().insert(a.clone()); + } + + let mut cliques: Vec> = vec![]; + + bron_kerbosch(&neighbors, HashSet::new(), neighbors.keys().cloned().collect(), HashSet::new(), &mut cliques); + + let res = cliques.iter() + .max_by_key(|x| x.len()) + .expect("no clique found") + .iter() + .sorted() + .join(","); + + Answer::String(res) + } +} + +fn parse(input: &str) -> Vec<(&str, &str)> { + input.trim() + .lines() + .map(|l| l.split_once('-').unwrap()) + .collect() +} + +fn bron_kerbosch(neigbors: &HashMap>, mut r: HashSet, mut p: HashSet, mut x: HashSet, cliques: &mut Vec>) { + if p.is_empty() && x.is_empty() { + cliques.push(r); + } else { + for vertex in p.clone().iter() { + bron_kerbosch(neigbors, + r.union(&HashSet::from([vertex.clone()])).cloned().collect(), + p.intersection(&neigbors[vertex]).cloned().collect(), + x.intersection(&neigbors[vertex]).cloned().collect(), + cliques); + + p.remove(vertex); + x.insert(vertex.clone()); + } } }