--- /dev/null
+use std::io::BufRead;
+
+type WordSearch = Vec<Vec<char>>;
+
+pub fn read_word_search<R>(reader: R) -> WordSearch
+where
+ R: BufRead,
+{
+ let mut word_search: WordSearch = Vec::new();
+ for l in reader.lines() {
+ word_search.push(l.unwrap().chars().collect());
+ }
+ word_search
+}
+
+const DIRECTIONS: [(i32, i32); 8] = [
+ (0, 1),
+ (1, 0),
+ (0, -1),
+ (-1, 0),
+ (1, 1),
+ (-1, 1),
+ (1, -1),
+ (-1, -1),
+];
+
+pub fn nb_of_word_occurences(word_search: &WordSearch, word: &str) -> i32 {
+ let mut n = 0;
+ for i in 0..word_search.len() {
+ for j in 0..word_search[i].len() {
+ 'next_direction: for (di, dj) in DIRECTIONS {
+ for (k, c) in word.chars().enumerate() {
+ let (pos_i, pos_j) = (i as i32 + k as i32 * di, j as i32 + k as i32 * dj);
+ if pos_i < 0
+ || pos_i >= word_search.len() as i32
+ || pos_j < 0
+ || pos_j >= word_search[i].len() as i32
+ || word_search[pos_i as usize][pos_j as usize] != c
+ {
+ continue 'next_direction;
+ }
+ }
+ n += 1;
+ }
+ }
+ }
+ n
+}
+
+const XMAS_CROSS_1: [(i32, i32, char); 5] = [
+ (0, 0, 'A'),
+ (1, 1, 'S'),
+ (-1, 1, 'S'),
+ (-1, -1, 'M'),
+ (1, -1, 'M'),
+];
+
+const XMAS_CROSS_2: [(i32, i32, char); 5] = [
+ (0, 0, 'A'),
+ (1, 1, 'M'),
+ (-1, 1, 'S'),
+ (-1, -1, 'S'),
+ (1, -1, 'M'),
+];
+
+const XMAS_CROSS_3: [(i32, i32, char); 5] = [
+ (0, 0, 'A'),
+ (1, 1, 'M'),
+ (-1, 1, 'M'),
+ (-1, -1, 'S'),
+ (1, -1, 'S'),
+];
+
+const XMAS_CROSS_4: [(i32, i32, char); 5] = [
+ (0, 0, 'A'),
+ (1, 1, 'S'),
+ (-1, 1, 'M'),
+ (-1, -1, 'M'),
+ (1, -1, 'S'),
+];
+
+const XMAS_CROSSES: [[(i32, i32, char); 5]; 4] =
+ [XMAS_CROSS_1, XMAS_CROSS_2, XMAS_CROSS_3, XMAS_CROSS_4];
+
+pub fn nb_of_mas_cross(word_search: &WordSearch) -> i32 {
+ let mut n = 0;
+ for i in 1..word_search.len() - 1 {
+ for j in 1..word_search[i].len() - 1 {
+ 'next_cross: for cross in XMAS_CROSSES {
+ for (di, dj, c) in cross {
+ let (pos_i, pos_j) = (i as i32 + di, j as i32 + dj);
+ if word_search[pos_i as usize][pos_j as usize] != c {
+ continue 'next_cross;
+ }
+ }
+ n += 1;
+ break;
+ }
+ }
+ }
+ n
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static WORD_SEARCH: &str = "MMMSXXMASM
+MSAMXMSMSA
+AMXSXMAAMM
+MSAMASMSMX
+XMASAMXAMM
+XXAMMXXAMA
+SMSMSASXSS
+SAXAMASAAA
+MAMMMXMMMM
+MXMXAXMASX";
+
+ #[test]
+ fn test_part1() {
+ let word_search = read_word_search(WORD_SEARCH.as_bytes());
+ let n = nb_of_word_occurences(&word_search, "XMAS");
+ assert_eq!(n, 18);
+ }
+
+ #[test]
+ fn test_part2() {
+ let word_search = read_word_search(WORD_SEARCH.as_bytes());
+ let n = nb_of_mas_cross(&word_search);
+ assert_eq!(n, 9);
+ }
+}
day03::execute_corrupted_program_dodont(&program)
)
}
+
+pub fn day04() -> String {
+ let f = fs::File::open("data/day04.input").unwrap();
+ let word_search = day04::read_word_search(BufReader::new(f));
+ format!(
+ "part1: {}, part2: {}",
+ day04::nb_of_word_occurences(&word_search, "XMAS"),
+ day04::nb_of_mas_cross(&word_search)
+ )
+}