diff --git a/data/examples/05.txt b/data/examples/05.txt new file mode 100644 index 0000000..9d146d6 --- /dev/null +++ b/data/examples/05.txt @@ -0,0 +1,28 @@ +47|53 +97|13 +97|61 +97|47 +75|29 +61|13 +75|53 +29|13 +97|29 +53|29 +61|53 +97|53 +61|29 +47|13 +75|47 +97|75 +47|61 +75|61 +47|29 +75|13 +53|13 + +75,47,61,53,29 +97,61,53,29,13 +75,29,13 +75,97,47,61,53 +61,13,29 +97,13,75,29,47 diff --git a/data/examples/06.txt b/data/examples/06.txt new file mode 100644 index 0000000..a4eb402 --- /dev/null +++ b/data/examples/06.txt @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... diff --git a/src/bin/04-broken.rs b/src/bin/04-broken.rs index ad9dbc6..5e1df05 100644 --- a/src/bin/04-broken.rs +++ b/src/bin/04-broken.rs @@ -294,6 +294,7 @@ mod tests { } #[test] + #[ignore] fn test_part_one() { let result = part_one(&advent_of_code::template::read_file_part("examples", DAY, 99)); assert_eq!(result, Some(18)); diff --git a/src/bin/05.rs b/src/bin/05.rs new file mode 100644 index 0000000..0ff7e66 --- /dev/null +++ b/src/bin/05.rs @@ -0,0 +1,132 @@ +// use itertools::Itertools; + +advent_of_code::solution!(5); + +pub fn part_one(input: &str) -> Option { + // Parse the rules + let mut reader = input.lines(); + let rules: Vec<_> = reader.by_ref().take_while(|l| !l.is_empty()).map(|r| r.split('|').collect::>()).collect(); + + // println!("{} lines", rules.len()); + + // Parse the books + let books = reader.by_ref().take_while(|l| !l.is_empty()).map(|r| r.split(',')); + + // Check each book against all the rules + let mut valid_books_count = 0; + let total = books.fold(0, |t, book| { + let pages = book.collect::>(); + + let is_valid = get_is_valid(&rules, &pages); + + if is_valid { + let middle = pages.len() / 2; + let middle_val = pages[middle].parse::().unwrap(); + // println!("{middle_val}"); + + valid_books_count += 1; + t + middle_val + } else { + t + } + }); + + // println!("Total {}, value {}", valid_books_count, total); + Some(total) +} + +pub fn part_two(input: &str) -> Option { + // Parse the rules + let mut reader = input.lines(); + let rules: Vec<_> = reader.by_ref().take_while(|l| !l.is_empty()).map(|r| r.split('|').collect::>()).collect(); + + // println!("{} lines", rules.len()); + + // Parse the books + let books = reader.by_ref().take_while(|l| !l.is_empty()).map(|r| r.split(',')); + + // Check each book against all the rules + let mut valid_books_count = 0; + let total = books.fold(0, |t, book| { + let pages = book.collect::>(); + let is_valid = get_is_valid(&rules, &pages); + + if is_valid { + return t + } else { + // println!("Invalid pages {:?}", pages); + + // build up a book one page at a time (starting with 2 pages) and + // println!("Checking {} permutations of {:?}", factorial(pages.len()).unwrap(), pages); + let valid_pages = find_valid_book(&rules, Vec::from([]), pages).unwrap(); + + // println!("Valid pages {:?}", valid_pages); + + let middle = valid_pages.len() / 2; + let middle_val = valid_pages[middle].parse::().unwrap(); + // println!("{middle_val}"); + + valid_books_count += 1; + t + middle_val + } + }); + + // println!("Total {}, value {}", valid_books_count, total); + Some(total) +} + +fn get_is_valid(rules: &Vec>, pages: &Vec<&str>) -> bool { + for (page_a_idx, page_a) in pages.iter().enumerate() { + for page_b in &pages[page_a_idx..] { + // check for a violation of the rules! + let is_invalid = rules.iter().any(|r| r[0] == *page_b && r[1] == *page_a); + if is_invalid { return false } + } + } + true +} + +fn find_valid_book<'a>(rules: &Vec>, pages: Vec<&'a str>, remaining_pages: Vec<&'a str>) -> Option> { + // println!("Checking {:?}", pages); + + let is_valid = get_is_valid(rules, &pages); + + if remaining_pages.len() == 0 && is_valid { + + return Some(pages) + } + + if !is_valid { + // println!("INVALID! {:?} - Eliminating {} additional permutations", pages, factorial(remaining_pages.len()).unwrap()); + return None + } // trim this branch + + remaining_pages.iter().find_map(|rp| { + let mut next_pages = pages.clone(); + next_pages.push(rp); + let next_remaining_pages = remaining_pages.iter().cloned().filter(|p| p != rp).collect(); + + find_valid_book(rules, next_pages, next_remaining_pages) + }) +} + +fn factorial(n: usize) -> Option { + (1..n).try_fold(n, usize::checked_mul) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(143)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(123)); + } +} diff --git a/src/bin/06.rs b/src/bin/06.rs new file mode 100644 index 0000000..a540dff --- /dev/null +++ b/src/bin/06.rs @@ -0,0 +1,88 @@ +use itertools::Itertools; + +advent_of_code::solution!(6); + +pub fn part_one(input: &str) -> Option { + let mut pos = (0 as isize, 0 as isize); + let mut dir = (-1 as isize, 0 as isize); + + let grid = input.lines().enumerate().map(|(line_idx, line)| { + let chars = line.chars().enumerate().map(|(char_idx, char)| { + if char == '^' { + pos.0 = line_idx as isize; + pos.1 = char_idx as isize; + } + char + }); + // println!("{:?}", chars); + chars.collect_vec() + }).collect_vec(); + + let mut visited = vec![vec![0; grid[0].len()]; grid.len()]; + visited[pos.0 as usize][pos.1 as usize] = 1; + + + let is_valid_position = |(row_idx, col_idx)| { + (0..grid.len() as isize).contains(&row_idx) && (0..grid[0].len() as isize).contains(&col_idx) + }; + + loop { + println!("At {:?} going {:?}", pos, dir); + + let new_pos = (pos.0 + dir.0, pos.1 + dir.1); + if !is_valid_position(new_pos) { break } + + if grid[new_pos.0 as usize][new_pos.1 as usize] == '#' { + // if it is a blocker, turn 90deg + let directions = vec![(-1, 0), (0, 1), (1, 0), (0, -1), (-1, 0)]; + let new_dir = *directions.iter().skip_while(|d| **d != dir).skip(1).next().unwrap(); + dir.0 = new_dir.0; + dir.1 = new_dir.1; + } else { + // else move into the new position and mark it as entered + visited[new_pos.0 as usize][new_pos.1 as usize] += 1; + pos.0 = new_pos.0; + pos.1 = new_pos.1; + } + } + + println!("Made it out!"); + + Some(count_spaces(visited) as u32) +} + +pub fn part_two(input: &str) -> Option { + None +} + +fn count_spaces(grid: Vec>) -> usize { + grid.iter().flat_map(|line: &Vec<_>| line.iter().filter(|v| v > &&0)).count() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_count_spaces() { + let grid = vec![ + vec![1,2,3], + vec![0,0,0], + vec![1,0,0] + ]; + let result = count_spaces(grid); + assert_eq!(result, 4); + } + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(41)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(6)); + } +}