summaryrefslogtreecommitdiff
path: root/src/bin/day6.rs
blob: 67896e415353b4735654743ec1e7d964b30b2fae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use regex::Regex;

fn main() {
    let input = advent::read_lines(6);
    println!("6a: {}", count_lit(&input));
    println!("6b: {}", total_brightness(&input));
}

enum Operation {
    Toggle,
    TurnOn,
    TurnOff,
}

struct Instruction {
    op: Operation,
    from: (usize, usize),
    to: (usize, usize),
}

fn parse_instructions(input: &[String]) -> Vec<Instruction> {
    let re = Regex::new(r"^([a-z ]+) (\d+),(\d+) through (\d+),(\d+)$").unwrap();
    let mut instructions = Vec::new();
    for line in input {
        let cap = re.captures(line).unwrap();
        let op = match &cap[1] {
            "turn on" => Operation::TurnOn,
            "turn off" => Operation::TurnOff,
            "toggle" => Operation::Toggle,
            err => panic!("unsupported operation: {}", err),
        };
        let x1 = cap[2].parse::<usize>().unwrap();
        let y1 = cap[3].parse::<usize>().unwrap();
        let x2 = cap[4].parse::<usize>().unwrap();
        let y2 = cap[5].parse::<usize>().unwrap();
        instructions.push(Instruction { op, from: (x1,y1), to: (x2,y2) });
    }
    instructions
}

fn decorations(input: &[String]) -> [[bool; 1000]; 1000] {
    let instructions = parse_instructions(input);

    let mut grid = [[false; 1000]; 1000];
    for Instruction { op, from, to } in instructions {
        for grid_x in grid.iter_mut().take(to.0 + 1).skip(from.0) {
            for grid_x_y in grid_x.iter_mut().take(to.1 + 1).skip(from.1) {
                *grid_x_y = match op {
                    Operation::Toggle => !*grid_x_y,
                    Operation::TurnOn => true,
                    Operation::TurnOff => false,
                };
            }
        }
    }

    grid
}

fn decorations2(input: &[String]) -> Vec<[i32; 1000]> {
    let instructions = parse_instructions(input);

    let mut grid = Vec::new();
    for _ in 0..1000 {
        grid.push([0; 1000]);
    }
    for Instruction { op, from, to } in instructions {
        for grid_x in grid.iter_mut().take(to.0 + 1).skip(from.0) {
            for grid_x_y in grid_x.iter_mut().take(to.1 + 1).skip(from.1) {
                *grid_x_y = match op {
                    Operation::Toggle => *grid_x_y + 2,
                    Operation::TurnOn => *grid_x_y + 1,
                    Operation::TurnOff => std::cmp::max(0, *grid_x_y - 1),
                };
            }
        }
    }

    grid
}

fn count_lit(input: &[String]) -> usize {
    decorations(input).iter()
                      .flatten()
                      .filter(|&x| *x)
                      .count()
}

fn total_brightness(input: &[String]) -> i32 {
    decorations2(input).iter()
                       .flatten()
                       .sum()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        assert_eq!(count_lit(&["turn on 0,0 through 999,999".to_string()]), 1000 * 1000);
        assert_eq!(total_brightness(&["turn on 0,0 through 0,0".to_string()]), 1);
        assert_eq!(total_brightness(&["toggle 0,0 through 999,999".to_string()]), 2000000);
    }
}