Day 4
This commit is contained in:
		
							parent
							
								
									a8df580730
								
							
						
					
					
						commit
						22168572c8
					
				
					 4 changed files with 152 additions and 0 deletions
				
			
		
							
								
								
									
										7
									
								
								2024/day4/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								2024/day4/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					# This file is automatically @generated by Cargo.
 | 
				
			||||||
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
 | 
					version = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "day4"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
							
								
								
									
										6
									
								
								2024/day4/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								2024/day4/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "day4"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
							
								
								
									
										22
									
								
								2024/day4/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								2024/day4/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					# Solution Day 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hooray... 2D text analysis... My favorite thing! Not. I am just not good with those. Never was, probably never
 | 
				
			||||||
 | 
					really will be.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Task 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I might've gone of the wrong track, because this solution is just so complicated. I started out in 2D, i.e.
 | 
				
			||||||
 | 
					split the text into lines and tried from there, but got fed up with the complexity and reverted back to a
 | 
				
			||||||
 | 
					1D-approach with jump offsets to get from one line to the other. Basically the algorithm goes from the start
 | 
				
			||||||
 | 
					point and checks whether it is too close to one of the edges, I remove the jump offsets in this direction from
 | 
				
			||||||
 | 
					my jumps array. After that the jumps get executed 4 times, collecting the letters along the way to form the words.
 | 
				
			||||||
 | 
					The algorithm collects all words in all directions from each point in the text and then checks, which of those
 | 
				
			||||||
 | 
					fit the pattern. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sounds simply, hoo boy! how many times I overran the array bounds before I got all parts of that right!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Task 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Much, much simpler. Either the task was really simpler or my approach just fit way better. Basically I check every position,
 | 
				
			||||||
 | 
					whether it's an `A` and, if yes, I check the diagonals for `M.S` and `S.M `. Basically the whole implementation
 | 
				
			||||||
 | 
					worked on the first try. I nearly didn't want to continue after task 1, but this was a quick win after all.
 | 
				
			||||||
							
								
								
									
										117
									
								
								2024/day4/src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								2024/day4/src/main.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,117 @@
 | 
				
			||||||
 | 
					fn get_words_at(
 | 
				
			||||||
 | 
					    text: &Vec<char>,
 | 
				
			||||||
 | 
					    line_length: isize,
 | 
				
			||||||
 | 
					    num_lines: isize,
 | 
				
			||||||
 | 
					    top: isize,
 | 
				
			||||||
 | 
					    left: isize,
 | 
				
			||||||
 | 
					) -> Vec<String> {
 | 
				
			||||||
 | 
					    // the jump offsets to get to the next character in any direction. 0 entries are ignored later on, so we use them as markers when getting next to the borders
 | 
				
			||||||
 | 
					    let mut offsets = vec![
 | 
				
			||||||
 | 
					        1,                // right
 | 
				
			||||||
 | 
					        line_length + 1,  // down-right
 | 
				
			||||||
 | 
					        line_length,      // down
 | 
				
			||||||
 | 
					        line_length - 1,  // down-left
 | 
				
			||||||
 | 
					        -1,               // left
 | 
				
			||||||
 | 
					        -line_length - 1, // up-left
 | 
				
			||||||
 | 
					        -line_length,     // up
 | 
				
			||||||
 | 
					        -line_length + 1, // up-right
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    // remove invalid jump directions (because the word wouldn't fit anyway)
 | 
				
			||||||
 | 
					    if top < 3 {
 | 
				
			||||||
 | 
					        offsets[5] = 0;
 | 
				
			||||||
 | 
					        offsets[6] = 0;
 | 
				
			||||||
 | 
					        offsets[7] = 0;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if top > num_lines - 4 {
 | 
				
			||||||
 | 
					        offsets[1] = 0;
 | 
				
			||||||
 | 
					        offsets[2] = 0;
 | 
				
			||||||
 | 
					        offsets[3] = 0;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if left < 3 {
 | 
				
			||||||
 | 
					        offsets[3] = 0;
 | 
				
			||||||
 | 
					        offsets[4] = 0;
 | 
				
			||||||
 | 
					        offsets[5] = 0;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if left > line_length - 5
 | 
				
			||||||
 | 
					    /* don't try the final \n */
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        offsets[0] = 0;
 | 
				
			||||||
 | 
					        offsets[1] = 0;
 | 
				
			||||||
 | 
					        offsets[7] = 0;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    let mut result = vec![];
 | 
				
			||||||
 | 
					    for &offset in offsets.iter() {
 | 
				
			||||||
 | 
					        if offset != 0 {
 | 
				
			||||||
 | 
					            let mut string = String::new();
 | 
				
			||||||
 | 
					            for i in 0..4 {
 | 
				
			||||||
 | 
					                let index = top * line_length + left + offset * i;
 | 
				
			||||||
 | 
					                if index >= text.len() as isize {
 | 
				
			||||||
 | 
					                    println!("Offsets: {:#?}, current: {}, index: {}", offsets, offset, i);
 | 
				
			||||||
 | 
					                    panic!(
 | 
				
			||||||
 | 
					                        "Invalid index: {} = {} * {} + {} + {} * {}",
 | 
				
			||||||
 | 
					                        index, top, line_length, left, offset, i
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                string.push(text[index as usize]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            result.push(string);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn task1() {
 | 
				
			||||||
 | 
					    let input = std::fs::read_to_string("./input.txt").unwrap();
 | 
				
			||||||
 | 
					    let text: Vec<char> = input.chars().collect(); // makes the offset jumperoo easier in get_words_at
 | 
				
			||||||
 | 
					    let line_length = (input.lines().next().unwrap().len() + 1) as isize; // need to include the final \n to get the calculations right
 | 
				
			||||||
 | 
					    let num_lines = input.len() as isize / line_length;
 | 
				
			||||||
 | 
					    let mut count = 0;
 | 
				
			||||||
 | 
					    println!("Text has {} lines of length {}", num_lines, line_length);
 | 
				
			||||||
 | 
					    for top in 0..num_lines {
 | 
				
			||||||
 | 
					        for left in 0..line_length {
 | 
				
			||||||
 | 
					            count += get_words_at(&text, line_length, num_lines, top, left)
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .fold(0, |existing, word| {
 | 
				
			||||||
 | 
					                    if word == "XMAS" {
 | 
				
			||||||
 | 
					                        existing + 1
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        existing
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("Task 1: total: {}", count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn task2() {
 | 
				
			||||||
 | 
					    let input = std::fs::read_to_string("./input.txt").unwrap();
 | 
				
			||||||
 | 
					    let text: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut count = 0;
 | 
				
			||||||
 | 
					    for row_idx in 1..text.len() - 1 {
 | 
				
			||||||
 | 
					        for col_idx in 1..text[row_idx].len() - 1 {
 | 
				
			||||||
 | 
					            if text[row_idx][col_idx] == 'A'
 | 
				
			||||||
 | 
					                && (
 | 
				
			||||||
 | 
					                    // top-left-bottom-right word
 | 
				
			||||||
 | 
					                    text[row_idx - 1][col_idx - 1] == 'M' && text[row_idx + 1][col_idx + 1] == 'S'
 | 
				
			||||||
 | 
					                        || text[row_idx - 1][col_idx - 1] == 'S'
 | 
				
			||||||
 | 
					                            && text[row_idx + 1][col_idx + 1] == 'M'
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                && (
 | 
				
			||||||
 | 
					                    // bottom-left-top-right word
 | 
				
			||||||
 | 
					                    text[row_idx + 1][col_idx - 1] == 'M' && text[row_idx - 1][col_idx + 1] == 'S'
 | 
				
			||||||
 | 
					                        || text[row_idx + 1][col_idx - 1] == 'S'
 | 
				
			||||||
 | 
					                            && text[row_idx - 1][col_idx + 1] == 'M'
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                count += 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("Task 2: Total: {}", count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    task1();
 | 
				
			||||||
 | 
					    task2();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue