1
0
Fork 0
advent-of-code/2018/day12/src/main.rs

120 lines
3.4 KiB
Rust

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
const MAP_SIZE: usize = 500;
const MAP_ZERO_INDEX: usize = 200;
fn get_score(state: &[char; MAP_SIZE]) -> i64 {
let mut score = 0;
for i in 0..MAP_SIZE {
if state[i] == '#' {
score += i as i64 - MAP_ZERO_INDEX as i64;
}
}
score
}
fn run_game(
initial_state: String,
states: HashMap<String, char>,
generations: i64,
) -> (i64, [i64; MAP_SIZE]) {
let mut last_state = ['.'; MAP_SIZE];
for (i, c) in initial_state.char_indices() {
if c == '#' {
last_state[MAP_ZERO_INDEX + i] = '#';
}
}
let mut scores = [0i64; MAP_SIZE];
for gen in 0..generations {
let mut next_state = ['.'; MAP_SIZE];
for i in 2..(MAP_SIZE - 2) {
let mut key = String::new();
for j in i - 2..=i + 2 {
key.push(last_state[j]);
}
if let Some(dest_state) = states.get(&key) {
next_state[i] = *dest_state;
}
}
last_state = next_state;
scores[gen as usize] = get_score(&last_state);
}
(scores[generations as usize - 1], scores)
}
fn find_big_score(initial_state: String, states: HashMap<String, char>, iterations: i64) -> i64 {
let (_, scores) = run_game(initial_state, states, MAP_SIZE as i64);
for i in 0..(MAP_SIZE - 3) {
let diff1 = scores[i + 1] - scores[i];
let diff2 = scores[i + 2] - scores[i + 1];
let diff3 = scores[i + 3] - scores[i + 2];
if diff1 == diff2 {
if diff2 == diff3 {
let sum = ((iterations - i as i64 - 1) * diff1) + scores[i];
println!(
"({} - {}) * {} + {} = {}",
iterations - 1,
i as i64,
diff1,
scores[i],
sum
);
return sum;
}
}
}
-1
}
fn read_file(filename: &str) -> (String, HashMap<String, char>) {
let mut lines: Vec<String> = BufReader::new(File::open(filename).unwrap())
.lines()
.map(|line| line.unwrap())
.collect();
let mut initial_state = lines.remove(0);
initial_state.replace_range(0..15, "");
lines.remove(0);
let mut states: HashMap<String, char> = HashMap::new();
for line in lines.iter() {
let mut chars = line.chars();
let mut state = String::with_capacity(5);
state.push(chars.nth(0).unwrap());
state.push(chars.nth(0).unwrap());
state.push(chars.nth(0).unwrap());
state.push(chars.nth(0).unwrap());
state.push(chars.nth(0).unwrap());
let dest = chars.nth(4).unwrap();
states.insert(state, dest);
}
(initial_state, states)
}
fn main() {
let (initial_state, states) = read_file("input");
let (part1score, _) = run_game(initial_state.clone(), states.clone(), 20);
println!("part 1 score after 20 generations: {}", part1score);
let iterations = 50000000000;
let part2score = find_big_score(initial_state, states, iterations);
println!("part 2 score after {} is {}", iterations, part2score);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let (initial_state, states) = read_file("test-input");
let (score, _) = run_game(initial_state, states, 20);
assert_eq!(score, 325);
}
}