diff --git a/2020/Cargo.toml b/2020/Cargo.toml index 4241ac1..4908ae6 100644 --- a/2020/Cargo.toml +++ b/2020/Cargo.toml @@ -13,3 +13,6 @@ aoc-runner-derive = "0.3.0" regex = "1.4.2" [dev-dependencies] pretty_assertions = "0.6" + +[profile.release] +debug = true diff --git a/2020/input/2020/day24.txt b/2020/input/2020/day24.txt new file mode 100644 index 0000000..64b1db4 --- /dev/null +++ b/2020/input/2020/day24.txt @@ -0,0 +1,349 @@ +sewnwwwswnwnwwneneeenwwseswseww +nwwseneswnwsenwwweseneenesenwwwnw +seswewnwnesewneneneseseswwsesesesesenew +sesewnwwwswesenwswswneswswswwwnew +nwswenenwswenwnwwnwnwnw +wwswwwswwnwwe +wewnwsenwswnenwneneesenwwswsene +nenwnwnwnenwnesewnwnwnenwnene +nwewwwnwnwnwswwnw +nwnwseesewswsenesenesesewswseseseeswe +swnweseseenwseeswewneeneswewesesenw +enwneneeswneesewneneneenwnwneeese +senwswseesesesenwswseswsenwneseseseswsese +seswswnewneswswseneswsweswsw +swnwnwnwnwnenwwnwnwenwnwswnenwsenwnwnw +nenesesenenenenewenwneneneneswnewnwne +seweeeseewseseewseewwneeee +nwwwswwewwwswnwswswewswwsw +nwnwnwsesenwnenenwnwsesenwnwnwnwenwswnww +wesewsewswneneesenenenwnenwwnenwnwnw +nwnenwnenenenenenwnwsenw +wesweeswenwenweeenweswsenweew +senwswswnenwwsweneswweswwswenesew +nwwnwenesenwnwnwnenesenwsenwnenwwnwesw +newnwenenenwnenwsenwnenwnenesenenesese +seswnewnewnwswewnwswwwnenwsweeeww +nenwnenenwnwnwnenwnwnwneseswne +enwswswswenenwwswswneswse +wwsenwsewnewnwswnwsweswewwwwsw +eseeneewnwwnwneswneweeeeesee +swwneswswesenwnenwnwsenewwseseeswseene +wwswneswswswswneswswswswsewswswenesesw +nenenenenenenenenenenenwnesene +nwwnweswnwwwswenwswswwwswswwneeese +swneswnwseseseswswswweseswswswnweswewsw +weseseeswesenwseeeeseesenwesene +wswswseewnewswwneneswseneswwseswsese +wswnwneeenenenenenesenenenenenenwsenene +neneneneneswnewneeswnenwneeeenenene +swseswsewseswwsenwswneseswswseeseswsw +wswswswnesweswswswswwewnewswneseswswsw +nwsenesesesewweseseswnesewswne +sewswwnenwneneseeneesw +nwwnwnwnwswnwwnwnwwwnwne +enwsewneweeeseeeseseseeseeee +seswneewneenenewneneneneneswnweswne +seswseenesesewswswswsenwseesenwsesesw +swnwwnwnwnwnwnwwswswnwnenwenwnwenwnww +nenwnwnwwenenwswswnwnwnwnwenwnenwnwne +nwsewsenwneswsenwsenenwwnwnewswsenwe +wneenewwnwseneeseseewwseswsesese +swswneeeseesenwneesweneseesesenwsww +wnwsweswswwnwswwswswswnesewseswswnwew +swsewsesesewswneseswswswsenwneewnwe +nenenwnenwnenwsewnwnwnene +neseswswwwnwseenwswswwswwwese +enwnewwswwesenwnwnwswnwnwwwnwwnww +nesewnenwwswnweenenenwnenenene +wnwseeneseswnwnwsese +wewswsewwnenwwsenwwwnwwwwnw +wsesewsenesesewesenweseswseseseneneswse +eeswswsenwnesenewne +wseseswswswswswswswwenewnwswnwswswne +wswswswswewwwwswenwewwswnwswsw +enwnwneseswneeneswneeeeneneeswenenw +nenwewnwnenwnwnwnenwswsenwenwnwwnw +swnewseswseseseseesesesenwnwswenwsew +seewwwwwnewswwwnwwwnwnewnenwnwse +neswenweneneseeeneewneswneewneenesw +nesenwsewnwsenenenwwswnw +sesweeeneseneeneenwweenenewwsene +neneneeswnewneseswnewenenwewnenene +swneneswwwsenwnesenwnwwwnewnwnwww +nwenenwnwnwswwnwwnwnwsesenwsenwnwsenenw +seseseseseswsenwseseseseseneswnwsesewsw +nwswweswswnenewneswswswewswswswese +seeneseswseeeeesewseseenwneeswesw +seseeswswsesesewsesenwseesesesenwsese +nwsenwnenweswswenenwswesenwnesenenene +nwnwnwnwnwwsenwswnenwwnwnwnenwnwsenwsene +nenwnwwseneenwnwsw +eeeneeeeeseswe +neneesweneneseswnenwneneseneenewnwwe +wswneneneswswswseswnenewswswswswswswsw +neswswseswewswnewswswewswnwwswswenw +wwwseneweswnesesweseseswneswseese +wneeswenesenweneweneeeswnwswseene +wseneseneswnwneeneenwnenenenewnewne +nwsenewenenesewwnese +sewwnenwewwwsewswewsewwnewwww +seeeenweneswnwswseswnwnwwswswenwne +senwwwnwenwewnwnwewnwwwesenwenw +neswnewseenenewsweeesewnwenenwe +seneneswseweewnwnenwseweneneewnew +swwswnewnweseseswwwneweeneneseswwne +sesenewswswseseseseseneswwse +swsenwnenwwnenenenwnenee +sweeweenweeeswenwee +swsenwneseswewsesesewesenwsenweesw +swwsewswwswwswwwswswnwsw +eswnwneseswneneenenesw +newswsenwesewwwwwnenwswnwnwenwnwnw +seeseseenwseneenwneeesweeswewesw +seeeseswesesewsesenweeenwseeeesw +nenesenewnenewnenewwswneseseseenwnene +swwswneswswswwswwsewsw +sewesweeseeseneeeeee +seseswswswnewnwewsweseneswswsesewwsw +wnesenesweeenenenenenenwewnenenesw +nesenewwnwwneswnwnwsenwsewnw +enwwswnwwwwnwnwwnww +sewneeeseseenwnwnwseswseseseeseneese +eseseseseswneseseenenweseswseswe +swsesesenwneswswwneseeseeswwnwswswse +swnwneseseseswseseswseseseseseswnesewsw +nwswwwseesweswwswwne +sewnwnwwsewsewsenenwnwnwwnenwwnwwesw +wwwnwwnwnwswwswwnwwnewwe +seswnwenweswewnwswseneseswneewnww +seseseseseneseesesesesesenwsewsewsese +swwsesenwswnwswnwewnwnwnwnenwnwnwnwwne +senwseeeeeeseeseewsese +swswenewswswneseseswseswnwswneseswww +neneneneseneneeneneneneswneswnwenwesene +swseswseseseneesenenewewwseeswnenew +swnwnewwwwwwsewwweswwwneww +wswswnwswwwswneseswswswswwswseweswsenw +enwswnwnesenwnwenwenwswneneswnwnwnww +eneesweneneneeswnwne +wnwwewwnwwnwwwnese +nwwewneseeeswenwseswswswswsenwwswnwsw +wnwnwnwwnwnwwwwwnesew +wnwswseeswenewww +nwnwnwnwnwwnwseswneenwnenw +enesweeneseeeweenwseneswwswee +sewwwswneswnwsewswsw +neseseswneswwswswseseswneseseswseswswse +eseswswswswnwswseswswswse +eeseswnwswswseenwwseswnwseneseswsene +wwswneneswsewwneswswseswseswwwwnw +newswwsewneeneseeseseewsewnwweswse +nwnenwnwnwnenwnwnwwnwswnwnwnwnwsweenw +neneenesewnenewsenenenenwswwneenenese +neneseneneneneneneseeneneneswwnenewnene +nweswnwseswsweeeeenenenwsweseweese +swneswseswswswnwseseswswswswnwseeswwsw +wnwsenwwnwsenwwswnenwnwwnwenenewsenesw +nweseseeswsweesenweswnenweseseee +wswnenwnwnwsenwwenwnwseenwswnwnwsenwnene +nwnwnewnwnwnwnwwnwswnwnesweswsenwnwnww +neweewenenwneeeeneeseseswseenew +weweesweseneeswwseenwnwnewneee +wnesweneeeneseenwwwseenesweww +wnewseneneswswseswswwnesenwneswnewsenw +seswnwewsewswswswwnenwswsene +swswwnewswsewswweswswneseswswsw +nwewsweeneneneneswnww +newneweneneneswneneneneneneeneeseswne +nenwewnewseswnewneeswswseesenenww +seswswswneswswwswswswseneswneseneswsesww +nenenenenenwneeneseeesweneswsenwnenwww +eeneeeeeneeenesweesw +swwseneswsweswseswwseswseswneseswsenewse +seenweneeswwwwswnenenewneseneene +swswneswswswsewseseneseswweeenwwnwswsw +newnwswnewwnewwsesenwswnw +weneswswnewnwsenwswnenesenwnenenwnene +sesesesweseweswsewsewenwseesenwse +nenweenwwnwwsewnwwswnwnesenwwswsw +swnwswnwseneneseseswswseswwswsewneswswsese +nenwnenwenenesenwnenwnwswnwne +nwswswweseswswneswseew +eeswseenweeeseweseeeesee +sewwswswswseneswsweseneswswswneseswwsw +ewewnwsweeenesweeneseeswneenwe +neneswesenwnwsweeseswnwswwswnwewesw +neeneneeswenweeeeneneee +nenesesenenwnwnwnesewnwneneneswnenwnenwne +seseseneweneswwseseswsenwseseseswsese +sewsewneewewnwswwwneww +seseseseeseseswsenwsesesenwsenwseseee +sewwwwneswwesenwwwswswswww +eneeswneseweeweeewenweeene +swswnwswsweswswseseseswse +seseseswsenwswseseseeseswsesesesenwe +nenenewnenwnenwneeenenwnenwneneneswse +eseeeeeenweeeeee +wwwwnwwnewnwsewswwswneweesesew +seenewwneneneseeeneneenenenewnene +seswswneneeenwswwnwenenewnenenenesene +eeewneseeeswseenweewseewee +eeeewsweeenwnwweeseeneenenew +nwneswswnenwnenwnesenwnwwnwneswnwseswsew +nwsweeneeneseeenewnwnwneneswneswne +swsesewseseesenenew +nenesweseeeeewesweeesenwseee +nwnwenwwswsewswwneenwwnwsewseene +enwneneneswneeneneneswnenweeneswsene +swswwswswneswseswswwwswswsw +swswswswseswseneeswnewswwsesese +wseeswesenenwenenenwneeneweeswnee +eseenwseeseenwnwsweseseesesenw +sewswseseeseseseneseswsenesesewsesesw +swswnesenenwnewseewsweswneswwswswswse +sewwswseswnenwwewwswwwsewwnwswnwnw +nwnwnwenwwnwnwnwsenenwnwnw +swwnwsweswseeewnewwwnese +swwenwnwnwwswseeewnwnwwewswnenwne +seseneesenenwswnewwseesewseeswsese +swsesweeswnesewweeneswwswwswseswne +wswsewwwswnwwwnwwnenewwwseewnw +eewswnesenwswnwnewseeswnwnwnw +nwwwnewwewnwnwwnwnewwnwewswsw +sesewneswneenwseswseesese +neswweneeenesweneenesenewne +nwwnwseswswnwnwnenwnweswnwswnwwweenw +enwnenwnewenwnenenwnwwnene +neswnwnenenwnwswenenwnewse +nwweneenenewswneswnwenenesenwnewnw +neeswsewswnwnewswswswsesewnwneseswswsw +senwneswwnwnenenwnenenesenewenenenenene +sesewneswswsweenwsesweswnw +ewneesewneeeenesenweswnesesweee +swsewwwwnwwwewnenwsewwwsewwnene +swswnwseswesesweswneseswswseswswnwswnwswse +swseswswneseeseswneswenwneeswwnwswnww +weeswswnwswswswnwnwswswsweeswswswsww +nesewnwswseswwenweweseeeswnesene +sweseswnesenwseesesweneeswsesenwnesw +nwseeswseseeneswseswnwsweswseswsewse +sesewsesesweseeneenwesee +seneesewswewswnwsesw +seseseeseseseesesewseenenwnwsesesee +wneeeseseewswswseewnesenenwesenw +eneneeeneewneeenee +eneneneenenenewnenenesenwwnesw +eeeeeseeeenwe +nwnwnwnwnwenwnwnwnwwnw +seenwnenwswsenenwnenenewnenwnenenwnwnw +swenewweeeneseneneneeenweewnesw +nwnwnwnenwnenwnwnwnwse +seswswseesewswwseswneswswseenw +senewsewswnwewneswsewneenewwswsw +nenenwenwnenwswnenwnwne +nenenenenenwnenenewneneneswenene +eseneseseseswseseseseeee +wseseeneeseswseseseseenwwsewseswse +enwneeneneeneeseweeeeeewnesw +swswswswswswenwneswswwswswswneseswswe +eeeeeweneeee +wswswswnwewswswnwnweswwwswweswwse +nenenewnewseneneesweenweeneneeene +nenwneseswnwnenenewsesenenenwnesenewsenene +wswsenwswswseseswsenewneneseseseswswsese +nenwnwneenwswnwenwnwnenwnenwnwnwnewsw +nwnwwwnwwwwwneswnwwww +senweneswseeseweeseeewenewseee +eseseeeweesesesesesee +senenwnenwnewneeswneseenenwswseneneswne +nenwnenenewseneenenesesenenenewnenene +wnwnenenenewnenwwsenewseeseeswnenw +nwnwswwnesewnweewswnenwenenwnwwene +senwnenwnwnwnenwwnwnwnwwnenwesenwnwnw +seeeeeenwswswesenwnwsewesew +newwswnewsenwwwswwwenwnewwww +neneswnenwseewneneneneneneneneesenewnw +eneeesenewseneweswneeneneeenewe +seesewseeesesenwnwnwsweseseswsesesesee +enweseeeeenweseeswnwseewseeese +eswneeeeeeeenweneeeeesw +senwseseswseseeneseeseseseesewswnewe +nwnwnwenwsenwesenewnwswnwswnwnwnwnwnwnenw +neeneeenwsweeeenwsesweneneeewe +sweenenenewwneneneneenenenene +enweeeeeeneneeneneese +eneeseswsewsenwneswsweseswneeesenesw +enwwnwswnwnwwwwnwewnwwsewnwnwnw +wnwwwnwwewswnww +nenwneeswweswnesweneneeeswswewse +eswweseeseneenweneeewenwe +eswswswnweswswsweswswwswswnwsenewswnwne +swwseweneeeeweseeseesenenw +eeeeeenesweseeeeswnesweenwe +swwswneswwswwwswnewswwwewwswnw +nwneswnwswnenenwneenwnwenwnwnwnenwew +newwnwsewsewnwwweneswswnwwnwnew +neesweswswnwseswwwwwswneneswsenwwww +wswnewwwwwswneseswnwneneswwswwsew +eneswwwswnewwswswweswwwwswnwnenw +eswseneseswswsewseseswseseswseswswnwne +eeeeeeeeeeewswenenwee +sewnenenenewnwnwseeenwseswswweee +nenenenenenwseseneneneenenewneswswwnwnenw +wswswnwswnwseswseneswswswnewsweswsesw +eeewnenwneswwseseneeswseesewww +wsesweswswswswswswswswswswswnwwnwswenw +nwseswswswwswswsene +sewwwswwnwswswwnewswwnesewsesww +swwswswswswswswwswsenwne +nwnenwnwsewwnwwnwnwnwnwseww +swewseewnwenweseseneswnwenwsweesee +eeweswswneneenwesweneeeeseee +wseseseesesenewnwnesewswseseseesee +wswwnesewwnwwwnwseneswwwwew +nwwnenwwswnwweseeeswseseneenwwnwne +sewwwnwwsewwnwesesewswnwnwwnewe +newsesenwwsenesesewwneseseseseseneseesw +sweweseneseswnwswweswseswnwswnwnwsww +swsenenwnwneswnwnenwnenwnenenwnwewnw +swswwewwswsewewwwsenwwwnewwww +nenwsenwnwswnenwnenenwsenenwwnwnesenwne +seseseeeesewswnesesenweseseneewse +esesenweswseseneweeseseesesesee +wwswsewwwnewenewwwwwwnwnww +nwneseneeseeeseswnewseeswse +nwneneneeneenenese +eswseeeseesenweesesenwweewsesesese +wneweseswswnwswneneeeeene +nenewnwnenenwswsenenenesenwswneswswnenenw +sewnenwseswsesenwswnenenwnwnwnwnwwenw +nwnwnwenenwnwnwnwswnenenwnwsewnwsenwse +sesenewwnenwwnwwneswwswnwewenenwsw +neneewnwnesenwnwnenewneswnenwnenenwenw +neseenweneswnwnwneswwnwnwnwnenenenwnenw +nenenweswwneswnwnenenenweneenwswnene +swnenesenenenenenenenenwnenenwene +wneswnenwswwswseenwwwwwsew +sewwwnenewwwwwnesewwwswsewwne +nesenwneenesweeenwenene +seseeseeeswsenwseseeseseesesewsenw +nwnenwnwneneeenwswnenwswnwswneenwnwnwnenw +seneneeesweewesewwsewwnewee +nwwnenwsewnwwnwnwnwenenwnwwsewsenwnw +wswwwwwwswswsewneneewseenenwnw +nwseeswesesesesenwseenweeeeeeesw +seenewnenwswsenwnenesewnwswsenwnewnenw +wnwnewseswneeneeweenwnenweenese +swswsweenwnesenwswwneswseswwseneswse +nwesenenwnewneenwnwnwnwneswsesenwnwnenene +enenewneneneneneswewswneeneweneese +nwwwnwsenwnwwwnwwnwnenww +nwnwwnwnwnwnenwnwnwnwseswnwnwnwnew +swnewnenwneswenesenenwneewneneswnenesw +nwsewnwnwwnwswnewnenwwnwnwse +seneneswneneewnenwnenenewneswenenwsene +sweseneeeenewenenenweneenewene +enwwwwwwwnwwwsewwwswnewsene +sewewseswwsenwnwwesewewwwwnenew +nenwnwnwnwewnwsww diff --git a/2020/input/2020/day25.txt b/2020/input/2020/day25.txt new file mode 100644 index 0000000..4b4f611 --- /dev/null +++ b/2020/input/2020/day25.txt @@ -0,0 +1,2 @@ +12092626 +4707356 diff --git a/2020/src/day22.rs b/2020/src/day22.rs index 36a9976..533b615 100644 --- a/2020/src/day22.rs +++ b/2020/src/day22.rs @@ -372,6 +372,8 @@ use std::collections::{HashSet, VecDeque}; use aoc_runner_derive::aoc; +use crate::debug_println; + #[derive(Clone, Debug, PartialEq)] struct Players { p1: VecDeque, @@ -402,10 +404,6 @@ fn deck_to_str(deck: &VecDeque) -> String { s } - -macro_rules! debug_println { - ($($arg:tt)*) => (#[cfg(debug_assertions)] println!($($arg)*)); -} use std::sync::atomic::{AtomicUsize, Ordering}; static GAME_NUM: AtomicUsize = AtomicUsize::new(1); impl Players { diff --git a/2020/src/day23.rs b/2020/src/day23.rs index 5295a85..cca046a 100644 --- a/2020/src/day23.rs +++ b/2020/src/day23.rs @@ -71,17 +71,250 @@ //! //! Using your labeling, simulate 100 moves. What are the labels on the cups after cup 1? +//! --- Part Two --- +//! Due to what you can only assume is a mistranslation (you're not exactly fluent in Crab), you are quite surprised when the crab starts arranging many cups in a circle on your raft - one million (1000000) in total. +//! +//! Your labeling is still correct for the first few cups; after that, the remaining cups are just numbered in an increasing fashion starting from the number after the highest number in your list and proceeding one by one until one million is reached. (For example, if your labeling were 54321, the cups would be numbered 5, 4, 3, 2, 1, and then start counting up from 6 until one million is reached.) In this way, every number from one through one million is used exactly once. +//! +//! After discovering where you made the mistake in translating Crab Numbers, you realize the small crab isn't going to do merely 100 moves; the crab is going to do ten million (10000000) moves! +//! +//! The crab is going to hide your stars - one each - under the two cups that will end up immediately clockwise of cup 1. You can have them if you predict what the labels on those cups will be when the crab is finished. +//! +//! In the above example (389125467), this would be 934001 and then 159792; multiplying these together produces 149245887792. +//! +//! Determine which two cups will end up immediately clockwise of cup 1. What do you get if you multiply their labels together? + use std::fmt; +use std::ops::{Index, IndexMut, Range, RangeFrom}; use aoc_runner_derive::aoc; -struct Hand { + +use crate::debug_println; + +trait Hand { + fn play(&mut self, rounds: usize) { + use std::time::{Duration, Instant}; + let start = Instant::now(); + let mut last_report = Instant::now(); + (0..rounds).for_each(|i| { + debug_println!("-- move {} --", i + 1); + if last_report.elapsed() > Duration::new(1, 0) { + let elapsed = start.elapsed(); + let runtime = elapsed * rounds as u32 / i as u32; + let eta = runtime - elapsed; + + println!( + "{} steps ({}%) in {}s, Estimated runtime {}s, ETA {}s", + i, + 100 * i / rounds, + elapsed.as_secs_f32(), + runtime.as_secs_f32(), + eta.as_secs_f32(), + ); + last_report = Instant::now(); + } + self.step(); + }); + } + fn part1_answer(&self) -> String; + fn part2_answer(&self) -> usize; + fn step(&mut self); + fn test_cur_to_end(&self) -> Vec; +} + +#[derive(Debug)] +struct TargetCup { + val: usize, + idx: usize, +} + +#[derive(Debug)] +struct FastHand { + idx_to_val: Vec, + val_to_idx: Vec, + cur: usize, + min: usize, + max: usize, +} + +impl FastHand { + fn new(s: &str) -> FastHand { + let data: Vec<_> = s.bytes().map(|s| (s - b'0') as usize).collect(); + let min = *data.iter().min().unwrap(); + let max = *data.iter().max().unwrap(); + let mut idx_to_val = vec![0; data.len()]; + let mut val_to_idx = vec![0; data.len()]; + data.into_iter().enumerate().for_each(|(idx, val)| { + val_to_idx[val - 1] = idx; + idx_to_val[idx] = val; + }); + FastHand { + idx_to_val, + val_to_idx, + cur: 0, + min, + max, + } + } + fn new_part2(s: &str) -> FastHand { + let mut data: Vec<_> = s.bytes().map(|s| (s - b'0') as usize).collect(); + let min = *data.iter().min().unwrap(); + let mut max = *data.iter().max().unwrap(); + data.extend(max + 1..=1000000); + max = 1000000; + let mut idx_to_val = vec![0; data.len()]; + let mut val_to_idx = vec![0; data.len()]; + data.into_iter().enumerate().for_each(|(idx, val)| { + val_to_idx[val - 1] = idx; + idx_to_val[idx] = val; + }); + FastHand { + idx_to_val, + val_to_idx, + cur: 0, + min, + max, + } + } + + fn destination_cup_idx(&self, skip_vals: &[usize]) -> usize { + let mut search_val = self.idx_to_val[self.cur] - 1; + while skip_vals.contains(&search_val) { + search_val -= 1; + } + + if search_val < self.min { + search_val = self.max; + } + while skip_vals.contains(&search_val) { + search_val -= 1; + } + + self.val_to_idx[search_val - 1] + } +} + +impl fmt::Display for FastHand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (idx, val) in self.idx_to_val.iter().enumerate() { + if idx == self.cur { + write!(f, "({}) ", val)?; + } else { + write!(f, "{} ", val)?; + }; + } + Ok(()) + } +} + +#[derive(Debug)] +struct CircleVec { + data: Vec, +} + +impl CircleVec { + fn len(&self) -> usize { + self.data.len() + } + fn iter(&self) -> impl Iterator { + self.data.iter() + } +} + +// TODO(wathiede): Index and Index? +impl Index for CircleVec { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.data[index % self.data.len()] + } +} + +impl IndexMut for CircleVec { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let len = self.data.len(); + &mut self.data[index % len] + } +} + +impl Hand for FastHand { + fn step(&mut self) { + let n_cups = self.idx_to_val.len(); + let right_idx = self.cur + 1; + let mut three = vec![0; 3]; + (0..3).for_each(|dst| three[dst] = self.idx_to_val[(right_idx + dst) % n_cups]); + let dst_idx = self.destination_cup_idx(&three); + + // TODO + debug_println!( + "before {} three {:?} target {}", + self, + three, + self.idx_to_val[dst_idx] + ); + + //dbg!(right, &dst); + let end_idx = if dst_idx < right_idx { + n_cups + dst_idx - 3 + 1 + } else { + dst_idx + 1 - 3 + }; + debug_println!("moving window {}.. to {}..{}", dst_idx, right_idx, end_idx); + (right_idx..end_idx) + // Allow wrap around. + .zip((right_idx + 3..).chain(0..)) + .for_each(|(dst_idx, src_idx)| { + let src_idx = src_idx % n_cups; + let dst_idx = dst_idx % n_cups; + let v = self.idx_to_val[src_idx]; + debug_println!( + "moving {}({}) -> {}({})", + v, + src_idx, + self.idx_to_val[dst_idx], + dst_idx + ); + self.idx_to_val[dst_idx] = v; + self.val_to_idx[v - 1] = dst_idx; + }); + (0..3).for_each(|i| { + let dst_idx = (end_idx + i) % n_cups; + self.idx_to_val[dst_idx] = three[i]; + self.val_to_idx[three[i] - 1] = dst_idx; + }); + self.cur = (self.cur + 1) % n_cups; + debug_println!(" after {}", self); + } + fn test_cur_to_end(&self) -> Vec { + self.idx_to_val[self.cur..] + .iter() + .chain(self.idx_to_val[..self.cur].iter()) + .cloned() + .collect() + } + fn part1_answer(&self) -> String { + let one_idx = self.val_to_idx[1 - 1]; + let s = self.idx_to_val[one_idx + 1..] + .iter() + .fold("".to_string(), |acc, c| format!("{}{}", acc, c)); + self.idx_to_val[..one_idx] + .iter() + .fold(s, |acc, c| format!("{}{}", acc, c)) + } + fn part2_answer(&self) -> usize { + let one_idx = self.val_to_idx[1 - 1]; + self.idx_to_val[one_idx + 1] * self.idx_to_val[one_idx + 2] + } +} + +struct SlowHand { cups: Vec, cur: usize, min: usize, max: usize, } -impl fmt::Display for Hand { +impl fmt::Display for SlowHand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (i, cup) in self.cups.iter().enumerate() { if i == self.cur { @@ -94,12 +327,12 @@ impl fmt::Display for Hand { } } -impl Hand { - fn new(s: &str) -> Hand { +impl SlowHand { + fn new(s: &str) -> SlowHand { let cups: Vec<_> = s.bytes().map(|s| (s - b'0') as usize).collect(); let min = *cups.iter().min().unwrap(); let max = *cups.iter().max().unwrap(); - Hand { + SlowHand { cups, cur: 0, min, @@ -107,15 +340,33 @@ impl Hand { } } - fn play(&mut self, rounds: usize) -> String { - (0..rounds).for_each(|i| { - println!("-- move {} --", i + 1); - self.step(); - }); - self.answer() + fn new_part2(s: &str) -> SlowHand { + let mut cups: Vec<_> = s.bytes().map(|s| (s - b'0') as usize).collect(); + let min = *cups.iter().min().unwrap(); + let mut max = *cups.iter().max().unwrap(); + cups.extend(max + 1..1000000); + max = 1000000; + SlowHand { + cups, + cur: 0, + min, + max, + } + } +} + +impl Hand for SlowHand { + fn part1_answer(&self) -> String { + let idx = self.cups.iter().position(|i| i == &1).unwrap(); + let s = self.cups[idx + 1..] + .iter() + .fold("".to_string(), |acc, c| format!("{}{}", acc, c)); + self.cups[..idx] + .iter() + .fold(s, |acc, c| format!("{}{}", acc, c)) } fn step(&mut self) { - println!("{}", self); + debug_println!("{}", self); let cur = self.cups[self.cur]; let mut pickups = Vec::new(); let mut destination = self.cups[self.cur] - 1; @@ -140,9 +391,9 @@ impl Hand { } //dbg!(&pickups, &self.cups, destination); let idx = self.cups.iter().position(|i| i == &destination).unwrap(); - println!("pick up: {:?}", pickups); - println!("destination: {}({})", destination, idx); - println!("next destination: {}", next); + debug_println!("pick up: {:?}", pickups); + debug_println!("destination: {}({})", destination, idx); + debug_println!("next destination: {}", next); pickups .into_iter() @@ -151,21 +402,34 @@ impl Hand { self.cur = self.cups.iter().position(|i| i == &next).unwrap(); } - fn answer(&self) -> String { - let idx = self.cups.iter().position(|i| i == &1).unwrap(); - let s = self.cups[idx + 1..] + + /// Return internal state in a way unit tests can use + fn test_cur_to_end(&self) -> Vec { + self.cups[self.cur..] .iter() - .fold("".to_string(), |acc, c| format!("{}{}", acc, c)); - self.cups[..idx] - .iter() - .fold(s, |acc, c| format!("{}{}", acc, c)) + .chain(self.cups[..self.cur].iter()) + .cloned() + .collect() + } + fn part2_answer(&self) -> usize { + let one = self.cups.iter().position(|n| n == &1).unwrap(); + self.cups[one + 1] * self.cups[one + 2] } } #[aoc(day23, part1)] fn solution1(input: &str) -> String { - let mut hand = Hand::new(input); - hand.play(100) + let mut hand = SlowHand::new(input); + hand.play(100); + hand.part1_answer() +} + +#[aoc(day23, part2)] +fn solution2(input: &str) -> usize { + let mut hand = FastHand::new_part2(input); + //hand.play(1_000); + hand.play(10_000_000); + hand.part2_answer() } #[cfg(test)] @@ -173,13 +437,56 @@ mod tests { use super::*; const INPUT: &'static str = "389125467"; - #[test] - fn part1_10step() { - let mut hand = Hand::new(INPUT); - assert_eq!(hand.play(10), "92658374"); + fn test_hand(mut hand: H) { + let want = vec![ + [3, 8, 9, 1, 2, 5, 4, 6, 7], + [2, 8, 9, 1, 5, 4, 6, 7, 3], + [5, 4, 6, 7, 8, 9, 1, 3, 2], + [8, 9, 1, 3, 4, 6, 7, 2, 5], + [4, 6, 7, 9, 1, 3, 2, 5, 8], + [1, 3, 6, 7, 9, 2, 5, 8, 4], + [9, 3, 6, 7, 2, 5, 8, 4, 1], + [2, 5, 8, 3, 6, 7, 4, 1, 9], + [6, 7, 4, 1, 5, 8, 3, 9, 2], + [5, 7, 4, 1, 8, 3, 9, 2, 6], + [8, 3, 7, 4, 1, 9, 2, 6, 5], + ]; + want.iter().enumerate().for_each(|(step, want)| { + assert_eq!(hand.test_cur_to_end(), want, "step0 {}", step); + hand.step(); + }); } - //#[test] + #[test] + fn slow_step() { + let mut hand = SlowHand::new(INPUT); + test_hand(hand); + } + + #[test] + fn fast_step() { + let mut hand = FastHand::new(INPUT); + test_hand(hand); + } + + #[test] + fn part1_10step_slow() { + let mut hand = SlowHand::new(INPUT); + hand.play(10); + assert_eq!(hand.part1_answer(), "92658374"); + } + + #[test] + fn part1_10step_fast() { + let mut hand = FastHand::new(INPUT); + hand.play(10); + assert_eq!(hand.part1_answer(), "92658374"); + } + #[test] fn part1() { assert_eq!(solution1(INPUT), "67384529"); } + #[test] + fn part2() { + assert_eq!(solution2("389125467"), 149245887792); + } } diff --git a/2020/src/day24.rs b/2020/src/day24.rs new file mode 100644 index 0000000..8569d6d --- /dev/null +++ b/2020/src/day24.rs @@ -0,0 +1,166 @@ +//! --- Day 24: Lobby Layout --- +//! Your raft makes it to the tropical island; it turns out that the small crab was an excellent navigator. You make your way to the resort. +//! +//! As you enter the lobby, you discover a small problem: the floor is being renovated. You can't even reach the check-in desk until they've finished installing the new tile floor. +//! +//! The tiles are all hexagonal; they need to be arranged in a hex grid with a very specific color pattern. Not in the mood to wait, you offer to help figure out the pattern. +//! +//! The tiles are all white on one side and black on the other. They start with the white side facing up. The lobby is large enough to fit whatever pattern might need to appear there. +//! +//! A member of the renovation crew gives you a list of the tiles that need to be flipped over (your puzzle input). Each line in the list identifies a single tile that needs to be flipped by giving a series of steps starting from a reference tile in the very center of the room. (Every line starts from the same reference tile.) +//! +//! Because the tiles are hexagonal, every tile has six neighbors: east, southeast, southwest, west, northwest, and northeast. These directions are given in your list, respectively, as e, se, sw, w, nw, and ne. A tile is identified by a series of these directions with no delimiters; for example, esenee identifies the tile you land on if you start at the reference tile and then move one tile east, one tile southeast, one tile northeast, and one tile east. +//! +//! Each time a tile is identified, it flips from white to black or from black to white. Tiles might be flipped more than once. For example, a line like esew flips a tile immediately adjacent to the reference tile, and a line like nwwswee flips the reference tile itself. +//! +//! Here is a larger example: +//! +//! sesenwnenenewseeswwswswwnenewsewsw +//! neeenesenwnwwswnenewnwwsewnenwseswesw +//! seswneswswsenwwnwse +//! nwnwneseeswswnenewneswwnewseswneseene +//! swweswneswnenwsewnwneneseenw +//! eesenwseswswnenwswnwnwsewwnwsene +//! sewnenenenesenwsewnenwwwse +//! wenwwweseeeweswwwnwwe +//! wsweesenenewnwwnwsenewsenwwsesesenwne +//! neeswseenwwswnwswswnw +//! nenwswwsewswnenenewsenwsenwnesesenew +//! enewnwewneswsewnwswenweswnenwsenwsw +//! sweneswneswneneenwnewenewwneswswnese +//! swwesenesewenwneswnwwneseswwne +//! enesenwswwswneneswsenwnewswseenwsese +//! wnwnesenesenenwwnenwsewesewsesesew +//! nenewswnwewswnenesenwnesewesw +//! eneswnwswnwsenenwnwnwwseeswneewsenese +//! neswnwewnwnwseenwseesewsenwsweewe +//! wseweeenwnesenwwwswnew +//! In the above example, 10 tiles are flipped once (to black), and 5 more are flipped twice (to black, then back to white). After all of these instructions have been followed, a total of 10 tiles are black. +//! +//! Go through the renovation crew's list and determine which tiles they need to flip. After all of the instructions have been followed, how many tiles are left with the black side up? +use std::collections::HashMap; + +use aoc_runner_derive::{aoc, aoc_generator}; + +#[derive(Debug, PartialEq)] +enum Direction { + East, + SouthEast, + SouthWest, + West, + NorthWest, + NorthEast, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +struct TileCoord((isize, isize, isize)); + +#[derive(Debug, PartialEq)] +struct Tile { + directions: Vec, +} + +impl std::str::FromStr for Tile { + type Err = (); + fn from_str(s: &str) -> Result { + let mut it = s.bytes(); + let mut directions = Vec::new(); + use Direction::*; + while let Some(b) = it.next() { + match b { + b'n' => match it.next().unwrap() { + b'e' => directions.push(NorthEast), + b'w' => directions.push(NorthWest), + c => panic!(format!("unexpected tile direction {}", c)), + }, + b's' => match it.next().unwrap() { + b'e' => directions.push(SouthEast), + b'w' => directions.push(SouthWest), + c => panic!(format!("unexpected tile direction {}", c)), + }, + b'e' => directions.push(East), + b'w' => directions.push(West), + c => panic!(format!("unexpected tile direction {}", c)), + } + } + Ok(Tile { directions }) + } +} +impl Tile { + fn coord(&self) -> TileCoord { + // Based on 'cube coordinates' from https://www.redblobgames.com/grids/hexagons/ + TileCoord( + self.directions + .iter() + .fold((0, 0, 0), |(x, y, z), dir| match dir { + Direction::East => (x + 1, y - 1, z), + Direction::SouthEast => (x, y - 1, z + 1), + Direction::SouthWest => (x - 1, y, z + 1), + Direction::West => (x - 1, y + 1, z), + Direction::NorthWest => (x, y + 1, z - 1), + Direction::NorthEast => (x + 1, y, z - 1), + }), + ) + } +} + +#[aoc_generator(day24)] +fn parse(input: &str) -> Vec { + input + .split('\n') + .map(|l| l.parse().expect("Failed to parse tile")) + .collect() +} + +#[aoc(day24, part1)] +fn solution1(tiles: &[Tile]) -> usize { + let mut colors: HashMap = HashMap::new(); + tiles.iter().for_each(|t| { + let v = colors.entry(t.coord()).or_insert(false); + *v = !*v; + }); + colors.values().filter(|v| **v).count() +} + +#[cfg(test)] +mod tests { + use super::*; + const INPUT: &'static str = r#" +sesenwnenenewseeswwswswwnenewsewsw +neeenesenwnwwswnenewnwwsewnenwseswesw +seswneswswsenwwnwse +nwnwneseeswswnenewneswwnewseswneseene +swweswneswnenwsewnwneneseenw +eesenwseswswnenwswnwnwsewwnwsene +sewnenenenesenwsewnenwwwse +wenwwweseeeweswwwnwwe +wsweesenenewnwwnwsenewsenwwsesesenwne +neeswseenwwswnwswswnw +nenwswwsewswnenenewsenwsenwnesesenew +enewnwewneswsewnwswenweswnenwsenwsw +sweneswneswneneenwnewenewwneswswnese +swwesenesewenwneswnwwneseswwne +enesenwswwswneneswsenwnewswseenwsese +wnwnesenesenenwwnenwsewesewsesesew +nenewswnwewswnenesenwnesewesw +eneswnwswnwsenenwnwnwwseeswneewsenese +neswnwewnwnwseenwseesewsenwsweewe +wseweeenwnesenwwwswnew +"#; + + #[test] + fn tile() { + use Direction::*; + assert_eq!( + "esenee".parse::().expect("failed to parse tile"), + Tile { + directions: vec![East, SouthEast, NorthEast, East] + } + ); + } + + #[test] + fn part1() { + assert_eq!(solution1(&parse(INPUT)), 10); + } +} diff --git a/2020/src/lib.rs b/2020/src/lib.rs index 9ec58e3..76ddfd4 100644 --- a/2020/src/lib.rs +++ b/2020/src/lib.rs @@ -13,7 +13,8 @@ pub mod day2; //pub mod day20; pub mod day21; pub mod day22; -pub mod day23; +//pub mod day23; +pub mod day24; pub mod day3; pub mod day4; pub mod day5; @@ -24,4 +25,14 @@ pub mod day9; use aoc_runner_derive::aoc_lib; +#[macro_export] +macro_rules! debug_print{ + ($($arg:tt)*) => (#[cfg(debug_assertions)] print!($($arg)*)); +} + +#[macro_export] +macro_rules! debug_println { + ($($arg:tt)*) => (#[cfg(debug_assertions)] println!($($arg)*)); +} + aoc_lib! { year = 2020 }