diff --git a/.aoc_tiles/tiles/2024/23.png b/.aoc_tiles/tiles/2024/23.png
index 269ba34..e8f4326 100644
Binary files a/.aoc_tiles/tiles/2024/23.png and b/.aoc_tiles/tiles/2024/23.png differ
diff --git a/README.md b/README.md
index 422c0bf..f23874d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
- 2024 - 43 ⭐ - Rust
+ 2024 - 44 ⭐ - Rust
@@ -68,4 +68,7 @@
+
+
+
diff --git a/src/day23.rs b/src/day23.rs
new file mode 100644
index 0000000..6dbbbdf
--- /dev/null
+++ b/src/day23.rs
@@ -0,0 +1,144 @@
+use std::fmt::Debug;
+
+use aoc_runner_derive::aoc;
+use itertools::Itertools;
+use rustc_hash::{FxHashMap, FxHashSet};
+
+#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
+struct Node([char; 2]);
+
+impl Debug for Node {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("{}", self.0.iter().join("")))
+ }
+}
+
+impl From<[char; 2]> for Node {
+ fn from(value: [char; 2]) -> Self {
+ Node(value)
+ }
+}
+
+impl TryFrom> for Node {
+ type Error = <[char; 2] as TryFrom>>::Error;
+ fn try_from(value: Vec) -> Result {
+ let array: [char; 2] = value.try_into()?;
+ Ok(Self(array))
+ }
+}
+
+struct Network {
+ nodes: Vec,
+ edges: FxHashMap>,
+}
+
+impl Network {
+ fn groups_3(&self) -> FxHashSet> {
+ let mut sets = FxHashSet::default();
+ for n in &self.nodes {
+ let neighbours = self.edges.get(n).unwrap();
+ for neigh in neighbours {
+ let neighbours2 = self.edges.get(neigh).unwrap();
+ for neigh2 in neighbours2 {
+ let neighbours3 = self.edges.get(neigh2).unwrap();
+ if neighbours3.contains(n) {
+ let mut set = vec![*n, *neigh, *neigh2];
+ set.sort();
+ sets.insert(set);
+ }
+ }
+ }
+ }
+ sets
+ }
+}
+
+impl From<&str> for Network {
+ fn from(input: &str) -> Self {
+ let mut nodes = Vec::new();
+ let mut edges = FxHashMap::default();
+ for line in input.lines() {
+ let (node1, node2) = line.split_once('-').unwrap();
+ let (node1, node2): (Node, Node) = (
+ node1.chars().collect_vec().try_into().unwrap(),
+ node2.chars().collect_vec().try_into().unwrap(),
+ );
+ if !nodes.contains(&node1) {
+ nodes.push(node1);
+ }
+ if !nodes.contains(&node2) {
+ nodes.push(node2);
+ }
+ edges.entry(node1).or_insert(Vec::new()).push(node2);
+ edges.entry(node2).or_insert(Vec::new()).push(node1);
+ }
+ Self { nodes, edges }
+ }
+}
+
+fn parse(input: &str) -> Network {
+ input.into()
+}
+
+#[aoc(day23, part1)]
+pub fn part1(input: &str) -> i64 {
+ let network = parse(input);
+ println!("edges: {:?}", network.edges);
+ let sets = network.groups_3();
+ let t_count = sets.iter().filter(|set| set.iter().any(|s| s.0[0] == 't')).count();
+ println!("groups: {:?}", sets);
+
+ t_count as i64
+}
+
+#[aoc(day23, part2)]
+pub fn part2(input: &str) -> String {
+ todo!()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ const EXAMPLE: &str = "kh-tc
+qp-kh
+de-cg
+ka-co
+yn-aq
+qp-ub
+cg-tb
+vc-aq
+tb-ka
+wh-tc
+yn-cg
+kh-ub
+ta-co
+de-co
+tc-td
+tb-wq
+wh-td
+ta-ka
+td-qp
+aq-cg
+wq-ub
+ub-vc
+de-ta
+wq-aq
+wq-vc
+wh-yn
+ka-de
+kh-ta
+co-tc
+wh-qp
+tb-vc
+td-yn";
+
+ #[test]
+ fn part1_example() {
+ assert_eq!(part1(EXAMPLE), 7);
+ }
+
+ #[test]
+ fn part2_example() {
+ assert_eq!(part2(EXAMPLE), "co,de,ka,ta");
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 320bb98..6adecb4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,6 +13,7 @@ pub mod day2;
pub mod day20;
pub mod day21;
pub mod day22;
+pub mod day23;
pub mod day3;
pub mod day4;
pub mod day5;