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