diff --git a/Cargo.toml b/Cargo.toml index 065a668..e9ea4bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] anyhow = "1.0.66" console = "0.15.2" +convert-base = "1.1.2" enum-iterator = "1.2.0" euclid = { version = "0.22.7", features = ["serde"] } evalexpr = "8.1.0" diff --git a/data/day24.txt b/data/day24.txt new file mode 100644 index 0000000..2e7207e --- /dev/null +++ b/data/day24.txt @@ -0,0 +1,73 @@ +.#.######...####..##.###.#########.######..######..#..###...#######.####. +#.#....##..#.##...#..##.#........###.#.###.#.###.###....#.###.#..##..##.. +..#########.#.#..##.##....##....##.......#...###....##..#..#.#.#..#.####. +.#..###.#.##...###..####.#.#..#.#.###.##.#.#......#.####..##.#####..#.##. +#..#.#######..####...##..#..##.###.#####...#.###.#....##.####..#.#.#####. +####.#.#..###########..#.###..#.###...###..#....#.####..###...#.##..##.#. +.##...##.##.####......#.#...#.#...###.#..##.###.###.#.########.#####.#.## +#....#.##..#.#..##..##.###.##.##..##..###.#.#...##....#.##..##.#.#..###.. +#.##.#.#.##..#.#..#####.#.#...###.#...#####...##.##.#.#......##...#...#.. +#.....#.##...##.##.#.####.#####.###..#.#.....#.###..#.######.#####.##.### +##......###...#..##.#####..###..#..######..#...#..#..#..#..#..#.###.#.##. +.....####..######..#.#.....###.#.##.#.##.##...##.#.######.##.#.##..#.###. +#.#.##.#.....#..###..#..##.######.#..####.##.##...##...#.#...#.....###### +.#.####..##...#...##.######.#.###.##.#..#...#...#..#.####.#.#####.##...#. +####.##.###...####.....#..#.##..#.#..###..#.#....#.#.#....#.#..#.###....# +.####.#..###...##.#.##........#.#.##.#.####..#..#..##..#..#.#.#.######.## +.###.#..###...######.#..##.#########.#..........####...#.###.##..#..####. +#####....######.##.#....##.####..#.###...#####.###..##..#.#.##..#..#..### +.#.###.#..##.#####.####.#.#.#.#.##..#.####.##.#.#.#..#.#.#..##.#..####.## +####......###.#.#...#.#.....#...##.#.#.......#.##...#..#.###.#.#####..#.. +.#.##....#...#.####.###.#.###.#.#.##.#.#.##.###.#####.....##..#..##.#...# +#....#...##.##.####....##...#...#.##...##.##.##...######.#.##..###.####.. +#..#.#.##..####.#.#..#.#..#....####...####..#..#..###...##.#.##.#..##.... +####..##.#.#.##.#####...####.#.##..##.#.#.#.##....##.#..#..##.##.#...#..# +##.#...#..####..##.#.#.#.#..##..##..###.#...##...#.#.#.#.##...####.##.##. +#######.#...#.####.....#.###.#..#.##.##.#####.....#.#.#..###..#....##.#.. +.###....#.#.##.#...#..##..#.#...#.#.....#.##.####..###....#.#.#.###.##.## +#.#.#..#.##.####...#..#..##....##.#.#...#.##..##.#.#####.###.#####.#..##. +.#####.#####....####...#...#..#..#..####.#........###.##..##.#.##..#.#.## +#..#..#.....#.#.##..##.#...#...###.#...###.#...##.##..##.....##.####.#... +##.#.##.###..#...#######.###.###..#.##.##.#..##.....##....##.##.....##### +..#..##.#.###.....#..#..#.##.###.##..###.#.....##..##.#.#.######..##..... +.##..##.#.##.#.#####.....#.#....#...####.#..#.##.#..#..##.#.##.##..#...#. +#.#.#..##...#.#####..#.###.##.###...##...#..##......##.#.#.#.#.#..#.#...# +..###......####.######...###..#.#....#..#.....#..#.#..#.##..####.##.##... +#...#..####..##....#...#..####.#..#####.######..#.######..####.##...#.#.# +##..#..##.####.#..##.###.....###....#...####...#..##..#.####......##.#### +.##.##.##.##....#..##.....#####.###....###..##..###..#....#.#.##..#.##### +.#.##..#.###..#.#.#...#..##...##.#.#..#..#.#..###...#..#.......#.#..#.#.# +###.......#.##.##.#..#..#.###.#####.##.#..###..#.#...##..#..#....###.#### +.##.#....##.##.#.####.##.#####..#.####..##.##.###..##.#...##.####.#..#..# +..##..###.#.#####.#.#.....#...#.#.#..##..##..##..##..#.###...#.##...#.##. +.####.#.#.##.##.#...##.##..###....#..##.##..#...##.#.###...#.##.#..#.#.## +#.###..#..#..###....#.#...#.#..########.##.######.#.#....##.#.##.##....## +.##.#...#.#.##..#.#.##.###.##.#.....##........##.######...###...######### +..##.##....#.....####....#..#..#....###.##..#.......#..##.#.##.####...##. +##......##.##.###......#.####...#..#.#...#.#.##.#.#....##...##..#.#####.# +##.#.####..####..#.##..#..####.#.#..#.##..####.##..#.##.#.#...##....#.... +###...#..##..#.#.#.##.##.#.#.#######.#.###.#...#.##.#.....##.#....#.#.... +##.#.#######.#.#....#...##.####.....####.#.##.###.#.##...#.#...#..#...### +.###......##.#..##.###.#...#......##..###.#......#.#..#...#..##.#...####. +##.#..#.#.###.#..#..#####...#.##.###.#.#.###...##.##..####.###.#..##.#.#. +#...#.#.###......##.##...####...######..##...####.#..####.#.#..####...### +##.##.#.####.##.....#..###.###...#....#..###.##....#..#...#.##.##.....#.# +.####..#.#.###.....##.#....#.##.#.#..##.....#.####..##.#####.....#####..# +#...###.#####..###.#...##...#.#.##..#####..##.##.##..#...##.#..###.#####. +###.#####..#.####.#.#.#...#.#.#...####.###.#.#..###..#.####.##..##.#..#.. +.#.....##...#.....##.#..###.#......#.##..##...####..##.#.##...#.#..#.###. +.#####.#..###.##.......#############.#.#.....##...#.##.##....###.#.##..## +####.#..#..#..##..#...#.#.#..##....#.########...####.####.#.###.....#.#.. +.##..#.##....#.#...#.#.#...###.#.#..#.#.###.##...#.###..#...#.##.######.. +#...#.####..#......#.....#######..#........###..##.#..##.#.#.#.###..##..# +.#.######.###.###.....#.#.####..##...#.##....#.##.##.####..###.#####.#.#. +...##...##.##..#.###.###.#......###.##.##.#.#.####.#.#..#...#...###...#.. +..#....#....#.#..###.#....#####.#......#....#...#..#........#..##.###.##. +#.#..##.#.####.##..##....##..#.#...#..#.#..#.#.##..#.#.####...#..#####..# +.##.###.#.#.#.#.#.#.##.###.##.#.##.######.##..##.##......####....#....#.. +.######..#####.#..#.#...#....###########.#.##.####.###.#....##.###..####. +..#####..##.#..##.#..#..#..##.#.###.#.#......######.#..#...###....#..#### +###.##...####....##..###......##.#.#...##..#.##...#.##.#.#.#.##.##.##.#.. +#..#.#.##.#.#.##..#..##.###..##.####...........#..####.#.##..#...#....#.. +###...#####.#..#..#.##.##...####....#.#..####.#..##..##.##.###.##.###.##. +#.....##.##...###.#.#..###.#####..#.#..####..#..#...#.#...##.####.#..###. \ No newline at end of file diff --git a/data/day25.txt b/data/day25.txt new file mode 100644 index 0000000..c6c9a45 --- /dev/null +++ b/data/day25.txt @@ -0,0 +1,115 @@ +2=-00=02-1 +1-1=02=1220 +1-000-00 +12=-=0--=202-= +1==0=0210-1==1--- +122110--01- +1-=1=-==02-12000 +1=1=20- +11-1-21-02221=2--= +2=1--11001 +210=-1020-=1-1 +20-= +10-000=12=21202== +20222=2--21= +1020010 +2-=1110=-0=2- +1==2=2-=1--= +100- +2211-==-021== +1=1 +1-=1--==0 +20220=1=-22 +12 +2-=002-102-2- +2-0-02 +20001-020=01 +1===-210--0010 +2021=121-00-12=-1= +1-0-0==2=1 +1-=01= +102=22=0=02 +11=01- +2=0 +20=-12=2121-- +111102011=0000 +22--12010- +1=-21202=-2=-2 +1=2-=-2-1- +2-=1=112-1- +22= +1=--20-=000=0-11=== +1--== +1000=1-1 +1=1-01000 +1=2--1=1 +1=2-2=--2-00 +1=00-=-0010-2 +102 +111101=21002= +211-=01-= +121--11=12022=-112 +1==--0100-=0 +2 +1=- +220=-1=10--12 +10---20--00 +1==1111- +12-=0-0==010 +2121=1 +2==102=21=-2=20 +201===- +1-00=11-200=-111012 +1-022 +1==1010--011-==-22 +11==20=1122=12=2-1 +1--0001=22 +2020==2-- +1===--0-- +12=2---1 +1-0100=-=-1--11 +122====20=--2 +1-0=-01==- +1-021 +2-01==1=0 +1=1-20=01121020==2 +1=02=-2011--01=21 +2-2110-=- +1=-=-002-== +2-=- +10-0 +1=0=-1= +1=1=1 +212-0 +11100= +21=202-111-1=-012-1 +22-=001= +11=21=0----010=-10 +1=1=221 +1221= +1=11=20=-0112-=2-= +2-1-02001 +12-=0=120-1=--20=- +2=1--- +2==--2=0--- +10=-010 +112 +1-=1 +1022100-= +1=220001000-1-1=== +2==-2-00=02=10=- +21=2 +2==1=02=-02 +1=10 +1-0202= +1--2=112021=-1112222 +1-122=2=-10 +1--2112--011- +2=1-= +2211211 +1=021=-000 +1101 +1=2=120= +2=02 +12-1 +2-=0-=2-1-0112 \ No newline at end of file diff --git a/src/bin/day23.rs b/src/bin/day23.rs index 813326b..9f3f663 100644 --- a/src/bin/day23.rs +++ b/src/bin/day23.rs @@ -357,8 +357,8 @@ fn main() -> Result<(), Error> { mod test { use super::*; - const EXPECTED_5: &str = include_str!("../../data/day23_ex.txt"); - const EXPECTED_10: &str = r#"xxx + const EXPECTED_5: &str = include_str!("../../data/day23_ex.txt"); + const EXPECTED_10: &str = r#"xxx .......#...... ...........#.. ..#.#..#...... @@ -374,17 +374,17 @@ mod test { "#; - fn parse_expected(s: &str) -> Vec> { - let mut exp = vec![]; - for chunk in s.split("\n\n") { - let mut elves = vec![]; - for (y, line) in chunk.lines().enumerate().skip(1) { - elves.extend(handle_line((y as isize - 3, line), 3)); - } - exp.push(elves); - } - exp - } + fn parse_expected(s: &str) -> Vec> { + let mut exp = vec![]; + for chunk in s.split("\n\n") { + let mut elves = vec![]; + for (y, line) in chunk.lines().enumerate().skip(1) { + elves.extend(handle_line((y as isize - 3, line), 3)); + } + exp.push(elves); + } + exp + } #[test] fn test_parse() { @@ -414,4 +414,3 @@ mod test { assert_eq!(rounds, 20); } } - diff --git a/src/bin/day24.rs b/src/bin/day24.rs new file mode 100644 index 0000000..1b36775 --- /dev/null +++ b/src/bin/day24.rs @@ -0,0 +1,106 @@ +use anyhow::Error; +use enum_iterator::Sequence; +use euclid::vec2; +use structopt::StructOpt; + +type Coord = i64; +type Point = euclid::default::Point2D; +type Box = euclid::default::Box2D; +type Vector = euclid::default::Vector2D; +type Rect = euclid::default::Rect; + +const DATA: &str = include_str!("../../data/day23.txt"); +const SAMPLE: &str = r#"....#.. +..###.# +#...#.# +.#...## +#.###.. +##.#.## +.#..#.."#; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Sequence)] +#[repr(usize)] +enum Direction { + North, + South, + West, + East, +} + +impl Direction { + fn as_char(&self) -> char { + (*self).into() + } +} + +impl Into for Direction { + fn into(self) -> Vector { + match self { + Direction::North => vec2(0, -1), + Direction::East => vec2(1, 0), + Direction::South => vec2(0, 1), + Direction::West => vec2(-1, 0), + } + } +} + +impl Into for Direction { + fn into(self) -> char { + match self { + Direction::North => '^', + Direction::East => '>', + Direction::South => 'v', + Direction::West => '<', + } + } +} + +fn parse(_s: &str) -> () {} + +fn solve_part_1() -> usize { + todo!(); +} + +fn solve_part_2() -> usize { + todo!(); +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "day24", about = "Blizzard Basin")] +struct Opt { + /// Use puzzle input instead of the sample + #[structopt(short, long)] + puzzle_input: bool, +} + +fn main() -> Result<(), Error> { + let opt = Opt::from_args(); + + let _ = parse(if opt.puzzle_input { DATA } else { SAMPLE }); + + let p1 = solve_part_1(); + println!("part 1 = {}", p1); + + println!("part 2 = {}", solve_part_2()); + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_parse() { + let _ = parse(SAMPLE); + todo!(); + } + + #[test] + #[ignore] + fn test_part_1() {} + + #[test] + #[ignore] + fn test_part_2() {} +} diff --git a/src/bin/day25.rs b/src/bin/day25.rs new file mode 100644 index 0000000..958c981 --- /dev/null +++ b/src/bin/day25.rs @@ -0,0 +1,143 @@ +use anyhow::Error; +use structopt::StructOpt; + +const DATA: &str = include_str!("../../data/day25.txt"); +const SAMPLE: &str = r#"1=-0-2 +12111 +2=0= +21 +2=01 +111 +20012 +112 +1=-1= +1-12 +12 +1= +122"#; + +fn snafu_digit(c: char) -> isize { + match c { + '1' => 1, + '2' => 2, + '0' => 0, + '-' => -1, + '=' => -2, + _ => panic!("illegal snafu digit"), + } +} + +fn to_snafu_digit(i: isize) -> char { + match i { + 0 => '0', + 1 => '1', + 2 => '2', + 3 => '=', + 4 => '-', + _ => panic!("illegal snafu digit"), + } +} + +fn parse_snafu(s: &str) -> isize { + if s.is_empty() { + return 0; + } + let max_value = 5isize.pow(s.len() as u32); + + let value: isize = s + .chars() + .map(snafu_digit) + .scan(max_value, |max_value, digit_value| { + *max_value /= 5; + Some(digit_value * *max_value) + }) + .sum(); + value +} + +fn to_snafu_string(mut v: isize) -> String { + let mut snafu_digits = Vec::new(); + while v > 0 { + let amount_to_encode = v % 5; + snafu_digits.push(to_snafu_digit(amount_to_encode)); + if amount_to_encode >= 3 { + v += 5 + } + v /= 5; + } + snafu_digits.iter().rev().collect::() +} + +fn to_snafu_string2(v: isize) -> String { + let snafu_digits: Vec = std::iter::repeat(()) + .scan(v, |current_value, _| { + let mut v = *current_value; + if v > 0 { + let amount_to_encode = v % 5; + let digit = to_snafu_digit(amount_to_encode); + if amount_to_encode >= 3 { + v += 5 + } + v /= 5; + *current_value = v; + Some(digit) + } else { + None + } + }) + .collect(); + snafu_digits.iter().rev().collect::() +} + +fn parse(s: &str) -> Vec { + s.lines().map(str::to_string).collect() +} + +fn solve_part_1(s: &Vec) -> String { + let values: Vec = s.iter().map(String::as_str).map(parse_snafu).collect(); + let sum: isize = values.iter().sum(); + to_snafu_string2(sum) +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "day25", about = "Full of Hot Air")] +struct Opt { + /// Use puzzle input instead of the sample + #[structopt(short, long)] + puzzle_input: bool, +} + +fn main() -> Result<(), Error> { + let opt = Opt::from_args(); + + let value_list = parse(if opt.puzzle_input { DATA } else { SAMPLE }); + + let p1 = solve_part_1(&value_list); + println!("part 1 = {}", p1); + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + use itertools::assert_equal; + + const EXPECTED: &[isize] = &[1747, 906, 198, 11, 201, 31, 1257, 32, 353, 107, 7, 3, 37]; + + #[test] + fn test_parse() { + let value_list = parse(SAMPLE); + let values: Vec = value_list + .iter() + .map(String::as_str) + .map(parse_snafu) + .collect(); + assert_equal(values.iter(), EXPECTED.iter()); + + let sum: isize = values.iter().sum(); + assert_eq!(sum, 4890); + + assert_eq!(to_snafu_string2(sum).as_str(), "2=-1=0"); + } +}