You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
advent-of-code/2016/rust/src/day_08.rs

150 lines
3.4 KiB

use std::collections::HashMap;
use std::fmt;
use regex::Regex;
use errors::*;
pub fn solve(input: &str) -> Result<String> {
let rect_re = Regex::new(r"rect (\d+)x(\d+)").unwrap();
let rotate_re = Regex::new(r"rotate (column x|row y)=(\d+) by (\d+)").unwrap();
let mut screen = Screen::new(50, 6);
for line in input.lines() {
if let Some(caps) = rect_re.captures(line) {
screen.rect(caps[1].parse().unwrap(), caps[2].parse().unwrap());
} else if let Some(caps) = rotate_re.captures(line) {
let index = caps[2].parse().unwrap();
let count = caps[3].parse().unwrap();
if &caps[1] == "column x" {
screen.rotate_col(index, count);
} else if &caps[1] == "row y" {
screen.rotate_row(index, count);
}
} else {
return Err(format!("unexpected input: '{}'", line).into());
}
}
Ok(format!("{}", screen.pixels.iter().filter(|&(_, &v)| v).count()))
// Ok(format!("{}", screen))
}
#[derive(Eq,Hash,PartialEq)]
struct Point(usize, usize);
type Pixel = bool;
pub struct Screen {
width: usize,
height: usize,
pixels: HashMap<Point, Pixel>,
}
impl Screen {
fn new(width: usize, height: usize) -> Self {
Screen {
width: width,
height: height,
pixels: HashMap::new(),
}
}
fn rect(&mut self, x: usize, y: usize) {
for x in 0..x {
for y in 0..y {
self.pixels.insert(Point(x, y), true);
}
}
}
fn rotate_col(&mut self, index: usize, count: usize) {
let count = count % self.height;
let mut col = (0..self.height)
.map(|y| self.pixels.get(&Point(index, y)).cloned().unwrap_or(false))
.collect::<Vec<_>>();
let col = Self::rotate(&mut col, count);
for (y, &pixel) in col.iter().enumerate() {
self.pixels.insert(Point(index, y), pixel);
}
}
fn rotate_row(&mut self, index: usize, count: usize) {
let count = count % self.width;
let mut row = (0..self.width)
.map(|x| self.pixels.get(&Point(x, index)).cloned().unwrap_or(false))
.collect::<Vec<_>>();
let row = Self::rotate(&mut row, count);
for (x, &pixel) in row.iter().enumerate() {
self.pixels.insert(Point(x, index), pixel);
}
}
fn rotate<T: Clone>(v: &mut Vec<T>, count: usize) -> Vec<T> {
let count = v.len() - count - 1;
v[(count + 1)..].iter().chain(v[0...count].iter()).cloned().collect()
}
}
impl fmt::Display for Screen {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = (0..self.height)
.map(|y| {
(0..self.width)
.map(|x| {
if self.pixels.get(&Point(x, y)).cloned().unwrap_or(false) {
'#'
} else {
'.'
}
})
.collect::<String>()
})
.collect::<Vec<_>>()
.join("\n");
write!(f, "{}", s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_screen() {
let mut screen = Screen::new(7, 3);
assert_eq!(format!("{}", screen),
".......
.......
.......");
screen.rect(3, 2);
assert_eq!(format!("{}", screen),
"###....
###....
.......");
screen.rotate_col(1, 1);
assert_eq!(format!("{}", screen),
"#.#....
###....
.#.....");
screen.rotate_row(0, 4);
assert_eq!(format!("{}", screen),
"....#.#
###....
.#.....");
screen.rotate_col(1, 1);
assert_eq!(format!("{}", screen),
".#..#.#
#.#....
.#.....");
}
}