| 
					
				 | 
			
			
				@@ -1,9 +1,9 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use std::{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    cmp::Reverse, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    collections::{BinaryHeap, HashMap, HashSet}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use aoc2022_niels_overkamp::common::{self, AOCResult}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use aoc2023_niels_overkamp::common::{self, AOCResult}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use itertools::Itertools; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::iter::once; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::thread; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::error::Error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::collections::HashMap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const DAY: &str = "day12"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -11,109 +11,236 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     common::run(DAY, &run) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-enum Dirs { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Left, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Up, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Right, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Down, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-impl Dirs { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    fn apply(&self, (x, y): (usize, usize)) -> (usize, usize) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        match self { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Dirs::Left => (x.wrapping_sub(1), y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Dirs::Up => (x, y + 1), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Dirs::Right => (x + 1, y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Dirs::Down => (x, y.wrapping_sub(1)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn count_valid_solutions(row: &[u8], description: &Vec<usize>) -> usize { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let total_groups = row.len() - description.iter().sum::<usize>() + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut sum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for solution in (0..total_groups).combinations(description.len()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut valid = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut offset = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut last = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (index, size) in solution.iter().zip(description.iter()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let start = index + offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let end = index+offset+size; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprint!(" {:?}{:?},",  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 Vec::from_iter(row[last..start].into_iter()).into_iter().map(|n| *n as char).collect::<Vec<_>>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 Vec::from_iter(row[start..end].into_iter()).into_iter().map(|n| *n as char).collect::<Vec<char>>()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            valid &= row[start..end].into_iter().all(|byte| *byte != b'.'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            valid &= row[last..start].into_iter().all(|byte| *byte != b'#'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if !valid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset += size; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            last = end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        valid &= row[last..].into_iter().all(|byte| *byte != b'#'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if valid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!(" valid"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sum += 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!(""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return sum 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-const DIRECTIONS: [Dirs; 4] = [Dirs::Left, Dirs::Up, Dirs::Right, Dirs::Down]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn fast_count_valid_solutions(row: &[u8], description: &Vec<usize>) -> usize { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let description_length = description.len();     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let row_length = row.len(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut stack: Vec<(usize, usize, Option<usize>)> = vec![]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut index = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut size = description[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut offset = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut cache = HashMap::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-pub fn run(input: &Vec<String>) -> AOCResult { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut map: HashMap<(usize, usize), u8> = HashMap::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut start: Option<(usize, usize)> = None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut goal: Option<(usize, usize)> = None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for (y, line) in input.iter().enumerate() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (x, c) in line.bytes().enumerate() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            map.insert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                (x, y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                match c { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    b'S' => 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    b'E' => 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    c => c - b'a', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            match c { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                b'S' => start = Some((x, y)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                b'E' => goal = Some((x, y)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _ => (), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let count = 'outer: loop { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // eprintln!("i:{} o:{} s:{}",index ,offset, size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // eprintln!(" {:?}", cache); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // eprintln!(" {:?}", stack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut cut = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut valid = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut offset_delta = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut count = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if let Some(cached_count) = cache.get(&(index, offset)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprint!(" cache hit"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            count = *cached_count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if offset + size > row_length { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprint!(" too long"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if let Some(blank) = row[offset..offset+size] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .into_iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .position(|byte| *byte == b'.')  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprint!(" blank at {}", offset+blank); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if row[offset..offset+blank].into_iter().any(|byte| *byte == b'#') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" but fill before"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" offset+={}", blank + 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                offset_delta = blank + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if offset + size < row_length && row[offset+size] == b'#' { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprint!(" fill at end spacer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if row[offset] == b'#' { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" and fill at start"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" offset++"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                offset_delta = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if index == description_length - 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(filled) = row[offset+size..] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    .into_iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    .position(|byte| *byte == b'#')  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" fill after last group at {}", filled + size + offset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if row[offset..offset+filled+1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .into_iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .any(|byte| *byte == b'#') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // eprint!(" and fill before with too large gap"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // eprint!(" offset+={}", filled + 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    offset_delta = filled + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprint!(" completed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if row[offset] == b'#' { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // eprint!(" VALID\n\tbut terminates after"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    cut = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // eprint!(" offset++ VALID"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    offset_delta = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                count = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            stack.push((index, offset, None)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset_delta = size + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset += offset_delta;         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            index += 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            size = description[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!(" STEP"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let start = start.ok_or("No start found")?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let goal = goal.ok_or("No end found")?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // A* Search 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let h = |(x, y)| goal.0.abs_diff(x) + goal.1.abs_diff(y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut frontier = BinaryHeap::from([Reverse((h(start), start))]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut visited = HashSet::from([start]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut g_scores = HashMap::from([(start, 0usize)]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut f_scores = HashMap::from([(start, h(start))]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut length = None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while let Some(Reverse((_, pos))) = frontier.pop() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if pos == goal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            length = g_scores.get(&goal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let height = *map.get(&pos).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let g_score = *g_scores.get(&pos).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for dir in DIRECTIONS { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let neighbour = dir.apply(pos); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if let Some(_) = map.get(&neighbour).filter(|hn| **hn <= height + 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if *g_scores.get(&neighbour).unwrap_or(&usize::MAX) > g_score + 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    g_scores.insert(neighbour, g_score + 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    let f_score = g_score + 1 + h(neighbour); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    f_scores.insert(neighbour, f_score); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if !visited.contains(&neighbour) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        frontier.push(Reverse((f_score, neighbour))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        visited.insert(neighbour); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if cut { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!(" CUT"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!("{:?}\n{:?}", cache, stack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cache.insert((index, offset), count); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'inner: loop { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // eprintln!("{:?}\n{:?}", cache, stack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                match stack.pop() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Some((entry_index, entry_offset, Some(entry_count)))     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        count += entry_count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        cache.insert((entry_index, entry_offset), count); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Some((entry_index, entry_offset, None))                  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if row[entry_offset] != b'#' { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            stack.push((entry_index, entry_offset, Some(count))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            index = entry_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            offset = entry_offset + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            size = description[index];   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break 'inner; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            cache.insert((entry_index, entry_offset), count); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    None  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // eprintln!("DONE"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break 'outer count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!("{:?}\n{:?}", cache, stack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            stack.push((index, offset, Some(count))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset += offset_delta; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // eprintln!(""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let length = length.ok_or("No path to goal found")?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // println!("\t\t{}", count); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut frontier = BinaryHeap::from([Reverse((0, goal))]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut visited = HashSet::from([goal]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let mut shortest_path = usize::MAX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while let Some(Reverse((length, pos))) = frontier.pop() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if *map.get(&pos).unwrap() == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            shortest_path = shortest_path.min(length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let height = *map.get(&pos).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for neighbour in DIRECTIONS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .map(|d| d.apply(pos)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .filter(|pos| !visited.contains(pos)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .filter(|pos| map.get(pos).map(|h| (*h + 1) >= height).unwrap_or(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .collect::<Vec<_>>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            frontier.push(Reverse((length + 1, neighbour))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            visited.insert(neighbour); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub fn run(input: &Vec<String>) -> AOCResult { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut input = input.clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut sum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut long_sum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut handles = vec![]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let threads = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for i in 0..threads { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let input = input.split_off(input.len() - input.len() / (threads - i)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let handle = thread::spawn(move || -> Result<_, String> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut sum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let mut long_sum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let l = input.len(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (j, line) in input.into_iter().enumerate() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let temp = sum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if let Some((row, description)) = line.split_once(' ') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let description = description 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .split(',') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .map(str::parse::<usize>) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .collect::<Result<Vec<usize>, _>>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .map_err(|e| e.to_string())?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                     print!("{}", row); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let row = row.as_bytes(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sum += fast_count_valid_solutions(row, &description); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let len = description.len()*5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let description = Vec::from_iter(description.into_iter().cycle().take(len)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let len = row.len()*5 + 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let row: Vec<u8> = Vec::from_iter(row.into_iter().map(|n| *n).chain(once(b'?')).cycle().take(len)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                     print!("\tlong"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    long_sum += fast_count_valid_solutions(row.as_slice(), &description); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Err(format!("{} is not a valid \"row description\" format", line)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                println!("{}: ({}/{})\t", i, j + 1, l); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Ok((sum, long_sum)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        handles.push(handle); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Ok([Some(length.to_string()), Some(shortest_path.to_string())]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for handle in handles.into_iter() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let (result, long_result) = (handle.join().unwrap())?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        sum +=  result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        long_sum += long_result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Ok([Some(sum.to_string()), Some(long_sum.to_string())]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 pub fn test_day12() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     assert!(common::run_test(DAY, &run)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//     loop { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//         let mut line = String::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//         std::io::stdin().read_line(&mut line).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//         write!(std::io::stderr(), "{}", line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//         match run(&Vec::from([line[..line.len()-1].to_owned()])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//             Ok([v, _]) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 write!(std::io::stderr(), "{}\n", v.unwrap()).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 std::io::stderr().flush().unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//             Err(e) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 write!(std::io::stderr(), "{}\n", e).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                 std::io::stderr().flush().unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |