summaryrefslogtreecommitdiff
path: root/2017/src/bin/day_25.rs
blob: 8d7b0daa6a83610b0b4460f16cae7efa4dcbafd2 (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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
extern crate advent_of_code_2017;
use advent_of_code_2017::*;

extern crate regex;
use regex::Regex;

use std::slice::Iter;
use std::collections::HashSet;

fn main() {
    let args = AdventArgs::init();
    let program = parse(&args.input);

    let mut position: i32 = 0;
    let mut state = program.state(program.start).expect("Started out of program bounds");
    let mut tape = HashSet::new();
    
    for _ in 0..program.iterations {
        let instruction = if tape.contains(&position) {
            &state.if1
        } else {
            &state.if0
        };
        if instruction.write {
            tape.insert(position);
        } else {
            tape.remove(&position);
        }
        position += instruction.offset;
        state = program.state(instruction.next).expect("Redirected to unknown state");
    }

    println!("{}", tape.len());
}

fn parse(input: &Vec<String>) -> Program {
    let state_re = Regex::new(r"state (\w)").unwrap();
    let iterations_re = Regex::new(r"(\d+) steps").unwrap();
    let write_re = Regex::new(r"Write the value (\d)").unwrap();
    let move_re = Regex::new(r"Move one slot to the (\w+)").unwrap();

    let mut lines = input.iter();
    let start = parse_char(&mut lines, &state_re);
    let iterations = parse_number(&mut lines, &iterations_re);
    
    let mut states = Vec::new();
    while let Some(heading) = lines.next() {
        states.push(State {
            id: state_re.captures(heading).unwrap()[1].chars().next().unwrap(),
            if0: parse_instruction(&mut lines, &write_re, &move_re, &state_re),
            if1: parse_instruction(&mut lines, &write_re, &move_re, &state_re)
        });
    }

    Program {
        start: start,
        iterations: iterations,
        states: states
    }
}

fn parse_char(lines: &mut Iter<String>, re: &Regex) -> char {
    re.captures(
        lines.next().unwrap()
    ).unwrap()[1].chars().next().unwrap()
}

fn parse_number(lines: &mut Iter<String>, re: &Regex) -> u32 {
    re.captures(
        lines.next().unwrap()
    ).unwrap()[1].parse().unwrap()
}
fn parse_direction(lines: &mut Iter<String>, re: &Regex) -> i32 {
    if re.captures(
        lines.next().unwrap()
    ).unwrap()[1] == *"left" {
        -1
    } else {
        1
    }
}

fn parse_bool(lines: &mut Iter<String>, re: &Regex) -> bool {
    re.captures(
        lines.next().unwrap()
    ).unwrap()[1] == *"1"
}

fn parse_instruction(lines: &mut Iter<String>, write_re: &Regex, offset_re: &Regex, next_re: &Regex) -> Instruction {
    lines.next();
    Instruction {
        write: parse_bool(lines, &write_re),
        offset: parse_direction(lines, &offset_re),
        next: parse_char(lines, &next_re)
    }
}

#[derive(Debug)]
struct Program {
    start: char,
    iterations: u32,
    states: Vec<State>
}

impl Program {
    fn state(&self, i: char) -> Option<&State> {
        self.states.iter().find(|s| s.id == i)
    }
}

#[derive(Debug)]
struct State {
    id: char,
    if0: Instruction,
    if1: Instruction
}

#[derive(Debug)]
struct Instruction {
    write: bool,
    offset: i32,
    next: char
}