From 8f9bd3027b668061a6be032c39c4288067fa9f76 Mon Sep 17 00:00:00 2001 From: Jez Cope Date: Sun, 24 Dec 2017 19:32:13 +0000 Subject: [PATCH] Post: Advent of code day 22 --- posts/adventofcode/2017/21-fractal-art.md | 2 +- posts/adventofcode/2017/22-sporifica-virus.md | 149 ++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 posts/adventofcode/2017/22-sporifica-virus.md diff --git a/posts/adventofcode/2017/21-fractal-art.md b/posts/adventofcode/2017/21-fractal-art.md index 76b3d2f..5414cd7 100644 --- a/posts/adventofcode/2017/21-fractal-art.md +++ b/posts/adventofcode/2017/21-fractal-art.md @@ -13,7 +13,7 @@ series: aoc2017 [Today's challenge](http://adventofcode.com/2017/day/21) asks us to assist an artist building fractal patterns from a rulebook. -[→ Full code on GitHub](https://github.com/jezcope/aoc2017/blob/master/21-fractal-art.md) +[→ Full code on GitHub](https://github.com/jezcope/aoc2017/blob/master/21-fractal-art.py) !!! commentary Another fairly straightforward algorithm: the really tricky part was breaking the pattern up into chunks and rejoining it again. I could probably have done that more efficiently, and would have needed to if I had to go for a few more iterations and the grid grows with every iteration and gets big fast. diff --git a/posts/adventofcode/2017/22-sporifica-virus.md b/posts/adventofcode/2017/22-sporifica-virus.md new file mode 100644 index 0000000..d2cc25b --- /dev/null +++ b/posts/adventofcode/2017/22-sporifica-virus.md @@ -0,0 +1,149 @@ +--- +title: "Sporifica Virus — Rust — #adventofcode Day 22" +description: "In which I make more beautiful ASCII art and cause disease in the process." +slug: day-22 +date: 2017-12-24T19:32:03+00:00 +tags: +- Technology +- Learning +- Advent of Code +- Rust +series: aoc2017 +--- + +[Today's challenge](http://adventofcode.com/2017/day/22) has us helping to clean up (or spread, I can't really tell) an infection of the "sporifica" virus. + +[→ Full code on GitHub](https://github.com/jezcope/aoc2017/blob/master/22-sporifica-virus.rs) + +!!! commentary + I thought I'd have another play with Rust, as its Haskell-like features resonate with me at the moment. I struggled quite a lot with the Rust concepts of ownership and borrowing, and this is a cleaned-up version of the code based on some [good advice from the folks on /r/rust](https://www.reddit.com/r/rust/comments/7lnmz4/code_review_fighting_the_borrow_checker_for/). + +```rust +use std::io; +use std::env; +use std::io::BufRead; +use std::collections::HashMap; + +#[derive(PartialEq, Clone, Copy, Debug)] +enum Direction {Up, Right, Down, Left} +#[derive(PartialEq, Clone, Copy, Debug)] +enum Infection {Clean, Weakened, Infected, Flagged} + +use self::Direction::*; +use self::Infection::*; + +type Grid = HashMap<(isize, isize), Infection>; + +fn turn_left(d: Direction) -> Direction { + match d {Up => Left, Right => Up, Down => Right, Left => Down} +} + +fn turn_right(d: Direction) -> Direction { + match d {Up => Right, Right => Down, Down => Left, Left => Up} +} + +fn turn_around(d: Direction) -> Direction { + match d {Up => Down, Right => Left, Down => Up, Left => Right} +} + +fn make_move(d: Direction, x: isize, y: isize) -> (isize, isize) { + match d { + Up => (x-1, y), + Right => (x, y+1), + Down => (x+1, y), + Left => (x, y-1), + } +} + +fn basic_step(grid: &mut Grid, x: &mut isize, y: &mut isize, d: &mut Direction) -> usize { + let mut infect = 0; + let current = match grid.get(&(*x, *y)) { + Some(v) => *v, + None => Clean, + }; + if current == Infected { + *d = turn_right(*d); + } else { + *d = turn_left(*d); + infect = 1; + }; + grid.insert((*x, *y), match current { + Clean => Infected, + Infected => Clean, + x => panic!("Unexpected infection state {:?}", x), + }); + let new_pos = make_move(*d, *x, *y); + *x = new_pos.0; + *y = new_pos.1; + + infect +} + +fn nasty_step(grid: &mut Grid, x: &mut isize, y: &mut isize, d: &mut Direction) -> usize { + let mut infect = 0; + let new_state: Infection; + let current = match grid.get(&(*x, *y)) { + Some(v) => *v, + None => Infection::Clean, + }; + match current { + Clean => { + *d = turn_left(*d); + new_state = Weakened; + }, + Weakened => { + new_state = Infected; + infect = 1; + }, + Infected => { + *d = turn_right(*d); + new_state = Flagged; + }, + Flagged => { + *d = turn_around(*d); + new_state = Clean; + } + }; + grid.insert((*x, *y), new_state); + let new_pos = make_move(*d, *x, *y); + *x = new_pos.0; + *y = new_pos.1; + + infect +} + +fn virus_infect(mut grid: Grid, mut step: F, mut x: isize, mut y: isize, mut d: Direction, n: usize) -> usize + where F: FnMut(&mut Grid, &mut isize, &mut isize, &mut Direction) -> usize, +{ + (0..n).map(|_| step(&mut grid, &mut x, &mut y, &mut d)) + .sum() +} + +fn main() { + let args: Vec = env::args().collect(); + let n_basic: usize = args[1].parse().unwrap(); + let n_nasty: usize = args[2].parse().unwrap(); + + let stdin = io::stdin(); + let lines: Vec = stdin.lock() + .lines() + .map(|x| x.unwrap()) + .collect(); + let mut grid: Grid = HashMap::new(); + let x0 = (lines.len() / 2) as isize; + let y0 = (lines[0].len() / 2) as isize; + + for (i, line) in lines.iter().enumerate() { + for (j, c) in line.chars().enumerate() { + grid.insert((i as isize, j as isize), + match c {'#' => Infected, _ => Clean}); + } + } + + let basic_steps = virus_infect(grid.clone(), basic_step, x0, y0, Up, n_basic); + println!("Basic: infected {} times", basic_steps); + + let nasty_steps = virus_infect(grid, nasty_step, x0, y0, Up, n_nasty); + println!("Nasty: infected {} times", nasty_steps); +} +```