summaryrefslogtreecommitdiffstats
path: root/day12/src/main.rs
blob: 6b421e4037524f6071b9ac9352c3169aef241860 (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
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::process;
use std::collections::HashMap;

type State = Vec<(i64, char)>;
type RuleKey = (char, char, char, char, char);
type Rules = HashMap<RuleKey, char>;

static ITERATIONS: usize = 20;

fn parse_initial_state(line: &String) -> State {
  let initial: Vec<char> = line[15..].chars().collect();
  let mut slice: State = Vec::new();
  for i in -(ITERATIONS as i64) - 2..0 {
    slice.push((i, '.'));
  }
  for (i, ch) in initial.iter().enumerate() {
    slice.push((i as i64, *ch));
  }
  for i in initial.len()..initial.len() + ITERATIONS + 2 {
    slice.push((i as i64, '.'));
  }
  for (i, _) in &slice {
    print!("{} ", i);
  }
  print!("\n");
  slice
}

fn parse_rule(rules: &mut Rules, line: &String) {
  let chs: Vec<char> = line.chars().collect();
  let res: char = chs[chs.len() - 1];
  let p = chs[0..6].to_vec();
  let rule_key = (p[0], p[1], p[2], p[3], p[4]);
  rules.insert(rule_key, res);
}

fn main() {
  let args: Vec<String> = env::args().collect();
  if args.len() != 2 {
    println!("Wrong number of arguments. Provide a file name and worker count.");
    process::exit(1);
  }
  let filename = &args[1];

  println!("Using file {} as input.", filename);
  let f = match File::open(filename) {
    Ok(file) => file,
    Err(e) => {
      println!("Failed to open file {}. {:?}", filename, e);
      process::exit(1);
    }
  };
  let file = BufReader::new(&f);
  let lines: Vec<String> = file.lines()
    .map(|line| line.expect("Could not parse line."))
    .collect();

  let mut initial_state: State = Vec::new();
  let mut rules: Rules = HashMap::new();
  for (i, line) in lines.iter().enumerate() {
    match i {
      0 => { initial_state = parse_initial_state(&line); }
      1 => { }
      _ => { parse_rule(&mut rules, &line); }
    }
  }
  assert_ne!(initial_state.len(), 0);

  let state_len = initial_state.len();
  let mut states: Vec<State> = vec![initial_state];
  for iteration in 0..ITERATIONS {
    let mut new_state: State = vec![(-999, '.'); state_len];
    {
      let prev_state = &states[states.len() - 1];
      for (i, _) in prev_state.iter().enumerate() {
        if i < 2 || i >= state_len - 2 { continue; }
        let rule_key = (prev_state[i-2].1, prev_state[i-1].1, prev_state[i].1, prev_state[i+1].1, prev_state[i+2].1);
        let value = rules[&rule_key];
        new_state[i] = (prev_state[i].0, value);
      }
    }
    if iteration % 1000 == 0 {
      println!("Iteration: {}", iteration);
    }
    states.push(new_state);
  }

  for (i, state) in states.iter().enumerate() {
    print!("{}: ", i);
    for tupl in state {
      let ch = tupl.1;
      print!("{}", ch);
    }
    print!("\n");
  }

  let mut total = 0;
  let last_i = states.len() - 1;
  let last_state = &states[last_i];
  for (_, &tupl) in last_state.iter().enumerate() {
    let (i, ch) = tupl;
    if ch == '#' {
      total += i;
    }
  }
  println!("Result: {}", total);
}