diff --git a/2016/rust/src/day_08.rs b/2016/rust/src/day_08.rs
new file mode 100644
index 0000000..06952d3
--- /dev/null
+++ b/2016/rust/src/day_08.rs
@@ -0,0 +1,149 @@
+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),
+ ".#..#.#
+#.#....
+.#.....");
+ }
+}
diff --git a/2016/rust/src/lib.rs b/2016/rust/src/lib.rs
index 2e9fa82..3ff0012 100644
--- a/2016/rust/src/lib.rs
+++ b/2016/rust/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(inclusive_range_syntax)]
#![recursion_limit = "1024"]
#[macro_use]
@@ -13,3 +14,4 @@ pub mod day_04;
pub mod day_05;
pub mod day_06;
pub mod day_07;
+pub mod day_08;
diff --git a/2016/rust/src/main.rs b/2016/rust/src/main.rs
index ab72f40..d984eee 100644
--- a/2016/rust/src/main.rs
+++ b/2016/rust/src/main.rs
@@ -10,7 +10,7 @@ fn main() {
let mut input = String::new();
io::stdin().read_to_string(&mut input).ok();
- let solution = day_07::solve(&input)?;
+ let solution = day_08::solve(&input)?;
println!("{}", solution);
Ok(())