diff --git a/data/examples/19.txt b/data/examples/19.txt new file mode 100644 index 0000000..29648be --- /dev/null +++ b/data/examples/19.txt @@ -0,0 +1,10 @@ +r, wr, b, g, bwu, rb, gb, br + +brwrr +bggr +gbbr +rrbgbr +ubwu +bwurrg +brgr +bbrgwb diff --git a/src/bin/19.rs b/src/bin/19.rs new file mode 100644 index 0000000..44bdecd --- /dev/null +++ b/src/bin/19.rs @@ -0,0 +1,140 @@ +use itertools::Itertools; +use std::io::{stdout, Write}; + +advent_of_code::solution!(19); + +#[derive(Debug, PartialEq)] +#[repr(u8)] +enum Color { + White, + Blue, + Black, + Red, + Green +} + +pub fn part_one(input: &str) -> Option { + let mut lines = input.lines(); + let patterns = lines.next().unwrap().split(", ").map(|p| p.chars().map(map_color).collect_vec()).collect_vec(); + let patterns_slice = patterns.iter().map(Vec::as_slice).collect_vec(); + let designs = lines.by_ref().skip(1).map(|d| d.chars().map(map_color).collect_vec()).collect_vec(); + + let possible_designs = designs.iter().filter(|design| { + is_design_possible(design, &patterns_slice) + }); + + + + Some(possible_designs.collect_vec().len() as u32) +} + +pub fn part_two(input: &str) -> Option { + let mut lines = input.lines(); + let patterns = lines.next().unwrap().split(", ").map(|p| p.chars().map(map_color).collect_vec()).collect_vec(); + let patterns_slice = patterns.iter().map(Vec::as_slice).collect_vec(); + let designs = lines.by_ref().skip(1).map(|d| d.chars().map(map_color).collect_vec()).collect_vec(); + + let possible_designs: usize = designs.iter().map(|design| { + print!("."); + let _ = stdout().flush(); + all_possible_designs(design, &patterns_slice) + }).sum(); + + Some(possible_designs as u32) +} + +fn map_color(c: char) -> Color { + match c { + 'w' => Color::White, + 'u' => Color::Blue, + 'b' => Color::Black, + 'r' => Color::Red, + 'g' => Color::Green, + _ => panic!() + } +} + +fn is_design_possible(design: &[Color], patterns: &[&[Color]]) -> bool { + // if the remaining design exists as a pattern, use that + if patterns.contains(&design) { return true; } + + // otherwise find all the patterns that satisfy the next step of the design and check if that is a workable design + patterns.iter().any(|pattern| { + // eg design = abcd, patterns = [bbbbb, a, ab,cd] will match 'a' and 'ab' + if design.len() > pattern.len() && design[0..pattern.len()] == **pattern { + is_design_possible(&design[pattern.len()..], patterns) + } else { + false + } + }) +} + +fn all_possible_designs(design: &[Color], patterns: &[&[Color]]) -> usize { + println!("Checking {} stripe design against {} patterns", design.len(), patterns.len()); + let _ = stdout().flush(); + patterns.iter().map(|pattern| { + if design == *pattern { + return 1 + } else if design.len() > pattern.len() && design[0..pattern.len()] == **pattern { + all_possible_designs(&design[pattern.len()..], patterns) + } else { + 0 + } + }).sum() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_all_possible_designs() { + let patterns = "r, wr, b, g, bwu, rb, gb, br".split(", ").map(|p| p.chars().map(map_color).collect_vec()).collect_vec(); + let patterns_slice = patterns.iter().map(Vec::as_slice).collect_vec(); + + let design = "brwrr".chars().map(map_color).collect_vec(); + assert_eq!(2, all_possible_designs(&design, &patterns_slice)); + + let design = "bggr".chars().map(map_color).collect_vec(); + assert_eq!(1, all_possible_designs(&design, &patterns_slice)); + + let design = "gbbr".chars().map(map_color).collect_vec(); + assert_eq!(4, all_possible_designs(&design, &patterns_slice)); + + let design = "rrbgbr".chars().map(map_color).collect_vec(); + assert_eq!(6, all_possible_designs(&design, &patterns_slice)); + + let design = "bwurrg".chars().map(map_color).collect_vec(); + assert_eq!(1, all_possible_designs(&design, &patterns_slice)); + + let design = "brgr".chars().map(map_color).collect_vec(); + assert_eq!(2, all_possible_designs(&design, &patterns_slice)); + + let design = "ubwu".chars().map(map_color).collect_vec(); + assert_eq!(0, all_possible_designs(&design, &patterns_slice)); + + let design = "bbrgwb".chars().map(map_color).collect_vec(); + assert_eq!(0, all_possible_designs(&design, &patterns_slice)); + + // let patterns = "wubu, brr, uru, uw, gug, rgrur, ub, rrwg, wrw, uugg, wwb, gwrg, rgb, bbrbgw, guwb, rub, wgww, wgu, bwbu, bgubwb, gbuu, buwr, uub, wubgr, uwugbwb, gwwbbwrr, rbgbgr, gbuuww, bur, gubgbr, wgug, rrb, wbrugwrb, brb, gbu, rrwrbgrr, uburgr, bbrgrwg, rbbb, gbr, grgug, rr, wrbw, uugbgb, bbg, br, rubbbu, bbggubb, brwwr, rgwbrr, ubr, wgugg, grrburw, r, uuwrwug, gguw, ww, bbrb, bguw, uurr, bru, ru, bwubwrb, wur, wrbgru, bbug, gbbrw, rwbu, wrwrr, bgu, wrgbur, ubugg, wb, rguw, ubbrgbw, buwurgb, wrwruuu, rgwwu, wwrbw, uwwwubb, wg, wrgwrwur, gwg, wbw, wgrg, ruurruu, uwu, bwwbuuug, rbr, urgbg, gugu, gwgwbgur, gbg, gbwu, uur, ggwbb, grub, gwrrw, uuu, rwr, urwbu, uwwbrwgg, gbb, guwg, urguu, urwgug, grwuwu, rwb, rbwwbg, grbuwu, bwbbbb, rbgr, rwrrur, gur, rwruwg, uuwrw, wbb, uug, rrbr, wrbbb, ggwgg, wrrur, bub, ug, guubgw, gwubb, wub, rruw, uruwwww, rrugwb, urbu, wbbu, bggr, urgr, brww, bwg, rggwgg, urr, bbbgwbbw, bwrgw, ugb, gwr, uwugwgu, bbgrubb, wbr, brg, ggg, ububww, grw, grr, wrb, gbuubg, gbuuu, b, ubgw, gurrurg, urwwr, bggug, rrg, guwbwrw, urw, bwrurg, rubww, bb, bubur, bgrwu, bwb, uwr, bwgw, g, bwrbwgbb, bgwguw, guugg, wuggrru, ugbg, wuwgrrw, wrbrg, gb, u, gwgg, gbwrgbw, rgw, gwuwwg, ubgu, rgu, ggb, brurgw, rbrbgwr, guuu, bwwu, bug, bbrggg, bwuw, wbuwwbg, uburbgu, gub, www, rwu, wrgbwg, bwggrruw, ubgww, gbw, wwbrw, wrg, brw, brbg, wwuggg, uuubgr, bgru, bbb, wgr, wurrwubr, rur, rgugwbru, bbu, wbuw, rubuubgr, urug, uubr, bw, buu, rbw, ggwb, rrr, gwrbu, gu, gw, rwub, wrwug, uubg, rrbgr, bbbwr, wurggw, wgg, urbg, rrwuu, bwgb, ruw, gwrw, ggub, gwwrrb, bwgbw, rrw, gwb, rwbbb, rwwu, gggg, gbgugggw, brrgww, rgbbw, wgrguw, wrr, uwuw, bwbbgbgr, grb, buurbbrb, wgb, ugburb, ururw, ggrgbgw, rgr, gg, wggwb, bwrgu, wgw, wru, brwbu, wbrrg, gugr, uggw, bg, gubrguu, ubu, bww, rrbwrrwb, bgrbwww, bbw, bwrwrr, uuuug, bwrwb, bwggr, rggbw, bbgg, rw, ggbb, ggugwu, ggu, ruuuggu, ggw, bgwwb, rrggww, gurwgrg, rrruu, ubg, rrgw, wggu, ruu, bgwru, wrrgw, buww, ubb, buwgu, bbgr, uggb, rbb, bubg, grg, bwr, bwbwwb, ugubgb, rrwub, rgbr, wbbug, ruwr, ubgrgg, bbrgw, rwgwb, buwrw, bbwrw, rwgr, wwrwgr, urgrrw, brrbbug, bwu, wuw, rgg, gww, bbrwrb, wruur, bbubu, bbbb, bwbrb, guu, wuggw, wwuw, wbu, rrrg, bgr, wwbbgru, rgubuugu, rgrr, bbuurr, ruur, brgwr, bwgwb, rgrww, ugw, wrwr, guuw, rrgr, wbgb, wug, wbg, rggb, uww, rug, wrub, rguwb, wbrgr, brbwbgu, wruw, rb, gwuug, ubru, gbbbrbg, rbg, ubgb, burg, bbwbrwbu, uuww, wgbg, wrgrrr, gru, wr, rgwr, rww, uruwbrru, gwgu, uwb, wbwrgr, uu, ur, gurrrg, ugrguu, gwub, gwgw, bbr, ugg, wwbg, wwr, rwubbw, urg, gubr, uwbwr, buw, bgwgubu, wwu, wurgbw, wbrwb, grwub, urb, rubgu, rwwrrrr, rg, brbb, bgb, uwg, ugwbbbg, grrwwbb, gwrrggr, rubb, wbrguw, uwurbg, grrgb, ubw, wuwuw, rbbuwg, rwg, urbuub, gwu, bgg, wbug, wgwbb, uggwugg, bu, ugu, rguu, wgrbgw, brrggw, grrg, gbww, wwubu, gbubrb, bgw, uurgw, wwbu, wwg, ggbr, gbbrb, buurr, ugr, rrbrggu, rru, ggur, gbggwub, wrrbbgw, ruuguw" + // .split(", ").map(|p| p.chars().map(map_color).collect_vec()).collect_vec(); + // let patterns_slice = patterns.iter().map(Vec::as_slice).collect_vec(); + // let design = "wguurwubgburbugwwuwrwwggrggubwrbwurrrrgbrbuggugurg".chars().map(map_color).collect_vec(); + + // assert_eq!(0, all_possible_designs(&design, &patterns_slice)); + + } + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(6)); + } + + #[test] + #[ignore] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(16)); + } +}