From 1015b402870cb1af5e062ef257c75d5714dd5c1f Mon Sep 17 00:00:00 2001 From: Smaug123 Date: Wed, 19 May 2021 22:47:24 +0100 Subject: [PATCH] Day 22 --- Cargo.lock | 4 + Cargo.toml | 1 + day_22/Cargo.toml | 9 +++ day_22/input.txt | 25 ++++++ day_22/src/lib.rs | 198 +++++++++++++++++++++++++++++++++++++++++++++ day_22/src/main.rs | 8 ++ 6 files changed, 245 insertions(+) create mode 100644 day_22/Cargo.toml create mode 100644 day_22/input.txt create mode 100644 day_22/src/lib.rs create mode 100644 day_22/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3b949fc..13f7643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,10 @@ version = "0.1.0" name = "day_2" version = "0.1.0" +[[package]] +name = "day_22" +version = "0.1.0" + [[package]] name = "day_23" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 3cc1112..370de86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "day_17", "day_18", "day_19", + "day_22", "day_23", "day_25", ] diff --git a/day_22/Cargo.toml b/day_22/Cargo.toml new file mode 100644 index 0000000..a527b19 --- /dev/null +++ b/day_22/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day_22" +version = "0.1.0" +authors = ["Smaug123 "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day_22/input.txt b/day_22/input.txt new file mode 100644 index 0000000..024be8a --- /dev/null +++ b/day_22/input.txt @@ -0,0 +1,25 @@ +#..###...#..#.#.#...#..## +....#.##..#..###...###... +##.#.....###...#.##...### +##...#.####..#####..####. +##.#...#.##...##.....##.# +###.#.#...###..###.###... +#.#..#.#.###..#.##.#..### +.#..###.##..##.#....#.#.. +#.#.......###.##...#.##.. +#.#.######.##.#..#...#... +######.#.##...#.#...###.# +.#....#.###.##.######.... +#.#####.#####.#.#..##.### +..##.#.#...###......###.# +.##.##..##.#.#.#######.## +#..###.###....#.....##..# +..##..####..##.#...####.. +.##.####.##.##..##..#.... +###...#.#..##...#.#..##.. +......##.....#.#..#.#.### +#.#.##.##.#####....#.#..# +.....#.###.##...#...#..#. +#...#......##.##.#####.## +#.##.##.......#.##....#.# +####.##.#.#........###.## diff --git a/day_22/src/lib.rs b/day_22/src/lib.rs new file mode 100644 index 0000000..1c3a77f --- /dev/null +++ b/day_22/src/lib.rs @@ -0,0 +1,198 @@ +pub mod day_22 { + use std::collections::HashMap; + + enum State { + Clean, + Weakened, + Flagged, + Infected, + } + + enum Direction { + Left, + Right, + Up, + Down, + } + + impl Direction { + fn turn_right(d: &Direction) -> Direction { + match *d { + Direction::Left => Direction::Up, + Direction::Up => Direction::Right, + Direction::Right => Direction::Down, + Direction::Down => Direction::Left, + } + } + + fn turn_left(d: &Direction) -> Direction { + match *d { + Direction::Left => Direction::Down, + Direction::Up => Direction::Left, + Direction::Right => Direction::Up, + Direction::Down => Direction::Right, + } + } + + fn reverse(d: &Direction) -> Direction { + match *d { + Direction::Left => Direction::Right, + Direction::Up => Direction::Down, + Direction::Right => Direction::Left, + Direction::Down => Direction::Up, + } + } + } + + pub struct Board { + squares: HashMap<(i32, i32), State>, + position: (i32, i32), + direction: Direction, + } + + fn move_in_dir(row_col: (i32, i32), direction: &Direction) -> (i32, i32) { + let (row, col) = row_col; + match *direction { + Direction::Left => (row, col - 1), + Direction::Right => (row, col + 1), + Direction::Up => (row - 1, col), + Direction::Down => (row + 1, col), + } + } + + impl Board { + pub(crate) fn parse(s: &str) -> Board { + let mut output = HashMap::new(); + let mut num_cols = 0; + let mut num_rows = 0; + for l in s.lines() { + let mut col = 0; + for ch in l.trim().chars() { + output.insert( + (num_rows, col), + match ch { + '#' => State::Infected, + '.' => State::Clean, + c => { + panic!("Unexpected char: {}", c); + } + }, + ); + col += 1; + } + if num_rows == 0 { + num_cols = col; + } + num_rows += 1; + } + + Board { + squares: output, + position: (num_rows / 2, num_cols / 2), + direction: Direction::Up, + } + } + } + + pub fn input() -> Board { + let input = include_str!("../input.txt"); + Board::parse(&input) + } + + // Returns whether we caused an infection. + fn move_once(board: &mut Board) -> bool { + let mut to_ret = false; + let entry = board.squares.entry(board.position).or_insert(State::Clean); + match *entry { + State::Infected => { + board.direction = Direction::turn_right(&board.direction); + *entry = State::Clean; + } + State::Clean => { + board.direction = Direction::turn_left(&board.direction); + *entry = State::Infected; + to_ret = true; + } + _ => { + panic!("Unexpected state"); + } + } + board.position = move_in_dir(board.position, &board.direction); + to_ret + } + + pub fn part_1(mut board: Board, max: u32) -> usize { + let mut count = 0; + for _ in 0..max { + if move_once(&mut board) { + count += 1; + } + } + count + } + + // Returns whether we caused an infection. + fn move_once_2(board: &mut Board) -> bool { + let mut to_ret = false; + let entry = board.squares.entry(board.position).or_insert(State::Clean); + match *entry { + State::Infected => { + board.direction = Direction::turn_right(&board.direction); + *entry = State::Flagged; + } + State::Clean => { + board.direction = Direction::turn_left(&board.direction); + *entry = State::Weakened; + } + State::Flagged => { + board.direction = Direction::reverse(&board.direction); + *entry = State::Clean; + } + State::Weakened => { + *entry = State::Infected; + to_ret = true; + } + } + board.position = move_in_dir(board.position, &board.direction); + to_ret + } + + pub fn part_2(mut board: Board, max: u32) -> usize { + let mut count = 0; + for _ in 0..max { + if move_once_2(&mut board) { + count += 1; + } + } + count + } +} + +#[cfg(test)] +mod tests { + use super::day_22::*; + + #[test] + fn part1_known() { + let input = Board::parse("..#\n#..\n..."); + assert_eq!(part_1(input, 70), 41); + let input = Board::parse("..#\n#..\n..."); + assert_eq!(part_1(input, 10000), 5587); + } + + #[test] + fn part2_known() { + let input = Board::parse("..#\n#..\n..."); + assert_eq!(part_2(input, 100), 26); + let input = Board::parse("..#\n#..\n..."); + assert_eq!(part_2(input, 10000000), 2511944); + } + + #[test] + fn test_day_22() { + let board = input(); + assert_eq!(part_1(board, 10000), 5447); + let input = input(); + assert_eq!(part_2(input, 10000000), 2511705); + } +} diff --git a/day_22/src/main.rs b/day_22/src/main.rs new file mode 100644 index 0000000..ef70537 --- /dev/null +++ b/day_22/src/main.rs @@ -0,0 +1,8 @@ +use day_22::day_22; + +fn main() { + let input = day_22::input(); + println!("part 1 => {}", day_22::part_1(input, 10000)); + let input = day_22::input(); + println!("part 2 => {}", day_22::part_2(input, 10000000)); +}