126 lines
3.0 KiB
Rust
126 lines
3.0 KiB
Rust
use lazy_static::lazy_static;
|
|
use regex::Regex;
|
|
use Instruction::*;
|
|
|
|
#[derive(Debug)]
|
|
struct Point {
|
|
x: usize,
|
|
y: usize,
|
|
}
|
|
|
|
impl FromIterator<usize> for Point {
|
|
fn from_iter<T: IntoIterator<Item = usize>>(iter: T) -> Self {
|
|
let mut it = iter.into_iter();
|
|
Point {
|
|
x: it.next().unwrap(),
|
|
y: it.next().unwrap(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum Instruction {
|
|
On,
|
|
Off,
|
|
Toggle,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Command {
|
|
instruction: Instruction,
|
|
from: Point,
|
|
to: Point,
|
|
}
|
|
|
|
impl From<&str> for Command {
|
|
fn from(value: &str) -> Self {
|
|
lazy_static! {
|
|
static ref RE: Regex = Regex::new(
|
|
r"(turn on|turn off|toggle) (\d{1,3},\d{1,3}) through (\d{1,3},\d{1, 3})"
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
let capture = RE.captures(value).unwrap();
|
|
|
|
let instruction = match capture[1].as_ref() {
|
|
"turn on" => On,
|
|
"turn off" => Off,
|
|
"toggle" => Toggle,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let from: Point = capture[2].split(',').map(|x| x.parse().unwrap()).collect();
|
|
|
|
let to: Point = capture[3].split(',').map(|x| x.parse().unwrap()).collect();
|
|
|
|
Command {
|
|
instruction,
|
|
from,
|
|
to,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn part_one(input: &str) -> Option<u32> {
|
|
let mut a = vec![[0; 1000]; 1000];
|
|
for line in input.trim().split('\n') {
|
|
let Command {
|
|
instruction,
|
|
from,
|
|
to,
|
|
} = Command::from(line);
|
|
for x in a.iter_mut().take(to.x + 1).skip(from.x) {
|
|
for y in x.iter_mut().take(to.y + 1).skip(from.y) {
|
|
match instruction {
|
|
On => *y = 1,
|
|
Off => *y = 0,
|
|
Toggle => *y = 1 - *y,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Some(a.iter().map(|x| -> u32 { x.iter().sum() }).sum())
|
|
}
|
|
|
|
pub fn part_two(input: &str) -> Option<u32> {
|
|
let mut a = vec![[0; 1000]; 1000];
|
|
for line in input.trim().split('\n') {
|
|
let Command {
|
|
instruction,
|
|
from,
|
|
to,
|
|
} = Command::from(line);
|
|
for x in a.iter_mut().take(to.x + 1).skip(from.x) {
|
|
for y in x.iter_mut().take(to.y + 1).skip(from.y) {
|
|
match instruction {
|
|
On => *y += 1,
|
|
Toggle => *y += 2,
|
|
Off if y > &mut 0 => *y -= 1,
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Some(a.iter().map(|x| -> u32 { x.iter().sum() }).sum())
|
|
}
|
|
fn main() {
|
|
let input = &aoc::read_file("inputs", 6);
|
|
aoc::solve!(1, part_one, input);
|
|
aoc::solve!(2, part_two, input);
|
|
}
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
#[test]
|
|
fn test_part_one() {
|
|
let input = aoc::read_file("test_inputs", 6);
|
|
assert_eq!(part_one(&input), Some(998996));
|
|
}
|
|
#[test]
|
|
fn test_part_two() {
|
|
let input = aoc::read_file("test_inputs", 6);
|
|
assert_eq!(part_two(&input), Some(1001996));
|
|
}
|
|
}
|