day 18 solution
parent
960a2b1e28
commit
d3690d856e
|
@ -0,0 +1,4 @@
|
||||||
|
[[package]]
|
||||||
|
name = "day18"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "day18"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Andrew Coleman <penguincoder@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,50 @@
|
||||||
|
....#......|.#........###|...||.#|||.||.|...|.#.|.
|
||||||
|
|#|#....|#...||.|#.#|.|.|..#...||.#|#.|.#||#||.|#.
|
||||||
|
.....##...#..###..##.|.|....|..#.|...#.#.....|.|..
|
||||||
|
|....#|||#..||##....||#||.|..|...|..#....#|#....|#
|
||||||
|
|......|......|.#...|.....|..|.#...#.#..#|.....#|.
|
||||||
|
|#...#....#...#.|..#..|...|#..|.#.......#..#....|#
|
||||||
|
....|#.|#...........##...||......##...||#...#..|.|
|
||||||
|
.#.....|..|...|#..##||..#.#...#...#|.#...#.|....#.
|
||||||
|
.##|.....|||.....||.#...#...#...#......##...||#...
|
||||||
|
.||#.|#..|.....#.|.|..........|.#..|##...||...|#..
|
||||||
|
|......|..#...#.##||..||..#.|..|.|....##|..|..|.|.
|
||||||
|
|#...####.#.|.....|#..#....|#.#..|.#.#|####.#..|..
|
||||||
|
.#|.....#.|....|###..#||...#|...||.|.#|#.....|##..
|
||||||
|
#.|..#|..#...||#.#|...#.##|..|..#...|#.....|..#|..
|
||||||
|
#.|.....##..||##....|..|.|.|..##.#..|||.....|.....
|
||||||
|
......##|..|#.|#||...#.|..#..|.#....|..#....#..|##
|
||||||
|
|........|#.#.|.##...#|..|##.....|##.|.#....#.#...
|
||||||
|
#.#..#..|.........#|.##.......|...|.#..#.#|####.#.
|
||||||
|
.....#||#..|......#|.....#..|||..##.......#.#..#.#
|
||||||
|
#...........#|..#..|.||.|||.|....#||....|#..##.#..
|
||||||
|
.|...#..##|#...#.||.|##.|..#.||.#.#.#.###...#...#|
|
||||||
|
|#|...|.......#..#..#....|.###..|.||...|.#...|....
|
||||||
|
..#.#......|..|.||#.||.......|..#|.#.|..|.#..#.#.#
|
||||||
|
#..#...|...|..|..#....|..|...|#|...#......#...#...
|
||||||
|
|...|.|.||#...|...|....|...#.|.#.|.|.|#..|..###.#.
|
||||||
|
..|.|.....|##...##....|..|.....||...#..||##......|
|
||||||
|
.#.#....|.##|....|.|..|.|##..#...|##|.#.#.##|....#
|
||||||
|
..#|.|.....|.#....|...||....|.#..|#.#.|#|.||.||...
|
||||||
|
.|##.|.#|#|...|...##.||.....|.#|....|.....|#..||..
|
||||||
|
|.#|...||....#|..#...|.....|.....#|...|#.#|..|....
|
||||||
|
.|...|....###.|....||##||..|#||.#|##|..|.#.......|
|
||||||
|
...#.||###|#|.#.|...#...|.##.|.||#..#.......||.#.#
|
||||||
|
.#|....|#.|.###.##|...|#...#.||..##...#.#|##...#.#
|
||||||
|
..|#|#..#..#..#|#.....|.#.|...|..#.#......###..|.|
|
||||||
|
#.|.|..#.#.#.#.....|........|#.||..#......#|.....#
|
||||||
|
...#.#|#|.|.###|#...#.|......#|.......##||......#.
|
||||||
|
.#|#.|#..#|...|.|...##|.#....|#........|..|.#.#.#.
|
||||||
|
..|.##.|#..|...#|.#...#........|.|#|.#.|.|..|#|.#.
|
||||||
|
...#.#.#||.|||...|#||..##.....###......#..#|||#..#
|
||||||
|
...#.....#||##.|..#.#|......||..#..#..#..|..|..|..
|
||||||
|
####.|....|.......|.|.#...|...#.#.......|.|.#...||
|
||||||
|
..|.|#|.#..##..##...#.....|...|...#|.|...#|..#..##
|
||||||
|
|...##.#|.........#..||#..||.#....||#..|..||....#|
|
||||||
|
.#..........#|#.#|#.|...|#....|..|...|...##....|#.
|
||||||
|
|.|#..|..|......#..|...|..##|||#...|..##|...#.|#..
|
||||||
|
||#.||.#|.|...#.........#...|.|##.#.|#||.|.#|..#..
|
||||||
|
|..|..|..#....#...|.......#|.........|#....#|....|
|
||||||
|
##..###......#|.........|.......|...||.......#|..#
|
||||||
|
|..............#.......#...#|.|||..#..|..#........
|
||||||
|
...|||.#.|.#.|..#.....##|....###.#.|....|.......|.
|
|
@ -0,0 +1,182 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
const OPEN: char = '.';
|
||||||
|
const WOODED: char = '|';
|
||||||
|
const LUMBERYARD: char = '#';
|
||||||
|
const MAP_SIZE: usize = 50;
|
||||||
|
type Map = [[char; MAP_SIZE]; MAP_SIZE];
|
||||||
|
|
||||||
|
fn get_map_from_file(filename: &str) -> Map {
|
||||||
|
let lines: Vec<String> = BufReader::new(File::open(filename).unwrap())
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.unwrap())
|
||||||
|
.collect();
|
||||||
|
let mut m = [[OPEN; MAP_SIZE]; MAP_SIZE];
|
||||||
|
let mut y: usize = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
for (i, c) in line.char_indices() {
|
||||||
|
m[i][y] = c;
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_neighbors(map: &Map, width: usize, height: usize, x: usize, y: usize) -> Vec<char> {
|
||||||
|
let mut neighbors: Vec<char> = Vec::with_capacity(8);
|
||||||
|
if x > 0 && y > 0 {
|
||||||
|
neighbors.push(map[x - 1][y - 1]);
|
||||||
|
}
|
||||||
|
if y > 0 {
|
||||||
|
neighbors.push(map[x][y - 1]);
|
||||||
|
}
|
||||||
|
if x + 1 < width && y > 0 {
|
||||||
|
neighbors.push(map[x + 1][y - 1]);
|
||||||
|
}
|
||||||
|
if x > 0 {
|
||||||
|
neighbors.push(map[x - 1][y]);
|
||||||
|
}
|
||||||
|
if x + 1 < width {
|
||||||
|
neighbors.push(map[x + 1][y]);
|
||||||
|
}
|
||||||
|
if x > 0 && y + 1 < height {
|
||||||
|
neighbors.push(map[x - 1][y + 1]);
|
||||||
|
}
|
||||||
|
if y + 1 < height {
|
||||||
|
neighbors.push(map[x][y + 1]);
|
||||||
|
}
|
||||||
|
if x + 1 < width && y + 1 < height {
|
||||||
|
neighbors.push(map[x + 1][y + 1]);
|
||||||
|
}
|
||||||
|
neighbors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_map(map: &Map, width: usize, height: usize) {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
print!("{}", map[x][y]);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(map: &mut Map, width: usize, height: usize, ticks: u64) -> u64 {
|
||||||
|
for _ in 0..ticks {
|
||||||
|
let mut new_map: Map = [[OPEN; MAP_SIZE]; MAP_SIZE];
|
||||||
|
for x in 0..width {
|
||||||
|
for y in 0..height {
|
||||||
|
let mut wooded_squares = 0;
|
||||||
|
let mut lumberyard_squares = 0;
|
||||||
|
for c in get_neighbors(map, width, height, x, y).iter() {
|
||||||
|
match *c {
|
||||||
|
WOODED => wooded_squares += 1,
|
||||||
|
LUMBERYARD => lumberyard_squares += 1,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if map[x][y] == OPEN && wooded_squares >= 3 {
|
||||||
|
new_map[x][y] = WOODED;
|
||||||
|
} else if map[x][y] == WOODED && lumberyard_squares >= 3 {
|
||||||
|
new_map[x][y] = LUMBERYARD;
|
||||||
|
} else if map[x][y] == LUMBERYARD {
|
||||||
|
if lumberyard_squares >= 1 && wooded_squares >= 1 {
|
||||||
|
new_map[x][y] = LUMBERYARD;
|
||||||
|
} else {
|
||||||
|
new_map[x][y] = OPEN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_map[x][y] = map[x][y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for x in 0..width {
|
||||||
|
for y in 0..height {
|
||||||
|
map[x][y] = new_map[x][y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
part_one_score(map, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_to_string(map: &Map, width: usize, height: usize) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
s.push(map[x][y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_two_score(map: &mut Map, width: usize, height: usize, target_ticks: u64) -> u64 {
|
||||||
|
let max_iter = 500;
|
||||||
|
let mut scores: Vec<u64> = Vec::with_capacity(max_iter);
|
||||||
|
let mut maps: HashSet<String> = HashSet::new();
|
||||||
|
for i in 1..max_iter {
|
||||||
|
let mut m = map.clone();
|
||||||
|
let s = tick(&mut m, width, height, i as u64);
|
||||||
|
scores.push(s);
|
||||||
|
if !maps.insert(map_to_string(&m, width, height)) {
|
||||||
|
let mut index: u64 = 0;
|
||||||
|
for (i, k) in scores.iter().enumerate() {
|
||||||
|
if s == *k {
|
||||||
|
index = i as u64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let remaining_steps: u64 = target_ticks - index;
|
||||||
|
let cycle_len: u64 = scores.len() as u64 - index - 1;
|
||||||
|
let remainder: u64 = remaining_steps % cycle_len;
|
||||||
|
let final_tick: u64 = remainder + index;
|
||||||
|
println!("repeated value: {}", s);
|
||||||
|
println!("first occurrence at {}", index);
|
||||||
|
println!("remaining steps {}", remaining_steps);
|
||||||
|
println!("cycle len {}", cycle_len);
|
||||||
|
println!("remainder of {} with final tick at {}", remainder, final_tick);
|
||||||
|
return tick(&mut map.clone(), width, height, final_tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_one_score(map: &Map, width: usize, height: usize) -> u64 {
|
||||||
|
let mut woods: u64 = 0;
|
||||||
|
let mut lumberyards: u64 = 0;
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
match map[x][y] {
|
||||||
|
WOODED => woods += 1,
|
||||||
|
LUMBERYARD => lumberyards += 1,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
woods * lumberyards
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let m: Map = get_map_from_file("input");
|
||||||
|
print_map(&m, 50, 50);
|
||||||
|
let part_one_score = tick(&mut m.clone(), 50, 50, 10);
|
||||||
|
println!("part one score {}", part_one_score);
|
||||||
|
//part_two_score(&mut m.clone(), 50, 50, 1000000000);
|
||||||
|
let part_two_score = part_two_score(&mut m.clone(), 50, 50, 1000000000);
|
||||||
|
println!("part two score {}", part_two_score);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
let mut m: Map = get_map_from_file("test-input");
|
||||||
|
print_map(&m, 10, 10);
|
||||||
|
let part_one_score = tick(&mut m, 10, 10, 10);
|
||||||
|
assert_eq!(part_one_score, 1147);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
.#.#...|#.
|
||||||
|
.....#|##|
|
||||||
|
.|..|...#.
|
||||||
|
..|#.....#
|
||||||
|
#.#|||#|#|
|
||||||
|
...#.||...
|
||||||
|
.|....|...
|
||||||
|
||...#|.#|
|
||||||
|
|.||||..|.
|
||||||
|
...#.|..|.
|
Loading…
Reference in New Issue