summaryrefslogtreecommitdiff
path: root/2017/src/bin/day_16.rs
blob: 9676714c6357be20acd3263613e8d48f51c6e58f (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
extern crate advent_of_code_2017;
use advent_of_code_2017::*;

extern crate regex;
use regex::Regex;

fn main() {
    let args = AdventArgs::init();

    let spin_re = Regex::new(r"s(\d+)").unwrap();
    let exchange_re = Regex::new(r"x(\d+)/(\d+)").unwrap();
    let partner_re = Regex::new(r"p(\w)/(\w)").unwrap();
    let input: Vec<Instruction> = args.input[0]
        .split(',')
        .map(|instruction| {
            if let Some(caps) = spin_re.captures(instruction) {
                let spin_amount: usize = caps[1].parse().unwrap();
                Instruction::Spin(spin_amount)
            } else if let Some(caps) = exchange_re.captures(instruction) {
                let position_a: usize = caps[1].parse().unwrap();
                let position_b: usize = caps[2].parse().unwrap();
                Instruction::Exchange(position_a, position_b)
            } else if let Some(caps) = partner_re.captures(instruction) {
                let program_a = caps[1].chars().next().unwrap();
                let program_b = caps[2].chars().next().unwrap();
                Instruction::Partner(program_a, program_b)
            } else {
                panic!("Unhandled instruction: {}", instruction)
            }
        })
        .collect();
    
    let mut states = vec!("abcdefghijklmnop".chars().collect());
    if args.part == 1 {
        let answer = run(&input, &states.last().unwrap());
        println!("{}", answer.iter().collect::<String>());
    } else {
        let repetitions = 1_000_000_000;
        let mut cycle_found = false;
        let mut cycle_start = 0;
        while !cycle_found {
            let next = run(&input, &states.last().unwrap());
            if let Some(i) = states.iter().position(|&ref x| *x == next) {
                cycle_found = true;
                cycle_start = i;
            } else {
                states.push(next);
            }
        }
        println!("Cycle found after pushing {} states", states.len());
        println!("Cycle starts at {} states", cycle_start);
        
        let solution_index = (repetitions - cycle_start) % (states.len() - cycle_start);
        println!("{}", states[solution_index].iter().collect::<String>());
        
    }
}

enum Instruction {
    Spin(usize),
    Exchange(usize, usize),
    Partner(char, char)
}

fn run(instructions: &[Instruction], start: &Vec<char>) -> Vec<char> {
    let mut programs = start.clone();
    for instruction in instructions {
        match instruction {
            &Instruction::Exchange(a, b) => {
                programs.swap(a, b);
            },
            &Instruction::Spin(spin_amount) => {
                for _ in 0..spin_amount {
                    //this may be slow, but will suffice for right now
                    let end = programs.pop().unwrap();
                    programs.insert(0, end);
                }
            },
            &Instruction::Partner(program_a, program_b) => {
                let position_a: usize = programs.iter().position(|&x| x == program_a).unwrap();
                let position_b: usize = programs.iter().position(|&x| x == program_b).unwrap();
                programs.swap(position_a, position_b);
            }
        }
    }
    programs
}