summaryrefslogtreecommitdiffstats
path: root/day5/src/main.rs
blob: 4b2b0bca1b136d7520b60b9e5e58855f124e9de0 (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
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::process;

static ASCII_LOWER: [char; 26] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                                  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
                                  's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];

fn same_unit(a: &char, b: &char) -> bool {
  a.to_lowercase().to_string() == b.to_lowercase().to_string()
}

fn same_polarity(a: &char, b: &char) -> bool {
  (a.is_lowercase() && b.is_lowercase()) || (a.is_uppercase() && b.is_uppercase())
}

fn find_removable_indices(chars: &Vec<char>) -> Option<(usize, usize)> {
  let mut res: Option<(usize, usize)> = None;
  for (i, cur) in chars.iter().enumerate() {
    if i == chars.len() - 1 {  // last element
      break;
    }

    let next = chars[i + 1];
    if same_unit(&cur, &next) && !same_polarity(&cur, &next) {
      res = Some((i, i + 1));
      break;
    }
  }

  res
}

fn react_polymer(line: &String) -> String {
  let mut string: Vec<char> = line.trim().chars().collect();
  loop {
    let indices = find_removable_indices(&string);
    let (rem_i1, rem_i2): (usize, usize);
    match indices {
      Some((i1, i2)) => {
        rem_i1 = i1;
        rem_i2 = i2;

        let s = &mut string;
        s.remove(rem_i2);
        s.remove(rem_i1);

        continue;
      }
      None => {
        break;
      }
    };
  }

  string.into_iter().collect()
}

fn react_polymer_without_char(line: &String, ch: &char) -> String {
  let line_ref: &str = line.as_ref();
  let a = *ch;
  let b_str = a.to_uppercase().to_string();
  let b: &str = b_str.as_ref();
  let replaced_line = line_ref.replace(*ch, "").replace(a, "").replace(b, "");
  let res = react_polymer(&replaced_line);
  res
}

fn main() {
  let args: Vec<String> = env::args().collect();
  if args.len() != 2 {
    println!("Wrong number of arguments. Provide just a file name.");
    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 mut lines: Vec<String> = file.lines()
    .map(|line| line.expect("Could not parse line."))
    .collect();
  &lines.sort();
  assert_eq!(lines.len(), 1);
  let line = &lines[0];

  // exercise 1
  println!("Solving 1...");
  let result = react_polymer(&line);

  // println!("1. Result: {}", result);
  println!("1. Length: {}", result.len());

  // exercise 2
  println!("Solving 2...");
  let mut best = line.len();
  for ch in &ASCII_LOWER {
    let result = react_polymer_without_char(&line, ch);
    let len = result.len();
    println!("Debug: ch: {}, len: {}", &ch, &len);
    if len < best {
      best = len;
      println!("Debug: new best: {}", &len);
    }
  }
  println!("2. Length: {}", best);
}