diff --git a/Cargo.lock b/Cargo.lock index 07cc225..76f3d59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "arrays" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dbdbb2877d26e0647c6b8125802b2ecf2dc2a28d864dde41e6f9b9a54da08fe" + [[package]] name = "bitflags" version = "1.3.2" @@ -104,6 +110,9 @@ version = "0.1.0" [[package]] name = "day06" version = "0.1.0" +dependencies = [ + "itermore", +] [[package]] name = "day07" @@ -246,6 +255,35 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "iterchunks" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb61464343bc874be283540bf6bb148d6e5b61023bc5acbb9f969b56c806780" +dependencies = [ + "arrays", +] + +[[package]] +name = "itermore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0331e230609e456fccf9d3b3d4f273a1b3f6b601ed37e943dc197fe5d24bb4da" +dependencies = [ + "arrays", + "iterchunks", + "iterwindows", +] + +[[package]] +name = "iterwindows" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbf3a88c019a9667dbea976f47cf797ffc8d765c53d893e60f27576be6333b0" +dependencies = [ + "arrays", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/day06/Cargo.toml b/day06/Cargo.toml index dcc1747..377f632 100644 --- a/day06/Cargo.toml +++ b/day06/Cargo.toml @@ -8,3 +8,4 @@ build = true app = true [dependencies] +itermore = "0.5.0" diff --git a/day06/input b/day06/input new file mode 100644 index 0000000..68bd997 --- /dev/null +++ b/day06/input @@ -0,0 +1 @@ +pjbjvjtjljplppjssvtvwtwptptztltbtrrjgrjrzrqrjrbrhbrhrlllbpbdbbzqqgsqshqssjjbsjbsbmbhhmchhrqrcqqbwbqwwqrrznnsbswwwdjwdwmmsvszzlbbgddbgdgfgttzjzrjzrjzzvrvqqgpqggtbgtgvvrhvhtvtjjbpjjfjhjbhbddbjjjmzmtmgmpgmmmljlnljjmpmbpmbmrrlhhlppdgdfgfbbqlbbtffjjgvvnpvpbpttqmmnhhgfgrrwhrrbnbznzccmbmvmmzszsvsbvbccsrslsjsbbtdtwtvttvpvzzvbzzwczwcczhzhwhjhjghgppgpgttdwdhwhphnppqmpqqhthcchdhmhnnbcnbcbbggbfblljttwsswspsggpjjzszcscsmcmdmnngzzhrzrbrhbhzbzvzgvgffnlnljlrrhchhsvhssmpmccncdnccgdgbglgtlggnllsvvpfvpfpbffsgglddjrrzzphhptprtppwrwffzllrbrmrpmpdmpdmpplpspcphcphhgmmqnmmvnmmdvmvsmmqjmmlmlbmlbmlltlptphpnncscbscbcggwhhgjgqjqmjmdjmdjdrrvgvvzlldgdnnvttmmpffdjjvvchcwwbhwbwzzlmlccrttcntccpcgccpgcpggdrrbtrthhlrrbqrrpspdsdldbldblbzbpbgggtngtgqqtwwdjjmmcrmcrcvclcddhllpzpdzzmccrtccfvffccfhccpscctbbbzqzvvllgwlgwgvwwjswjswsvvwhhvjvsjvjmmjhjrhrmrvrnrccmnmzzmdzzbtbvbqvvgzgcgvvvvlltvllbfbqqrppwhpwpffzddzdzwdzzrggmhmfhmhbbzjzsjzzhhjdhhdnndsnssnfffbmffwhwrhhmmbnnbrnrbrrtqtztnzzzzblbhbdhbbfmfqfmmsgszzvfzfmfwfnwfwggwngnqnwqnwqwvwqvwvdvrvjjfnjnmnfmmwzzltztjjqnnnmlmzlmmrcmclcqqhrhdhccdfdvfvccvtcvvdmmtmccwjjcbcrrjmrjrdrffgwwvbvlvsspwpsspzsschssmqsqmqmlqmmqgqfqcqjcjtthjttlddfvvwwjvvtpvvfsvffqnffznzqzszgzmmjttwztwzzhqqccqsqmqnmqqjhqhzhwhvhdddsndsdfftvffwlwnnmmdpmmnhhrqrrclcdlcddhcdcppgrprnpnptnpphgpbqfngdgzvgndwcgrwcsfmhzsvddhzbgjmvvdjjzswvgnpmvgdpwsgbgjzjpsrfdzdzjzzrpplbhsmgddqzjbdzdzltqqwqjzqvwfmcdppbdbprrwzhmnrqclzrnmdjnfbwmvdrwtpwvgscrqgpndqnzbjsbljcbthbpgdjdcdwfhpvjnbsfjdlrjldvvmtfdslrhlfwmvclqrljrqmmjgqfwmfgwdjzzptgcthvtgdswsqjrqvnzmtqldjjcqnfhtvbwhjqlvpptfwjrdpcwvzddgcjzvqbhtsnnnjqqmqlbgvqmvjhvvpbzcbdmhgmcjbfcccsvlzjztvjzrrlhtgwccdcgcptqlmdhmdhvqzfntbjqtsmvqgwsltqntgszllntrljfgfsghtbbcqrdgwqphmbqtzmjqccrgvqpqpchzjstdmmtvntwjqsbcqjgnhzlllcfbpgtgrhwwhqqdlgrlsbzbmchvjnsgpdnmqvtgwqjpgflqgfngjfcfwqzmvvgzmmhbgfnbzvzclwclqdcccgbrrzpwdtprgsvhbgsnbntgrvnzhrnzfzdmnlbnrbqvmjbwpgvjlhbcvsrlqmcsnlrvtfdwtvcbmlndgbctsnmtctjszlpddqmzbtphhhfznwbdfsgppmdmczmhmmrzpllfqqbgvlsrscpfgznhdhgrnnnvrchgvzlqbgvcfghjvlvrvpclfcshbmvglcfrjbzrbcjmjjrfgqthwfrqbgtjldmbnfwllspmwrvstvrltvrlvrtjvprgtgzjlrgclvjhqpfcwcdbdtzwdsdfrtsvtvgjmsszdfqlmhqqlzswjfndswlmhcrhglphvpnfjpbmggbwlmzjchpnrllbjpmgmzjjrqpqgsbrszqhdljcpnclvrvbntgtcdcmhtdhgslhpvdjpvrszfrjhsbvcvtfwvvgczprnpbhmnnlmctbtqdjspgvhvnhwvspwgnjvzllwlnjhfjwsslppmjbfbdnthcpzbcmnnbvhctgwgdvhvlrbltmdnlfcsncqgrmjprshdvvtvcccgzhszcjgczhmhtvmccjpchqshhdzjjhbfpzqdjszdhdvlmgctmwcjprwlsqbcqhlcrfdgnqzfdfvqslmqlppbsvbmjmfbrtdmpmtqvwvppcfzddjzhhzlrrnnhbrlhmzlqwftprfvctnfhfhfzrnrvggfqmqwcwszhtbfjncprgwcqbjlvtnrprlwwghswvprjmsbmqvwnnfggprndvshfvvwtrqjpwghgbppftgzhqjslfzhngwfsjnmjzdsjqgpmglwnjlcgmczgvndszrszcpnzqpbzjmgrfsbjlghwrbqsqdhlnhzsvsgbqhbcdffjlgrbdrrjvclzqpftlhdvvcrvlgvlpnjcqdcbdjtlwnldjhhhzrwsqlhlsztwrznfsszptlrhjmqwmnfwjtjwmmmtvwzhpmjgzgsscbddgvvhpcnhvnggzhbzvvjlmdftpbcsvtsttrvgghptmmcdclbdvmnsdntthfbdznbclwccnlzcvdwzrqgddjszvbdqcjppzrtpnrhfcvvwpjqczgqwzzzvzmlnlzqszvtllftthgwgftjzsndpzzcnqpcvmsdvvfrjdsvfclsqqhsjrrctfvdrlhfmhprjggdcmqrrbqtwnrllhhztvjgmzqszbvqfwsgllvhsvfrjffvdscwjzqlzlwdpgthddpgzjfdbdqpsnntwpslvsdpqfnsgcllszcjwvtqhwhpfrlfdgwrfmgfpjmvnstrmtfcvgwlqdfqvntltqtrmjjtwcthvwntqgvncssplnmvlnstlcphvlcmvjnstwldtntchcbmzmlzhgjfbrdlgzvqpgcndmfdnmcnwhmpdnpqstfddddcrpgrpfwfbzjqtnzwwqpzrqpmrjpfznrndfgwhtlvrcrphqfjzjbttwhgnsngqwvnsbvcqtjlmhvmnmnnmjcmlpnpgmrqsbmgljvsfqvrlljqzmzqqbgpvcrwdjmgsglssjswmnvtshhfqjhqmfmvcjwfpwsppgtrqsbhhcdljnjphnjszqpvdplbwzpwmmpwfhmhngtllzqvpmgdctmfqwwqjszssmjhwnrjdtmmvpdnwlqtcbpfcmwtbjmmsmmdpqgzdhsblgjmjbpzgqvqhnggtwmhztbbhlflllgwblncjjsngdgvsfdmsbsvlpnjjzqqbzhsqclmjnnmmwlpvtgwqmcgmrqdwdddlgbvhntbztbjnqhdlggnzwsdtdzprgddhtcttjrcpszgchtfwqjsdlnbntfwqpzpfsqrqjhthmcfszwtwcqwbvfzdnrrpmzjdrhsgmhfbsldvcrjdwvpqpszzlvbptljgvccqsdhhnztjpghbvhfptgplqdvldjzfthpspwvgljwnnndwrqzbrstnqbvrrcghssnrpvtrhmvcmbngwndzfswmgjwnnzqdcjhpthcgvthsnwqzrnzrvdjmctchhsbnrtvctzqfpcjhzmhnfjlqftbjztfbcppgmwvrzzrvlcpnpwwpvtcpdplrcfpgfqjtlfjtphhpcltwqcbqbznbtjrtdrpgtvzmgsclhpptrssqqbctdrftqzmwjmrmjtgmjmsnbnspjvcqpqnmgzgjrmfhghvsfsdqnbdjsbcpczsdswdcvhfzlgpzbtmztcnbpcvjnlcdmmlbtwzsfqtfnlrwjtwmgslcgptgbdsfwdhppvfwbbgdfdqtrbncbznmqtchzsdzlhlhjnnbpdvnnfjrdfbdqmvcb diff --git a/day06/input.test b/day06/input.test new file mode 100644 index 0000000..5a2b0a7 --- /dev/null +++ b/day06/input.test @@ -0,0 +1 @@ +mjqjpqmgbljsphdztnvjfqwrcgsmlb \ No newline at end of file diff --git a/day06/src/bitmask.rs b/day06/src/bitmask.rs new file mode 100644 index 0000000..5d58db5 --- /dev/null +++ b/day06/src/bitmask.rs @@ -0,0 +1,41 @@ +use std::ops::{BitAnd, BitOr}; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub struct Bitmask(u64); + +impl Bitmask { + pub const fn from_alpha(alpha: &u8) -> Self { + // 'a' is the LSB, 'Z' is MSB + if *alpha <= b'Z' { + Self(1 << (alpha - b'A' + 26)) + } else { + Self(1 << (alpha - b'a')) + } + } + /// Get the priority from a rucksack entry + pub const fn count_ones(self) -> u32 { + self.0.count_ones() + } +} + +impl const BitOr for Bitmask { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +impl const BitAnd for Bitmask { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self(self.0 & rhs.0) + } +} + +impl std::fmt::Binary for Bitmask { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:b}", self.0) + } +} diff --git a/day06/src/main.rs b/day06/src/main.rs index e7a11a9..f40d7a3 100644 --- a/day06/src/main.rs +++ b/day06/src/main.rs @@ -1,3 +1,108 @@ -fn main() { - println!("Hello, world!"); +#![feature(array_windows)] +#![feature(const_trait_impl)] +#![feature(const_ops)] +use itermore::{self, IterArrayWindows}; + +use std::{ + fs::File, + io::{BufRead, BufReader}, + ops::BitOr, +}; + +use bitmask::Bitmask; + +mod bitmask; + +#[derive(Debug, Default, PartialEq, Eq)] +enum SolvePuzzle { + First, + #[default] + Second, +} + +fn solve_puzzle(reader: B) -> usize { + reader + .bytes() + .map(Result::unwrap) + .filter(u8::is_ascii_alphabetic) + .map(|byte| Bitmask::from_alpha(&byte)) + .array_windows::() + .enumerate() + .find_map(|(position, window)| { + if window + .iter() + .copied() + .reduce(BitOr::bitor) + .unwrap_or_default() + .count_ones() + == LEN as u32 + { + Some(position + LEN) + } else { + None + } + }) + .unwrap_or_default() +} + +fn main() { + let mut args = ::std::env::args().skip(1); + let file = args.next().unwrap_or_else(|| String::from("./input")); + let solve = args + .next() + .map(|arg| match arg.as_str() { + "first" => SolvePuzzle::First, + "second" => SolvePuzzle::Second, + _ => unreachable!(), + }) + .unwrap_or_default(); + let file = BufReader::new(File::open(file).expect("Input file not found")); + let solution = match solve { + SolvePuzzle::First => solve_puzzle::<4, _>(file), + SolvePuzzle::Second => solve_puzzle::<14, _>(file), + }; + println!("{}", solution); +} + +#[cfg(test)] +mod tests { + use std::io::Cursor; + + use super::*; + + #[test] + fn first_with_example_1() { + let reader = Cursor::new(include_str!("../input.test")); + assert_eq!(solve_puzzle::<4, _>(reader), 7); + } + + #[test] + fn second_with_example_1() { + let reader = Cursor::new(include_str!("../input.test")); + assert_eq!(solve_puzzle::<14, _>(reader), 19); + } + + #[test] + fn first_with_additional_examples() { + let reader = Cursor::new("bvwbjplbgvbhsrlpgdmjqwftvncz"); + assert_eq!(solve_puzzle::<4, _>(reader), 5); + let reader = Cursor::new("nppdvjthqldpwncqszvftbrmjlhg"); + assert_eq!(solve_puzzle::<4, _>(reader), 6); + let reader = Cursor::new("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg"); + assert_eq!(solve_puzzle::<4, _>(reader), 10); + let reader = Cursor::new("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw"); + assert_eq!(solve_puzzle::<4, _>(reader), 11); + } + + #[test] + fn second_with_additional_examples() { + let reader = Cursor::new("bvwbjplbgvbhsrlpgdmjqwftvncz"); + assert_eq!(solve_puzzle::<14, _>(reader), 23); + let reader = Cursor::new("nppdvjthqldpwncqszvftbrmjlhg"); + assert_eq!(solve_puzzle::<14, _>(reader), 23); + let reader = Cursor::new("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg"); + assert_eq!(solve_puzzle::<14, _>(reader), 29); + let reader = Cursor::new("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw"); + assert_eq!(solve_puzzle::<14, _>(reader), 26); + } }