diff --git a/c/2024/19/linen_layout.c b/c/2024/19/linen_layout.c
index 1f720d0..1c51c27 100644
--- a/c/2024/19/linen_layout.c
+++ b/c/2024/19/linen_layout.c
@@ -10,6 +10,7 @@ typedef char Towel[10];
 typedef struct Towels {
   Towel towels[2000];
   int towels_count;
+  AocHashmap *map;
 } Towels;
 
 bool towels_valid_design(Towels *t, char *design) {
@@ -22,11 +23,34 @@ bool towels_valid_design(Towels *t, char *design) {
   return false;
 }
 
+long towels_valid_designs(Towels *t, char *design) {
+  AocHashmapNode *memo = aoc_hashmap_get(t->map, design);
+  if (memo != NULL) return memo->value;
+
+  if (strlen(design) == 0) return 1;
+
+  long valid_designs = 0;
+  for (int i = 0; i < t->towels_count; i++) {
+    if (strstr(design, t->towels[i]) == design) {
+      valid_designs += towels_valid_designs(t, design + strlen(t->towels[i]));
+    }
+  }
+
+  aoc_hashmap_put(t->map, design, valid_designs);
+
+  return valid_designs;
+}
+
 int main() {
   char *line;
 
   Towels towels;
   towels.towels_count = 0;
+  towels.map = malloc(sizeof(AocHashmap));
+  for (int i = 0; i < AOC_HASHMAP_RADIX; i++) {
+    towels.map->buckets[i] = NULL;
+  }
+
 
   line = aoc_read_line();
   char *token = strtok(line, ", ");
@@ -37,12 +61,16 @@ int main() {
 
   aoc_read_line(); // blank line
 
-  int valid_designs = 0;
+  int valid_single_designs = 0;
+  long valid_multi_designs = 0;
   while ((line = aoc_read_line()) != NULL) {
-    if (towels_valid_design(&towels, line)) valid_designs++;
+    printf("Checking %s, %d\n", line, aoc_hash(line));
+    if (towels_valid_design(&towels, line)) valid_single_designs++;
+    valid_multi_designs += towels_valid_designs(&towels, line);
   }
 
-  printf("Part 1: %d\n", valid_designs);
+  printf("Part 1: %d\n", valid_single_designs);
+  printf("Part 2: %ld\n", valid_multi_designs);
 
   aoc_free();
   exit(0);